diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
commit | 3917ac5846dd0f9ad1238166f90caab9912052e6 (patch) | |
tree | 1c298935def4f29edb39192365a65d73de999155 /fs | |
parent | af2f803c8b2d469fe38e4a7ce952658dfcb6681a (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.c | 4 | ||||
-rw-r--r-- | fs/attr.c | 12 | ||||
-rw-r--r-- | fs/autofs/root.c | 2 | ||||
-rw-r--r-- | fs/buffer.c | 2 | ||||
-rw-r--r-- | fs/coda/Makefile | 2 | ||||
-rw-r--r-- | fs/coda/cache.c | 41 | ||||
-rw-r--r-- | fs/coda/coda_linux.c | 1 | ||||
-rw-r--r-- | fs/coda/dir.c | 18 | ||||
-rw-r--r-- | fs/coda/file.c | 10 | ||||
-rw-r--r-- | fs/coda/psdev.c | 135 | ||||
-rw-r--r-- | fs/coda/stats.c | 416 | ||||
-rw-r--r-- | fs/coda/symlink.c | 7 | ||||
-rw-r--r-- | fs/coda/sysctl.c | 10 | ||||
-rw-r--r-- | fs/coda/upcall.c | 38 | ||||
-rw-r--r-- | fs/dcache.c | 9 | ||||
-rw-r--r-- | fs/dquot.c | 23 | ||||
-rw-r--r-- | fs/exec.c | 21 | ||||
-rw-r--r-- | fs/ext2/acl.c | 9 | ||||
-rw-r--r-- | fs/ext2/balloc.c | 3 | ||||
-rw-r--r-- | fs/ext2/file.c | 2 | ||||
-rw-r--r-- | fs/ext2/inode.c | 4 | ||||
-rw-r--r-- | fs/ext2/ioctl.c | 7 | ||||
-rw-r--r-- | fs/ext2/namei.c | 8 | ||||
-rw-r--r-- | fs/minix/namei.c | 8 | ||||
-rw-r--r-- | fs/namei.c | 30 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 2 | ||||
-rw-r--r-- | fs/open.c | 15 | ||||
-rw-r--r-- | fs/pipe.c | 2 | ||||
-rw-r--r-- | fs/proc/array.c | 12 | ||||
-rw-r--r-- | fs/proc/inode.c | 7 | ||||
-rw-r--r-- | fs/smbfs/proc.c | 3 | ||||
-rw-r--r-- | fs/super.c | 4 | ||||
-rw-r--r-- | fs/sysv/namei.c | 8 | ||||
-rw-r--r-- | fs/umsdos/namei.c | 8 |
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; @@ -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; } @@ -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; @@ -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) @@ -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){ |