summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-06-30 00:21:34 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-06-30 00:21:34 +0000
commit3917ac5846dd0f9ad1238166f90caab9912052e6 (patch)
tree1c298935def4f29edb39192365a65d73de999155 /fs
parentaf2f803c8b2d469fe38e4a7ce952658dfcb6681a (diff)
o Merge with Linux 2.1.100.
o Cleanup the machine dependencies of floppy and rtc. The driver for the Dallas thingy in the Indy is still missing. o Handle allocation of zero'd pages correct for R4000SC / R4400SC. o Page colouring shit to match the virtual and physical colour of all mapped pages. This tends to produce extreme fragmentation problems, so it's deactivated for now. Users of R4000SC / R4400SC may re-enable the code in arch/mips/mm/init.c by removing the definition of CONF_GIVE_A_SHIT_ABOUT_COLOURS. Should get them somewhat further - but don't shake to hard ... o Fixed ptrace(2)-ing of syscalls, strace is now working again. o Fix the interrupt forwarding from the keyboard driver to the psaux driver, PS/2 mice are now working on the Indy. The fix is somewhat broken as it prevents generic kernels for Indy and machines which handle things different. o Things I can't remember.
Diffstat (limited to 'fs')
-rw-r--r--fs/affs/namei.c4
-rw-r--r--fs/attr.c12
-rw-r--r--fs/autofs/root.c2
-rw-r--r--fs/buffer.c2
-rw-r--r--fs/coda/Makefile2
-rw-r--r--fs/coda/cache.c41
-rw-r--r--fs/coda/coda_linux.c1
-rw-r--r--fs/coda/dir.c18
-rw-r--r--fs/coda/file.c10
-rw-r--r--fs/coda/psdev.c135
-rw-r--r--fs/coda/stats.c416
-rw-r--r--fs/coda/symlink.c7
-rw-r--r--fs/coda/sysctl.c10
-rw-r--r--fs/coda/upcall.c38
-rw-r--r--fs/dcache.c9
-rw-r--r--fs/dquot.c23
-rw-r--r--fs/exec.c21
-rw-r--r--fs/ext2/acl.c9
-rw-r--r--fs/ext2/balloc.c3
-rw-r--r--fs/ext2/file.c2
-rw-r--r--fs/ext2/inode.c4
-rw-r--r--fs/ext2/ioctl.c7
-rw-r--r--fs/ext2/namei.c8
-rw-r--r--fs/minix/namei.c8
-rw-r--r--fs/namei.c30
-rw-r--r--fs/nfsd/nfsctl.c2
-rw-r--r--fs/open.c15
-rw-r--r--fs/pipe.c2
-rw-r--r--fs/proc/array.c12
-rw-r--r--fs/proc/inode.c7
-rw-r--r--fs/smbfs/proc.c3
-rw-r--r--fs/super.c4
-rw-r--r--fs/sysv/namei.c8
-rw-r--r--fs/umsdos/namei.c8
34 files changed, 740 insertions, 143 deletions
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 96d8c6f5a..d6480b4ee 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -245,7 +245,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
if (S_ISDIR(inode->i_mode))
goto unlink_done;
if (current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
+ current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
goto unlink_done;
if ((retval = affs_remove_header(bh,inode)) < 0)
@@ -363,7 +363,7 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
retval = -EPERM;
if (current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
+ current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
goto rmdir_done;
if (inode->i_dev != dir->i_dev)
goto rmdir_done;
diff --git a/fs/attr.c b/fs/attr.c
index e916a2a3d..789713164 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -27,28 +27,28 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
(current->fsuid != inode->i_uid ||
- attr->ia_uid != inode->i_uid) && !fsuser())
+ attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
goto error;
/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) &&
- !fsuser())
+ !capable(CAP_CHOWN))
goto error;
/* Make sure a caller can chmod. */
if (ia_valid & ATTR_MODE) {
- if ((current->fsuid != inode->i_uid) && !fsuser())
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
goto error;
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
- inode->i_gid) && !fsuser())
+ inode->i_gid) && !capable(CAP_FSETID))
attr->ia_mode &= ~S_ISGID;
}
/* Check for setting the inode time. */
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
- if (current->fsuid != inode->i_uid && !fsuser())
+ if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
goto error;
}
fine:
@@ -75,7 +75,7 @@ void inode_setattr(struct inode * inode, struct iattr * attr)
inode->i_ctime = attr->ia_ctime;
if (ia_valid & ATTR_MODE) {
inode->i_mode = attr->ia_mode;
- if (!in_group_p(inode->i_gid) && !fsuser())
+ if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
inode->i_mode &= ~S_ISGID;
}
mark_inode_dirty(inode);
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 60f9efe01..2eec54de4 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -478,7 +478,7 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp,
_IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
return -ENOTTY;
- if ( !autofs_oz_mode(sbi) && !fsuser() )
+ if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
return -EPERM;
switch(cmd) {
diff --git a/fs/buffer.c b/fs/buffer.c
index 5e55f89c7..887b9255c 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1871,7 +1871,7 @@ asmlinkage int sys_bdflush(int func, long data)
int i, error = -EPERM;
lock_kernel();
- if (!suser())
+ if (!capable(CAP_SYS_ADMIN))
goto out;
if (func == 1) {
diff --git a/fs/coda/Makefile b/fs/coda/Makefile
index 1f2d0a94c..4e6c40dce 100644
--- a/fs/coda/Makefile
+++ b/fs/coda/Makefile
@@ -4,7 +4,7 @@
O_TARGET := coda.o
O_OBJS := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\
- symlink.o pioctl.o sysctl.o
+ symlink.o pioctl.o sysctl.o stats.o
M_OBJS := $(O_TARGET)
# If you want debugging output, please uncomment the following line
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index cdf586507..1285ac757 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -32,9 +32,6 @@ static void coda_cache_create(struct inode *inode, int mask);
static struct coda_cache * coda_cache_find(struct inode *inode);
-/* Keep various stats */
-struct cfsnc_statistics cfsnc_stat;
-
/* insert a acl-cache entry in sb list */
static void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
{
@@ -295,41 +292,3 @@ void coda_flag_inode(struct inode *inode, int flag)
-int
-cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
- int len=0;
- off_t begin;
-
- /* cfsnc_gather_stats(); */
-
- /* this works as long as we are below 1024 characters! */
- len += sprintf(buffer,"Coda minicache statistics\n\n");
- len += sprintf(buffer+len, "cfsnc_hits : %d\n", cfsnc_stat.hits);
- len += sprintf(buffer+len, "cfsnc_misses : %d\n", cfsnc_stat.misses);
- len += sprintf(buffer+len, "cfsnc_enters : %d\n", cfsnc_stat.enters);
- len += sprintf(buffer+len, "cfsnc_dbl_enters : %d\n", cfsnc_stat.dbl_enters);
- len += sprintf(buffer+len, "cfsnc_long_name_enters : %d\n", cfsnc_stat.long_name_enters);
- len += sprintf(buffer+len, "cfsnc_long_name_lookups : %d\n", cfsnc_stat.long_name_lookups);
- len += sprintf(buffer+len, "cfsnc_long_remove : %d\n", cfsnc_stat.long_remove);
- len += sprintf(buffer+len, "cfsnc_lru_rm : %d\n", cfsnc_stat.lru_rm);
- len += sprintf(buffer+len, "cfsnc_zapPfids : %d\n", cfsnc_stat.zapPfids);
- len += sprintf(buffer+len, "cfsnc_zapFids : %d\n", cfsnc_stat.zapFids);
- len += sprintf(buffer+len, "cfsnc_zapFile : %d\n", cfsnc_stat.zapFile);
- len += sprintf(buffer+len, "cfsnc_zapUsers : %d\n", cfsnc_stat.zapUsers);
- len += sprintf(buffer+len, "cfsnc_Flushes : %d\n", cfsnc_stat.Flushes);
- len += sprintf(buffer+len, "cfsnc_SumLen : %d\n", cfsnc_stat.Sum_bucket_len);
- len += sprintf(buffer+len, "cfsnc_Sum2Len : %d\n", cfsnc_stat.Sum2_bucket_len);
- len += sprintf(buffer+len, "cfsnc_# 0 len : %d\n", cfsnc_stat.Num_zero_len);
- len += sprintf(buffer+len, "cfsnc_MaxLen : %d\n", cfsnc_stat.Max_bucket_len);
- len += sprintf(buffer+len, "cfsnc_SearchLen : %d\n", cfsnc_stat.Search_len);
- begin = offset;
- *start = buffer + begin;
- len -= begin;
-
- if(len>length)
- len = length;
- if (len< 0)
- len = 0;
- return len;
-}
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 4fe096df9..322b764a9 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -7,6 +7,7 @@
* the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
*/
+#include <linux/version.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 8fed69242..ba0ec6e2f 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -23,6 +23,7 @@
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
+#include <linux/coda_proc.h>
/* dir inode-ops */
static int coda_create(struct inode *dir, struct dentry *new, int mode);
@@ -179,6 +180,8 @@ int coda_permission(struct inode *inode, int mask)
int error;
ENTRY;
+ coda_vfs_stat.permission++;
+ coda_permission_stat.count++;
if ( mask == 0 ) {
EXIT;
@@ -187,6 +190,7 @@ int coda_permission(struct inode *inode, int mask)
if ( coda_access_cache == 1 ) {
if ( coda_cache_check(inode, mask) ) {
+ coda_permission_stat.hit_count++;
return 0;
}
}
@@ -221,6 +225,8 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
struct ViceFid newfid;
struct coda_vattr attrs;
+ coda_vfs_stat.create++;
+
CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode);
if (!dir || !S_ISDIR(dir->i_mode)) {
@@ -274,6 +280,8 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
struct ViceFid newfid;
+ coda_vfs_stat.mkdir++;
+
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("coda_mkdir: inode is NULL or not a directory\n");
return -ENOENT;
@@ -329,6 +337,7 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
int error;
ENTRY;
+ coda_vfs_stat.link++;
if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
@@ -373,6 +382,7 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
int error=0;
ENTRY;
+ coda_vfs_stat.symlink++;
if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
@@ -414,6 +424,7 @@ int coda_unlink(struct inode *dir, struct dentry *de)
int len = de->d_name.len;
ENTRY;
+ coda_vfs_stat.unlink++;
dircnp = ITOC(dir);
CHECK_CNODE(dircnp);
@@ -446,6 +457,8 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
int len = de->d_name.len;
int error, rehash = 0;
+ coda_vfs_stat.rmdir++;
+
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("coda_rmdir: inode is NULL or not a directory\n");
return -ENOENT;
@@ -502,6 +515,8 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
struct coda_inode_info *new_cnp, *old_cnp;
int error, rehash = 0, update = 1;
ENTRY;
+ coda_vfs_stat.rename++;
+
old_cnp = ITOC(old_dir);
CHECK_CNODE(old_cnp);
new_cnp = ITOC(new_dir);
@@ -565,6 +580,7 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
struct inode *inode=file->f_dentry->d_inode;
ENTRY;
+ coda_vfs_stat.readdir++;
if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
printk("coda_readdir: inode is NULL or not a directory\n");
@@ -606,6 +622,7 @@ int coda_open(struct inode *i, struct file *f)
unsigned short coda_flags = coda_flags_to_cflags(flags);
ENTRY;
+ coda_vfs_stat.open++;
CDEBUG(D_SPECIAL, "OPEN inode number: %ld, flags %o.\n",
f->f_dentry->d_inode->i_ino, flags);
@@ -659,6 +676,7 @@ int coda_release(struct inode *i, struct file *f)
unsigned short cflags = coda_flags_to_cflags(flags);
ENTRY;
+ coda_vfs_stat.release++;
cnp =ITOC(i);
CHECK_CNODE(cnp);
diff --git a/fs/coda/file.c b/fs/coda/file.c
index ae1dd9776..c92aeeb27 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -23,6 +23,7 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
#include <linux/coda_cache.h>
+#include <linux/coda_proc.h>
/* file operations */
static int coda_readpage(struct file *file, struct page * page);
@@ -83,6 +84,7 @@ static int coda_readpage(struct file * coda_file, struct page * page)
struct coda_inode_info *cii;
ENTRY;
+ coda_vfs_stat.readpage++;
cii = ITOC(coda_inode);
@@ -108,6 +110,8 @@ static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
struct coda_inode_info *cii;
int res;
+ coda_vfs_stat.file_mmap++;
+
ENTRY;
cii = ITOC(file->f_dentry->d_inode);
cii->c_mmcount++;
@@ -126,7 +130,9 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff,
struct file cont_file;
struct dentry cont_dentry;
int result = 0;
- ENTRY;
+
+ ENTRY;
+ coda_vfs_stat.file_read++;
cnp = ITOC(coda_inode);
CHECK_CNODE(cnp);
@@ -167,6 +173,7 @@ static ssize_t coda_file_write(struct file *coda_file, const char *buff,
int result = 0;
ENTRY;
+ coda_vfs_stat.file_write++;
cnp = ITOC(coda_inode);
CHECK_CNODE(cnp);
@@ -205,6 +212,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
struct dentry cont_dentry;
int result = 0;
ENTRY;
+ coda_vfs_stat.fsync++;
if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
S_ISLNK(coda_inode->i_mode)))
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 119d14f51..e3ce5b39f 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -44,7 +44,7 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
#include <linux/coda_cache.h>
-#include <linux/coda_sysctl.h>
+#include <linux/coda_proc.h>
/*
@@ -401,19 +401,106 @@ static struct file_operations coda_psdev_fops = {
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry proc_coda = {
+struct proc_dir_entry proc_sys_root = {
+ PROC_SYS, 3, "sys", /* inode, name */
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */
+ 0, &proc_dir_inode_operations, /* size, ops */
+ NULL, NULL, /* get_info, fill_inode */
+ NULL, /* next */
+ NULL, NULL /* parent, subdir */
+};
+
+struct proc_dir_entry proc_fs_coda = {
+ PROC_FS_CODA, 4, "coda",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+ 0, &proc_dir_inode_operations,
+ NULL, NULL,
+ NULL,
+ NULL, NULL
+};
+
+struct proc_dir_entry proc_sys_coda = {
0, 4, "coda",
- S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, 2, 0, 0,
- 0, &proc_net_inode_operations,
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+ 0, &proc_dir_inode_operations,
+ NULL, NULL,
+ NULL,
+ NULL, NULL
+};
+struct proc_dir_entry proc_fs = {
+ PROC_FS, 2, "fs",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+ 0, &proc_dir_inode_operations,
+ NULL, NULL,
+ NULL,
+ NULL, NULL
};
+#if 0
struct proc_dir_entry proc_coda_ncstats = {
0 , 12, "coda-ncstats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
cfsnc_nc_info
};
+#endif
+
+struct proc_dir_entry proc_coda_vfs = {
+ PROC_VFS_STATS , 9, "vfs_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_vfs_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_vfs_control = {
+ 0 , 9, "vfs_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_vfs_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_upcall = {
+ PROC_UPCALL_STATS , 12, "upcall_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_upcall_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_upcall_control = {
+ 0 , 12, "upcall_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_upcall_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_permission = {
+ PROC_PERMISSION_STATS , 16, "permission_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_permission_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_permission_control = {
+ 0 , 16, "permission_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_permission_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_cache_inv = {
+ PROC_CACHE_INV_STATS , 15, "cache_inv_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_cache_inv_stats_get_info
+ };
+
+struct proc_dir_entry proc_coda_cache_inv_control = {
+ 0 , 15, "cache_inv_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ coda_cache_inv_stats_get_info
+ };
#endif
@@ -429,9 +516,27 @@ int init_coda_psdev(void)
memset(coda_super_info, 0, sizeof(coda_super_info));
memset(&coda_callstats, 0, sizeof(coda_callstats));
+ reset_coda_vfs_stats();
+ reset_coda_upcall_stats();
+ reset_coda_permission_stats();
+ reset_coda_cache_inv_stats();
+
#ifdef CONFIG_PROC_FS
- proc_register(&proc_root,&proc_coda);
- proc_register(&proc_coda, &proc_coda_ncstats);
+ proc_register(&proc_root,&proc_fs);
+ proc_register(&proc_fs,&proc_fs_coda);
+ proc_register(&proc_fs_coda,&proc_coda_vfs);
+ proc_register(&proc_fs_coda,&proc_coda_upcall);
+ proc_register(&proc_fs_coda,&proc_coda_permission);
+ proc_register(&proc_fs_coda,&proc_coda_cache_inv);
+#if 0
+ proc_register(&proc_fs_coda, &proc_coda_ncstats);
+#endif
+ proc_register(&proc_sys_root,&proc_sys_coda);
+ proc_register(&proc_sys_coda,&proc_coda_vfs_control);
+ proc_register(&proc_sys_coda,&proc_coda_upcall_control);
+ proc_register(&proc_sys_coda,&proc_coda_permission_control);
+ proc_register(&proc_sys_coda,&proc_coda_cache_inv_control);
+
coda_sysctl_init();
#endif
return 0;
@@ -476,8 +581,22 @@ void cleanup_module(void)
#if CONFIG_PROC_FS
coda_sysctl_clean();
- proc_unregister(&proc_coda, proc_coda_ncstats.low_ino);
- proc_unregister(&proc_root, proc_coda.low_ino);
+
+ proc_unregister(&proc_sys_coda, proc_coda_cache_inv_control.low_ino);
+ proc_unregister(&proc_sys_coda, proc_coda_permission_control.low_ino);
+ proc_unregister(&proc_sys_coda, proc_coda_upcall_control.low_ino);
+ proc_unregister(&proc_sys_coda,proc_coda_vfs_control.low_ino);
+ proc_unregister(&proc_sys_root, proc_sys_coda.low_ino);
+
+#if 0
+ proc_unregister(&proc_fs_coda, proc_coda_ncstats.low_ino);
+#endif
+ proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
+ proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
+ proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
+ proc_unregister(&proc_fs_coda, proc_coda_vfs.low_ino);
+ proc_unregister(&proc_fs, proc_fs_coda.low_ino);
+ proc_unregister(&proc_root, proc_fs.low_ino);
#endif
}
diff --git a/fs/coda/stats.c b/fs/coda/stats.c
new file mode 100644
index 000000000..1b55b8ea7
--- /dev/null
+++ b/fs/coda/stats.c
@@ -0,0 +1,416 @@
+/*
+ * stats.c
+ *
+ * CODA operation statistics
+ *
+ * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+#include <linux/swapctl.h>
+#include <linux/proc_fs.h>
+#include <linux/malloc.h>
+#include <linux/stat.h>
+#include <linux/ctype.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <linux/utsname.h>
+
+#include <linux/coda.h>
+#include <linux/coda_linux.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_psdev.h>
+#include <linux/coda_cache.h>
+#include <linux/coda_proc.h>
+
+struct coda_vfs_stats coda_vfs_stat;
+struct coda_permission_stats coda_permission_stat;
+struct coda_cache_inv_stats coda_cache_inv_stat;
+struct coda_upcall_stats_entry coda_upcall_stat[CFS_NCALLS];
+
+/* keep this in sync with coda.h! */
+char *coda_upcall_names[] = {
+ "totals ", /* 0 */
+ "noop ", /* 1 */
+ "root ", /* 2 */
+ "sync ", /* 3 */
+ "open ", /* 4 */
+ "close ", /* 5 */
+ "ioctl ", /* 6 */
+ "getattr ", /* 7 */
+ "setattr ", /* 8 */
+ "access ", /* 9 */
+ "lookup ", /* 10 */
+ "create ", /* 11 */
+ "remove ", /* 12 */
+ "link ", /* 13 */
+ "rename ", /* 14 */
+ "mkdir ", /* 15 */
+ "rmdir ", /* 16 */
+ "readdir ", /* 17 */
+ "symlink ", /* 18 */
+ "readlink ", /* 19 */
+ "fsync ", /* 20 */
+ "inactive ", /* 21 */
+ "vget ", /* 22 */
+ "signal ", /* 23 */
+ "replace ", /* 24 */
+ "flush ", /* 25 */
+ "purgeuser ", /* 26 */
+ "zapfile ", /* 27 */
+ "zapdir ", /* 28 */
+ "zapvnode ", /* 28 */
+ "purgefid ", /* 30 */
+ "open_by_path" /* 31 */
+};
+
+
+
+
+void reset_coda_vfs_stats( void )
+{
+ memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
+}
+
+#if 0
+static void reset_upcall_entry( struct coda_upcall_stats_entry * pentry )
+{
+ pentry->count = 0;
+ pentry->time_sum = pentry->time_squared_sum = 0;
+}
+#endif
+
+void reset_coda_upcall_stats( void )
+{
+ memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) );
+}
+
+void reset_coda_permission_stats( void )
+{
+ memset( &coda_permission_stat, 0, sizeof( coda_permission_stat ) );
+}
+
+void reset_coda_cache_inv_stats( void )
+{
+ memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
+}
+
+
+void do_time_stats( struct coda_upcall_stats_entry * pentry,
+ unsigned long runtime )
+{
+
+ unsigned long time = runtime * 1000 /HZ; /* time in ms */
+ CDEBUG(D_SPECIAL, "time: %ld\n", time);
+
+ if ( pentry->count == 0 ) {
+ pentry->time_sum = pentry->time_squared_sum = 0;
+ }
+
+ pentry->count++;
+ pentry->time_sum += time;
+ pentry->time_squared_sum += time*time;
+}
+
+
+
+void coda_upcall_stats(int opcode, long unsigned runtime)
+{
+ struct coda_upcall_stats_entry * pentry;
+
+ if ( opcode < 0 || opcode > CFS_NCALLS - 1) {
+ printk("Nasty opcode %d passed to coda_upcall_stats\n",
+ opcode);
+ return;
+ }
+
+ pentry = &coda_upcall_stat[opcode];
+ do_time_stats(pentry, runtime);
+
+ /* fill in the totals */
+ pentry = &coda_upcall_stat[0];
+ do_time_stats(pentry, runtime);
+
+}
+
+unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry )
+{
+ return ( pentry->count == 0 ) ? 0 : pentry->time_sum / pentry->count;
+}
+
+static inline unsigned long absolute( unsigned long x )
+{
+ return x >= 0 ? x : -x;
+}
+
+static unsigned long sqr_root( unsigned long x )
+{
+ unsigned long y = x, r;
+ int n_bit = 0;
+
+ if ( x == 0 )
+ return 0;
+ if ( x < 0)
+ x = -x;
+
+ while ( y ) {
+ y >>= 1;
+ n_bit++;
+ }
+
+ r = 1 << (n_bit/2);
+
+ while ( 1 ) {
+ r = (r + x/r)/2;
+ if ( r*r <= x && x < (r+1)*(r+1) )
+ break;
+ }
+
+ return r;
+}
+
+unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry )
+{
+ unsigned long time_avg;
+
+ if ( pentry->count <= 1 )
+ return 0;
+
+ time_avg = get_time_average( pentry );
+ return
+ sqr_root( (pentry->time_squared_sum / pentry->count) -
+ time_avg * time_avg );
+}
+
+int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
+ void * buffer, size_t * lenp )
+{
+ if ( write ) {
+ reset_coda_vfs_stats();
+ }
+
+ *lenp = 0;
+ return 0;
+}
+
+int do_reset_coda_upcall_stats( ctl_table * table, int write,
+ struct file * filp, void * buffer,
+ size_t * lenp )
+{
+ if ( write ) {
+ reset_coda_upcall_stats();
+ }
+
+ *lenp = 0;
+ return 0;
+}
+
+int do_reset_coda_permission_stats( ctl_table * table, int write,
+ struct file * filp, void * buffer,
+ size_t * lenp )
+{
+ if ( write ) {
+ reset_coda_permission_stats();
+ }
+
+ *lenp = 0;
+ return 0;
+}
+
+int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
+ struct file * filp, void * buffer,
+ size_t * lenp )
+{
+ if ( write ) {
+ reset_coda_cache_inv_stats();
+ }
+
+ *lenp = 0;
+ return 0;
+}
+
+int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy )
+{
+ int len=0;
+ off_t begin;
+ struct coda_vfs_stats * ps = & coda_vfs_stat;
+
+ /* this works as long as we are below 1024 characters! */
+ len += sprintf( buffer,
+ "Coda VFS statistics\n"
+ "===================\n\n"
+ "File Operations:\n"
+ "\tfile_read\t%9d\n"
+ "\tfile_write\t%9d\n"
+ "\tfile_mmap\t%9d\n"
+ "\topen\t\t%9d\n"
+ "\trelase\t\t%9d\n"
+ "\tfsync\t\t%9d\n\n"
+ "Dir Operations:\n"
+ "\treaddir\t\t%9d\n\n"
+ "Inode Operations\n"
+ "\tcreate\t\t%9d\n"
+ "\tlookup\t\t%9d\n"
+ "\tlink\t\t%9d\n"
+ "\tunlink\t\t%9d\n"
+ "\tsymlink\t\t%9d\n"
+ "\tmkdir\t\t%9d\n"
+ "\trmdir\t\t%9d\n"
+ "\trename\t\t%9d\n"
+ "\tpermission\t%9d\n"
+ "\treadpage\t%9d\n",
+
+ /* file operations */
+ ps->file_read,
+ ps->file_write,
+ ps->file_mmap,
+ ps->open,
+ ps->release,
+ ps->fsync,
+
+ /* dir operations */
+ ps->readdir,
+
+ /* inode operations */
+ ps->create,
+ ps->lookup,
+ ps->link,
+ ps->unlink,
+ ps->symlink,
+ ps->mkdir,
+ ps->rmdir,
+ ps->rename,
+ ps->permission,
+ ps->readpage );
+
+ begin = offset;
+ *start = buffer + begin;
+ len -= begin;
+
+ if ( len > length )
+ len = length;
+ if ( len < 0 )
+ len = 0;
+
+ return len;
+}
+
+int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy )
+{
+ int len=0;
+ int i;
+ off_t begin;
+ off_t pos = 0;
+ char tmpbuf[80];
+ int tmplen = 0;
+
+ ENTRY;
+ /* this works as long as we are below 1024 characters! */
+ if ( offset < 80 )
+ len += sprintf( buffer,"%-79s\n", "Coda upcall statistics");
+ if ( offset < 160)
+ len += sprintf( buffer + len,"%-79s\n", "======================");
+ if ( offset < 240)
+ len += sprintf( buffer + len,"%-79s\n", "upcall\t\t count\tavg time(ms)\tstd deviation(ms)");
+ if ( offset < 320)
+ len += sprintf( buffer + len,"%-79s\n", "------\t\t -----\t------------\t-----------------");
+ pos = 320;
+ for ( i = 0 ; i < CFS_NCALLS ; i++ ) {
+ tmplen += sprintf(tmpbuf,"%s\t%9d\t%10ld\t%10ld",
+ coda_upcall_names[i],
+ coda_upcall_stat[i].count,
+ get_time_average(&coda_upcall_stat[i]),
+ coda_upcall_stat[i].time_squared_sum);
+ pos += 80;
+ if ( pos < offset )
+ continue;
+ len += sprintf(buffer + len, "%-79s\n", tmpbuf);
+ if ( len >= length )
+ break;
+ }
+
+ begin = len- (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+
+ if ( len > length )
+ len = length;
+ if ( len < 0 )
+ len = 0;
+ EXIT;
+ return len;
+}
+
+int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy )
+{
+ int len=0;
+ off_t begin;
+ struct coda_permission_stats * ps = & coda_permission_stat;
+
+ /* this works as long as we are below 1024 characters! */
+ len += sprintf( buffer,
+ "Coda permission statistics\n"
+ "==========================\n\n"
+ "count\t\t%9d\n"
+ "hit count\t%9d\n",
+
+ ps->count,
+ ps->hit_count );
+
+ begin = offset;
+ *start = buffer + begin;
+ len -= begin;
+
+ if ( len > length )
+ len = length;
+ if ( len < 0 )
+ len = 0;
+
+ return len;
+}
+
+int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy )
+{
+ int len=0;
+ off_t begin;
+ struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
+
+ /* this works as long as we are below 1024 characters! */
+ len += sprintf( buffer,
+ "Coda cache invalidation statistics\n"
+ "==================================\n\n"
+ "flush\t\t%9d\n"
+ "purge user\t%9d\n"
+ "zap_dir\t\t%9d\n"
+ "zap_file\t%9d\n"
+ "zap_vnode\t%9d\n"
+ "purge_fid\t%9d\n"
+ "replace\t\t%9d\n",
+ ps->flush,
+ ps->purge_user,
+ ps->zap_dir,
+ ps->zap_file,
+ ps->zap_vnode,
+ ps->purge_fid,
+ ps->replace );
+
+ begin = offset;
+ *start = buffer + begin;
+ len -= begin;
+
+ if ( len > length )
+ len = length;
+ if ( len < 0 )
+ len = 0;
+
+ return len;
+}
+
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index c6d770a20..eb2fe150d 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -23,6 +23,7 @@
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
+#include <linux/coda_proc.h>
static int coda_readlink(struct dentry *de, char *buffer, int length);
static struct dentry *coda_follow_link(struct dentry *, struct dentry *);
@@ -60,7 +61,7 @@ static int coda_readlink(struct dentry *de, char *buffer, int length)
ENTRY;
cp = ITOC(inode);
- CHECK_CNODE(cp);
+ coda_vfs_stat.readlink++;
/* the maximum length we receive is len */
if ( length > CFS_MAXPATHLEN )
@@ -93,11 +94,11 @@ static struct dentry *coda_follow_link(struct dentry *de,
unsigned int len;
char mem[CFS_MAXPATHLEN];
char *path;
-ENTRY;
+ ENTRY;
CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino);
cnp = ITOC(inode);
- CHECK_CNODE(cnp);
+ coda_vfs_stat.follow_link++;
len = CFS_MAXPATHLEN;
error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len);
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index c21016030..36e327dce 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -26,7 +26,7 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
#include <linux/coda_cache.h>
-#include <linux/coda_sysctl.h>
+#include <linux/coda_proc.h>
extern int coda_debug;
/* extern int cfsnc_use; */
extern int coda_print_entry;
@@ -47,6 +47,10 @@ struct ctl_table_header *fs_table_header, *coda_table_header;
#define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
#define CODA_MC 4 /* use/do not use the access cache */
#define CODA_HARD 5 /* mount type "hard" or "soft" */
+#define CODA_VFS 6 /* vfs statistics */
+#define CODA_UPCALL 7 /* upcall statistics */
+#define CODA_PERMISSION 8 /* permission statistics */
+#define CODA_CACHE_INV 9 /* cache invalidation statistics */
@@ -56,6 +60,10 @@ static ctl_table coda_table[] = {
{CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &coda_dointvec},
{CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &coda_dointvec},
{CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &coda_dointvec},
+ {CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
+ {CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
+ {CODA_PERMISSION, "permission_stats", NULL, 0, 0644, NULL, &do_reset_coda_permission_stats},
+ {CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
{ 0 }
};
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 13d3127c6..0e3ba95d1 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -37,6 +37,11 @@
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
+#include <linux/coda_proc.h>
+
+
+static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
+ union inputArgs *buffer);
#define UPARG(op)\
do {\
@@ -68,10 +73,11 @@ int venus_rootfid(struct super_block *sb, ViceFid *fidp)
union inputArgs *inp;
union outputArgs *outp;
int insize, outsize, error;
-ENTRY;
+ ENTRY;
insize = SIZE(root);
UPARG(CFS_ROOT);
+
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if (error) {
@@ -92,7 +98,7 @@ int venus_getattr(struct super_block *sb, struct ViceFid *fid,
{
union inputArgs *inp;
union outputArgs *outp;
- int insize, outsize, error;
+ int insize, outsize, error;
ENTRY;
insize = SIZE(getattr);
UPARG(CFS_GETATTR);
@@ -458,8 +464,8 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid,
int venus_fsync(struct super_block *sb, struct ViceFid *fid)
{
union inputArgs *inp;
- union outputArgs *outp;
- int insize, outsize, error;
+ union outputArgs *outp;
+ int insize, outsize, error;
insize=SIZE(fsync);
UPARG(CFS_FSYNC);
@@ -476,8 +482,8 @@ int venus_fsync(struct super_block *sb, struct ViceFid *fid)
int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
{
union inputArgs *inp;
- union outputArgs *outp;
- int insize, outsize, error;
+ union outputArgs *outp;
+ int insize, outsize, error;
insize = SIZE(access);
UPARG(CFS_ACCESS);
@@ -497,8 +503,8 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
unsigned int cmd, struct PioctlData *data)
{
union inputArgs *inp;
- union outputArgs *outp;
- int insize, outsize, error;
+ union outputArgs *outp;
+ int insize, outsize, error;
int iocsize;
insize = VC_MAXMSGSIZE;
@@ -583,11 +589,13 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
* reply and return Venus' error, also POSITIVE.
*
*/
-static inline void coda_waitfor_upcall(struct vmsg *vmp)
+static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp)
{
struct wait_queue wait = { current, NULL };
+ unsigned long posttime;
vmp->vm_posttime = jiffies;
+ posttime = jiffies;
add_wait_queue(&vmp->vm_sleep, &wait);
for (;;) {
@@ -616,13 +624,17 @@ static inline void coda_waitfor_upcall(struct vmsg *vmp)
remove_wait_queue(&vmp->vm_sleep, &wait);
current->state = TASK_RUNNING;
- return;
+ CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", posttime, jiffies-posttime);
+ return (jiffies - posttime);
+
}
-int coda_upcall(struct coda_sb_info *sbi, int inSize, int *outSize,
+static int coda_upcall(struct coda_sb_info *sbi,
+ int inSize, int *outSize,
union inputArgs *buffer)
{
+ unsigned long runtime;
struct vcomm *vcommp;
union outputArgs *out;
struct vmsg *vmp;
@@ -635,7 +647,6 @@ ENTRY;
}
vcommp = sbi->sbi_vcomm;
- clstats(((union inputArgs *)buffer)->ih.opcode);
if (!vcomm_open(vcommp))
return(ENODEV);
@@ -670,7 +681,8 @@ ENTRY;
* ENODEV. */
/* Go to sleep. Wake up on signals only after the timeout. */
- coda_waitfor_upcall(vmp);
+ runtime = coda_waitfor_upcall(vmp);
+ coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
vmp->vm_opcode, jiffies - vmp->vm_posttime,
diff --git a/fs/dcache.c b/fs/dcache.c
index 58c6479c9..0ef962687 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -430,12 +430,17 @@ void shrink_dcache_parent(struct dentry * parent)
* more memory, but aren't really sure how much. So we
* carefully try to free a _bit_ of our dcache, but not
* too much.
+ *
+ * Priority:
+ * 0 - very urgent: schrink everything
+ * ...
+ * 6 - base-level: try to shrink a bit.
*/
-void shrink_dcache_memory(void)
+void shrink_dcache_memory(int priority, unsigned int gfp_mask)
{
int count = select_dcache(32, 8);
if (count)
- prune_dcache(count);
+ prune_dcache((count << 6) >> priority);
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
diff --git a/fs/dquot.c b/fs/dquot.c
index b868ac3d7..58393b016 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -375,7 +375,8 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes)
if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
return(QUOTA_OK);
if (dquot->dq_ihardlimit &&
- (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && !fsuser()) {
+ (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit &&
+ !capable(CAP_SYS_RESOURCE)) {
if ((dquot->dq_flags & DQ_INODES) == 0 &&
need_print_warning(type, dquot)) {
sprintf(quotamessage, "%s: write failed, %s file limit reached\r\n",
@@ -387,7 +388,8 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes)
}
if (dquot->dq_isoftlimit &&
(dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
- dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !fsuser()) {
+ dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime &&
+ !capable(CAP_SYS_RESOURCE)) {
if (need_print_warning(type, dquot)) {
sprintf(quotamessage, "%s: warning, %s file quota exceeded too long.\r\n",
dquot->dq_mnt->mnt_dirname, quotatypes[type]);
@@ -397,7 +399,8 @@ static int check_idq(struct dquot *dquot, short type, u_long short inodes)
}
if (dquot->dq_isoftlimit &&
(dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
- dquot->dq_itime == 0 && !fsuser()) {
+ dquot->dq_itime == 0 &&
+ !capable(CAP_SYS_RESOURCE)) {
if (need_print_warning(type, dquot)) {
sprintf(quotamessage, "%s: warning, %s file quota exceeded\r\n",
dquot->dq_mnt->mnt_dirname, quotatypes[type]);
@@ -413,7 +416,8 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks)
if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)
return(QUOTA_OK);
if (dquot->dq_bhardlimit &&
- (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && !fsuser()) {
+ (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit &&
+ !capable(CAP_SYS_RESOURCE)) {
if ((dquot->dq_flags & DQ_BLKS) == 0 &&
need_print_warning(type, dquot)) {
sprintf(quotamessage, "%s: write failed, %s disk limit reached.\r\n",
@@ -425,7 +429,8 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks)
}
if (dquot->dq_bsoftlimit &&
(dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
- dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !fsuser()) {
+ dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime &&
+ !capable(CAP_SYS_RESOURCE)) {
if (need_print_warning(type, dquot)) {
sprintf(quotamessage, "%s: write failed, %s disk quota exceeded too long.\r\n",
dquot->dq_mnt->mnt_dirname, quotatypes[type]);
@@ -435,7 +440,8 @@ static int check_bdq(struct dquot *dquot, short type, u_long blocks)
}
if (dquot->dq_bsoftlimit &&
(dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
- dquot->dq_btime == 0 && !fsuser()) {
+ dquot->dq_btime == 0 &&
+ !capable(CAP_SYS_RESOURCE)) {
if (need_print_warning(type, dquot)) {
sprintf(quotamessage, "%s: warning, %s disk quota exceeded\r\n",
dquot->dq_mnt->mnt_dirname, quotatypes[type]);
@@ -1039,11 +1045,12 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
break;
case Q_GETQUOTA:
if (((type == USRQUOTA && current->uid != id) ||
- (type == GRPQUOTA && in_group_p(id))) && !fsuser())
+ (type == GRPQUOTA && in_group_p(id))) &&
+ !capable(CAP_SYS_ADMIN))
goto out;
break;
default:
- if (!fsuser())
+ if (!capable(CAP_SYS_ADMIN))
goto out;
}
diff --git a/fs/exec.c b/fs/exec.c
index 0ad7c4cdf..3e97d8bd3 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -77,10 +77,6 @@ __initfunc(void binfmt_setup(void))
init_elf_binfmt();
#endif
-#ifdef CONFIG_BINFMT_IRIX
- init_irix_binfmt();
-#endif
-
#ifdef CONFIG_BINFMT_ELF32
init_elf32_binfmt();
#endif
@@ -289,16 +285,18 @@ unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
p -= len;
pos = p;
while (len) {
- char *pag;
+ char *pag = (char *) page[pos/PAGE_SIZE];
int offset, bytes_to_copy;
offset = pos % PAGE_SIZE;
- if (!(pag = (char *) page[pos/PAGE_SIZE]) &&
- !(pag = (char *) page[pos/PAGE_SIZE] =
- (unsigned long *) get_free_page(GFP_USER))) {
- if (from_kmem==2)
- set_fs(old_fs);
- return 0;
+ if(!pag) {
+ pag = (char *) page[pos/PAGE_SIZE] = get_user_page(pos);
+ if(!pag) {
+ if(from_kmem == 2)
+ set_fs(old_fs);
+ return 0;
+ }
+ clear_page(pag);
}
bytes_to_copy = PAGE_SIZE - offset;
if (bytes_to_copy > len)
@@ -423,6 +421,7 @@ static int exec_mmap(void)
retval = new_page_tables(current);
if (retval)
goto fail_restore;
+ activate_context(current);
up(&mm->mmap_sem);
mmput(old_mm);
return 0;
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 7555b9a6f..111a2d6e0 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -51,8 +51,11 @@ int ext2_permission (struct inode * inode, int mask)
* Access is always granted for root. We now check last,
* though, for BSD process accounting correctness
*/
- if (((mode & mask & S_IRWXO) == mask) || fsuser())
+ if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
return 0;
- else
- return -EACCES;
+ if ((mask == S_IROTH) ||
+ (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
+ if (capable(CAP_DAC_READ_SEARCH))
+ return 0;
+ return -EACCES;
}
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index de5b422ed..f4ee29211 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -383,7 +383,8 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
((sb->u.ext2_sb.s_resuid != current->fsuid) &&
(sb->u.ext2_sb.s_resgid == 0 ||
- !in_group_p (sb->u.ext2_sb.s_resgid)) && !fsuser())) {
+ !in_group_p (sb->u.ext2_sb.s_resgid)) &&
+ !capable(CAP_SYS_RESOURCE))) {
unlock_super (sb);
return 0;
}
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 143dc53d5..3b36f970f 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -144,7 +144,7 @@ static inline void remove_suid(struct inode *inode)
/* was any of the uid bits set? */
mode &= inode->i_mode;
- if (mode && !suser()) {
+ if (mode && !capable(CAP_FSETID)) {
inode->i_mode &= ~mode;
mark_inode_dirty(inode);
}
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index a48723031..f0f2ca98f 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -726,9 +726,9 @@ int ext2_notify_change(struct dentry *dentry, struct iattr *iattr)
(ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
(inode->u.ext2_i.i_flags &
(EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
- if (!fsuser())
+ if (!capable(CAP_LINUX_IMMUTABLE))
goto out;
- } else if ((current->fsuid != inode->i_uid) && !fsuser())
+ } else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
goto out;
retval = inode_change_ok(inode, iattr);
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 70d4fc563..3b58bc822 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -39,10 +39,11 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
(inode->u.ext2_i.i_flags &
(EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
/* This test looks nicer. Thanks to Pauline Middelink */
- if (!fsuser())
+ if (!capable(CAP_LINUX_IMMUTABLE))
return -EPERM;
} else
- if ((current->fsuid != inode->i_uid) && !fsuser())
+ if ((current->fsuid != inode->i_uid) &&
+ !capable(CAP_FOWNER))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
@@ -70,7 +71,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
case EXT2_IOC_GETVERSION:
return put_user(inode->u.ext2_i.i_version, (int *) arg);
case EXT2_IOC_SETVERSION:
- if ((current->fsuid != inode->i_uid) && !fsuser())
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index e043163dc..5560efe63 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -631,7 +631,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
retval = -EPERM;
if ((dir->i_mode & S_ISVTX) &&
current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
+ current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
goto end_rmdir;
if (inode == dir) /* we may not delete ".", but "../dir" is ok */
goto end_rmdir;
@@ -725,7 +725,7 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
goto end_unlink;
if ((dir->i_mode & S_ISVTX) &&
current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
+ current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
goto end_unlink;
retval = -EIO;
@@ -923,7 +923,7 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
- current->fsuid != old_dir->i_uid && !fsuser())
+ current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER))
goto end_rename;
if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode))
goto end_rename;
@@ -964,7 +964,7 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
if (new_inode) {
if ((new_dir->i_mode & S_ISVTX) &&
current->fsuid != new_inode->i_uid &&
- current->fsuid != new_dir->i_uid && !fsuser())
+ current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER))
goto end_rename;
if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode))
goto end_rename;
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index e6bf93e4b..3155e72e4 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -416,7 +416,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry)
if ((dir->i_mode & S_ISVTX) &&
current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
+ current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
goto end_rmdir;
if (inode->i_dev != dir->i_dev)
goto end_rmdir;
@@ -482,7 +482,7 @@ repeat:
}
if ((dir->i_mode & S_ISVTX) &&
current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
+ current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
goto end_unlink;
if (de->inode != inode->i_ino) {
retval = -ENOENT;
@@ -641,7 +641,7 @@ start_up:
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
- current->fsuid != old_dir->i_uid && !fsuser())
+ current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER))
goto end_rename;
new_inode = new_dentry->d_inode;
new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
@@ -673,7 +673,7 @@ start_up:
retval = -EPERM;
if (new_inode && (new_dir->i_mode & S_ISVTX) &&
current->fsuid != new_inode->i_uid &&
- current->fsuid != new_dir->i_uid && !fsuser())
+ current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER))
goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
retval = -ENOTDIR;
diff --git a/fs/namei.c b/fs/namei.c
index a6de99ead..04ebe1fd9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -43,17 +43,24 @@
*
* The new code replaces the old recursive symlink resolution with
* an iterative one (in case of non-nested symlink chains). It does
- * this by looking up the symlink name from the particular filesystem,
- * and then follows this name as if it were a user-supplied one. This
- * is done solely in the VFS level, such that <fs>_follow_link() is not
- * used any more and could be removed in future. As a side effect,
- * dir_namei(), _namei() and follow_link() are now replaced with a single
- * function lookup_dentry() that can handle all the special cases of the former
- * code.
+ * this with calls to <fs>_follow_link().
+ * As a side effect, dir_namei(), _namei() and follow_link() are now
+ * replaced with a single function lookup_dentry() that can handle all
+ * the special cases of the former code.
*
* With the new dcache, the pathname is stored at each inode, at least as
* long as the refcount of the inode is positive. As a side effect, the
* size of the dcache depends on the inode cache and thus is dynamic.
+ *
+ * [29-Apr-1998 C. Scott Ananian] Updated above description of symlink
+ * resolution to correspond with current state of the code.
+ *
+ * Note that the symlink resolution is not *completely* iterative.
+ * There is still a significant amount of tail- and mid- recursion in
+ * the algorithm. Also, note that <fs>_readlink() is not used in
+ * lookup_dentry(): lookup_dentry() on the result of <fs>_readlink()
+ * may return different results than <fs>_follow_link(). Many virtual
+ * filesystems (including /proc) exhibit this behavior.
*/
/* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation:
@@ -191,8 +198,13 @@ int permission(struct inode * inode,int mask)
mode >>= 6;
else if (in_group_p(inode->i_gid))
mode >>= 3;
- if (((mode & mask & 0007) == mask) || fsuser())
+ if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
return 0;
+ /* read and search access */
+ if ((mask == S_IROTH) ||
+ (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
+ if (capable(CAP_DAC_READ_SEARCH))
+ return 0;
return -EACCES;
}
@@ -699,7 +711,7 @@ asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
lock_kernel();
error = -EPERM;
- if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser()))
+ if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !capable(CAP_SYS_ADMIN)))
goto out;
error = -EINVAL;
switch (mode & S_IFMT) {
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 7acaafade..66c4ecd1f 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -148,7 +148,7 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
if (!initialized)
nfsd_init();
err = -EPERM;
- if (!suser()) {
+ if (!capable(CAP_SYS_ADMIN)) {
goto done;
}
err = -EFAULT;
diff --git a/fs/open.c b/fs/open.c
index 204294cc3..6d23874f9 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -285,12 +285,14 @@ out:
/*
* access() needs to use the real uid/gid, not the effective uid/gid.
- * We do this by temporarily setting fsuid/fsgid to the wanted values
+ * We do this by temporarily clearing all FS-related capabilities and
+ * switching the fsuid/fsgid around to the real ones.
*/
asmlinkage int sys_access(const char * filename, int mode)
{
struct dentry * dentry;
int old_fsuid, old_fsgid;
+ kernel_cap_t old_cap;
int res = -EINVAL;
lock_kernel();
@@ -298,9 +300,15 @@ asmlinkage int sys_access(const char * filename, int mode)
goto out;
old_fsuid = current->fsuid;
old_fsgid = current->fsgid;
+ old_cap = current->cap_effective;
+
current->fsuid = current->uid;
current->fsgid = current->gid;
+ /* Clear the capabilities if we switch to a non-root user */
+ if (current->uid)
+ cap_clear(current->cap_effective);
+
dentry = namei(filename);
res = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
@@ -310,6 +318,7 @@ asmlinkage int sys_access(const char * filename, int mode)
current->fsuid = old_fsuid;
current->fsgid = old_fsgid;
+ current->cap_effective = old_cap;
out:
unlock_kernel();
return res;
@@ -411,7 +420,7 @@ asmlinkage int sys_chroot(const char * filename)
goto dput_and_out;
error = -EPERM;
- if (!fsuser())
+ if (!capable(CAP_SYS_CHROOT))
goto dput_and_out;
/* exchange dentries */
@@ -833,7 +842,7 @@ asmlinkage int sys_vhangup(void)
int ret = -EPERM;
lock_kernel();
- if (!suser())
+ if (!capable(CAP_SYS_TTY_CONFIG))
goto out;
/* If there is a controlling tty, hang it up */
if (current->tty)
diff --git a/fs/pipe.c b/fs/pipe.c
index cf0c44b6e..62ff29c87 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -54,7 +54,7 @@ static ssize_t pipe_read(struct file * filp, char * buf,
}
} else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) {
if (PIPE_EMPTY(*inode)) {
- if (!PIPE_WRITERS(*inode))
+ if (!PIPE_WRITERS(*inode) || !count)
return 0;
}
if (signal_pending(current))
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 26621a6e5..f80893afc 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -786,6 +786,17 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
return buffer;
}
+extern inline char *task_cap(struct task_struct *p, char *buffer)
+{
+ return buffer + sprintf(buffer, "CapInh:\t%016x\n"
+ "CapPrm:\t%016x\n"
+ "CapEff:\t%016x\n",
+ p->cap_inheritable.cap,
+ p->cap_permitted.cap,
+ p->cap_effective.cap);
+}
+
+
static int get_status(int pid, char * buffer)
{
char * orig = buffer;
@@ -800,6 +811,7 @@ static int get_status(int pid, char * buffer)
buffer = task_state(tsk, buffer);
buffer = task_mem(tsk, buffer);
buffer = task_sig(tsk, buffer);
+ buffer = task_cap(tsk, buffer);
return buffer - orig;
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index b2feaeef1..b4ca1094c 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -145,8 +145,13 @@ static int standard_permission(struct inode *inode, int mask)
mode >>= 6;
else if (in_group_p(inode->i_gid))
mode >>= 3;
- if (((mode & mask & 0007) == mask) || fsuser())
+ if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
return 0;
+ /* read and search access */
+ if ((mask == S_IROTH) ||
+ (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
+ if (capable(CAP_DAC_READ_SEARCH))
+ return 0;
return -EACCES;
}
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 34f9f969f..5597c2e6d 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -630,7 +630,8 @@ printk("smb_newconn: fd=%d, pid=%d\n", opt->fd, current->pid);
goto out;
error = -EACCES;
- if (current->uid != server->mnt->mounted_uid && !suser())
+ if (current->uid != server->mnt->mounted_uid &&
+ !capable(CAP_SYS_ADMIN))
goto out;
error = -EBADF;
diff --git a/fs/super.c b/fs/super.c
index 0433dd251..b28b5f0b6 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -743,7 +743,7 @@ asmlinkage int sys_umount(char * name)
struct dentry * dentry;
int retval;
- if (!suser())
+ if (!capable(CAP_SYS_ADMIN))
return -EPERM;
lock_kernel();
@@ -985,7 +985,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
struct file dummy; /* allows read-write or read-only flag */
lock_kernel();
- if (!suser())
+ if (!capable(CAP_SYS_ADMIN))
goto out;
if ((new_flags &
(MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 270cfe637..60b50720a 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -419,7 +419,7 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry)
if ((dir->i_mode & S_ISVTX) &&
current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
+ current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
goto end_rmdir;
if (inode->i_dev != dir->i_dev)
goto end_rmdir;
@@ -484,7 +484,7 @@ repeat:
}
if ((dir->i_mode & S_ISVTX) &&
current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid && !fsuser())
+ current->fsuid != dir->i_uid && !capable(CAP_FOWNER))
goto end_unlink;
if (de->inode != inode->i_ino) {
retval = -ENOENT;
@@ -643,7 +643,7 @@ start_up:
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
- current->fsuid != old_dir->i_uid && !fsuser())
+ current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER))
goto end_rename;
new_inode = new_dentry->d_inode;
new_bh = sysv_find_entry(new_dir, new_dentry->d_name.name,
@@ -675,7 +675,7 @@ start_up:
retval = -EPERM;
if (new_inode && (new_dir->i_mode & S_ISVTX) &&
current->fsuid != new_inode->i_uid &&
- current->fsuid != new_dir->i_uid && !fsuser())
+ current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER))
goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
retval = -ENOTDIR;
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index be72a9cb4..7b549fd96 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -350,14 +350,14 @@ static int umsdos_rename_f(
Printk (("ret %d ",ret));
if (ret == 0){
/* check sticky bit on old_dir */
- if ( !(old_dir->i_mode & S_ISVTX) || fsuser() ||
+ if ( !(old_dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) ||
current->fsuid == old_info.entry.uid ||
current->fsuid == old_dir->i_uid ) {
/* Does new_name already exist? */
PRINTK(("new findentry "));
ret = umsdos_findentry(new_dir,&new_info,0);
if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
- !(new_dir->i_mode & S_ISVTX) || fsuser() ||
+ !(new_dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) ||
current->fsuid == new_info.entry.uid ||
current->fsuid == new_dir->i_uid ) {
PRINTK (("new newentry "));
@@ -933,7 +933,7 @@ int UMSDOS_rmdir(
umsdos_real_lookup (dir, tdentry); /* fill inode part */
Printk (("isempty %d i_count %d ",empty,sdir->i_count));
/* check sticky bit */
- if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+ if ( !(dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) ||
current->fsuid == sdir->i_uid ||
current->fsuid == dir->i_uid ) {
if (empty == 1){
@@ -1024,7 +1024,7 @@ int UMSDOS_unlink (
if (ret == 0){
Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname));
/* check sticky bit */
- if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+ if ( !(dir->i_mode & S_ISVTX) || capable(CAP_FOWNER) ||
current->fsuid == info.entry.uid ||
current->fsuid == dir->i_uid ) {
if (info.entry.flags & UMSDOS_HLINK){