diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/compat_ioctl.c | 8 | ||||
-rw-r--r-- | fs/debugfs/file.c | 6 | ||||
-rw-r--r-- | fs/file.c | 3 | ||||
-rw-r--r-- | fs/fuse/dev.c | 40 | ||||
-rw-r--r-- | fs/inotify.c | 2 | ||||
-rw-r--r-- | fs/jbd/transaction.c | 10 | ||||
-rw-r--r-- | fs/namei.c | 43 | ||||
-rw-r--r-- | fs/namespace.c | 58 | ||||
-rw-r--r-- | fs/nfs/nfsroot.c | 3 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 6 | ||||
-rw-r--r-- | fs/reiserfs/hashes.c | 1 | ||||
-rw-r--r-- | fs/select.c | 4 | ||||
-rw-r--r-- | fs/super.c | 5 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 3 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_iops.c | 2 |
15 files changed, 122 insertions, 72 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 5dd0207ffd46..057e60217fc5 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -931,8 +931,8 @@ struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ static int sg_grt_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { int err, i; - sg_req_info_t *r; - struct compat_sg_req_info *o = (struct compat_sg_req_info *)arg; + sg_req_info_t __user *r; + struct compat_sg_req_info __user *o = (void __user *)arg; r = compat_alloc_user_space(sizeof(sg_req_info_t)*SG_MAX_QUEUE); err = sys_ioctl(fd,cmd,(unsigned long)r); if (err < 0) @@ -2739,8 +2739,8 @@ static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned lon static int lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct compat_timeval *tc = (struct compat_timeval *)arg; - struct timeval *tn = compat_alloc_user_space(sizeof(struct timeval)); + struct compat_timeval __user *tc = (struct compat_timeval __user *)arg; + struct timeval __user *tn = compat_alloc_user_space(sizeof(struct timeval)); struct timeval ts; if (get_user(ts.tv_sec, &tc->tv_sec) || get_user(ts.tv_usec, &tc->tv_usec) || diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index efc97d9b7860..d575452cd9f7 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -56,7 +56,7 @@ static u64 debugfs_u8_get(void *data) DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); /** - * debugfs_create_u8 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. + * debugfs_create_u8 - create a file in the debugfs filesystem that is used to read and write an unsigned 8 bit value. * * @name: a pointer to a string containing the name of the file to create. * @mode: the permission that the file should have @@ -98,7 +98,7 @@ static u64 debugfs_u16_get(void *data) DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); /** - * debugfs_create_u16 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. + * debugfs_create_u16 - create a file in the debugfs filesystem that is used to read and write an unsigned 16 bit value. * * @name: a pointer to a string containing the name of the file to create. * @mode: the permission that the file should have @@ -140,7 +140,7 @@ static u64 debugfs_u32_get(void *data) DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); /** - * debugfs_create_u32 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. + * debugfs_create_u32 - create a file in the debugfs filesystem that is used to read and write an unsigned 32 bit value. * * @name: a pointer to a string containing the name of the file to create. * @mode: the permission that the file should have diff --git a/fs/file.c b/fs/file.c index fd066b261c75..cea7cbea11d0 100644 --- a/fs/file.c +++ b/fs/file.c @@ -379,7 +379,6 @@ static void __devinit fdtable_defer_list_init(int cpu) void __init files_defer_init(void) { int i; - /* Really early - can't use for_each_cpu */ - for (i = 0; i < NR_CPUS; i++) + for_each_cpu(i) fdtable_defer_list_init(i); } diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 4526da8907c6..f556a0d5c0d3 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -120,9 +120,9 @@ struct fuse_req *fuse_get_request(struct fuse_conn *fc) return do_get_request(fc); } +/* Must be called with fuse_lock held */ static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req) { - spin_lock(&fuse_lock); if (req->preallocated) { atomic_dec(&fc->num_waiting); list_add(&req->list, &fc->unused_list); @@ -134,11 +134,19 @@ static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req) fc->outstanding_debt--; else up(&fc->outstanding_sem); - spin_unlock(&fuse_lock); } void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) { + if (atomic_dec_and_test(&req->count)) { + spin_lock(&fuse_lock); + fuse_putback_request(fc, req); + spin_unlock(&fuse_lock); + } +} + +static void fuse_put_request_locked(struct fuse_conn *fc, struct fuse_req *req) +{ if (atomic_dec_and_test(&req->count)) fuse_putback_request(fc, req); } @@ -163,26 +171,36 @@ void fuse_release_background(struct fuse_req *req) * still waiting), the 'end' callback is called if given, else the * reference to the request is released * + * Releasing extra reference for foreground requests must be done + * within the same locked region as setting state to finished. This + * is because fuse_reset_request() may be called after request is + * finished and it must be the sole possessor. If request is + * interrupted and put in the background, it will return with an error + * and hence never be reset and reused. + * * Called with fuse_lock, unlocks it */ static void request_end(struct fuse_conn *fc, struct fuse_req *req) { - void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; - req->end = NULL; list_del(&req->list); req->state = FUSE_REQ_FINISHED; - spin_unlock(&fuse_lock); - if (req->background) { + if (!req->background) { + wake_up(&req->waitq); + fuse_put_request_locked(fc, req); + spin_unlock(&fuse_lock); + } else { + void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; + req->end = NULL; + spin_unlock(&fuse_lock); down_read(&fc->sbput_sem); if (fc->mounted) fuse_release_background(req); up_read(&fc->sbput_sem); + if (end) + end(fc, req); + else + fuse_put_request(fc, req); } - wake_up(&req->waitq); - if (end) - end(fc, req); - else - fuse_put_request(fc, req); } /* diff --git a/fs/inotify.c b/fs/inotify.c index 878ccca61213..3041503bde02 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -967,7 +967,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) mask_add = 1; /* don't let user-space set invalid bits: we don't want flags set */ - mask &= IN_ALL_EVENTS; + mask &= IN_ALL_EVENTS | IN_ONESHOT; if (unlikely(!mask)) { ret = -EINVAL; goto out; diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 429f4b263cf1..ca917973c2c0 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1308,6 +1308,7 @@ int journal_stop(handle_t *handle) transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int old_handle_count, err; + pid_t pid; J_ASSERT(transaction->t_updates > 0); J_ASSERT(journal_current_handle() == handle); @@ -1333,8 +1334,15 @@ int journal_stop(handle_t *handle) * It doesn't cost much - we're about to run a commit and sleep * on IO anyway. Speeds up many-threaded, many-dir operations * by 30x or more... + * + * But don't do this if this process was the most recent one to + * perform a synchronous write. We do this to detect the case where a + * single process is doing a stream of sync writes. No point in waiting + * for joiners in that case. */ - if (handle->h_sync) { + pid = current->pid; + if (handle->h_sync && journal->j_last_sync_writer != pid) { + journal->j_last_sync_writer = pid; do { old_handle_count = transaction->t_handle_count; schedule_timeout_uninterruptible(1); diff --git a/fs/namei.c b/fs/namei.c index 7ac9fb4acb2c..e28de846c591 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -790,7 +790,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) inode = nd->dentry->d_inode; if (nd->depth) - lookup_flags = LOOKUP_FOLLOW; + lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE); /* At this point we know we have a real path component. */ for(;;) { @@ -885,7 +885,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) last_with_slashes: lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; last_component: - nd->flags &= ~LOOKUP_CONTINUE; + /* Clear LOOKUP_CONTINUE iff it was previously unset */ + nd->flags &= lookup_flags | ~LOOKUP_CONTINUE; if (lookup_flags & LOOKUP_PARENT) goto lookup_parent; if (this.name[0] == '.') switch (this.len) { @@ -1069,6 +1070,8 @@ static int fastcall do_path_lookup(int dfd, const char *name, unsigned int flags, struct nameidata *nd) { int retval = 0; + int fput_needed; + struct file *file; nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags; @@ -1090,29 +1093,22 @@ static int fastcall do_path_lookup(int dfd, const char *name, nd->mnt = mntget(current->fs->pwdmnt); nd->dentry = dget(current->fs->pwd); } else { - struct file *file; - int fput_needed; struct dentry *dentry; file = fget_light(dfd, &fput_needed); - if (!file) { - retval = -EBADF; - goto out_fail; - } + retval = -EBADF; + if (!file) + goto unlock_fail; dentry = file->f_dentry; - if (!S_ISDIR(dentry->d_inode->i_mode)) { - retval = -ENOTDIR; - fput_light(file, fput_needed); - goto out_fail; - } + retval = -ENOTDIR; + if (!S_ISDIR(dentry->d_inode->i_mode)) + goto fput_unlock_fail; retval = file_permission(file, MAY_EXEC); - if (retval) { - fput_light(file, fput_needed); - goto out_fail; - } + if (retval) + goto fput_unlock_fail; nd->mnt = mntget(file->f_vfsmnt); nd->dentry = dget(dentry); @@ -1123,10 +1119,17 @@ static int fastcall do_path_lookup(int dfd, const char *name, current->total_link_count = 0; retval = link_path_walk(name, nd); out: - if (unlikely(current->audit_context - && nd && nd->dentry && nd->dentry->d_inode)) + if (likely(retval == 0)) { + if (unlikely(current->audit_context && nd && nd->dentry && + nd->dentry->d_inode)) audit_inode(name, nd->dentry->d_inode, flags); -out_fail: + } + return retval; + +fput_unlock_fail: + fput_light(file, fput_needed); +unlock_fail: + read_unlock(¤t->fs->lock); return retval; } diff --git a/fs/namespace.c b/fs/namespace.c index ce97becff461..058a44865beb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -494,7 +494,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) p->mnt_namespace = NULL; list_del_init(&p->mnt_child); if (p->mnt_parent != p) - mnt->mnt_mountpoint->d_mounted--; + p->mnt_mountpoint->d_mounted--; change_mnt_propagation(p, MS_PRIVATE); } } @@ -1325,27 +1325,17 @@ dput_out: return retval; } -int copy_namespace(int flags, struct task_struct *tsk) +/* + * Allocate a new namespace structure and populate it with contents + * copied from the namespace of the passed in task structure. + */ +struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) { struct namespace *namespace = tsk->namespace; struct namespace *new_ns; struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; - struct fs_struct *fs = tsk->fs; struct vfsmount *p, *q; - if (!namespace) - return 0; - - get_namespace(namespace); - - if (!(flags & CLONE_NEWNS)) - return 0; - - if (!capable(CAP_SYS_ADMIN)) { - put_namespace(namespace); - return -EPERM; - } - new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL); if (!new_ns) goto out; @@ -1396,8 +1386,6 @@ int copy_namespace(int flags, struct task_struct *tsk) } up_write(&namespace_sem); - tsk->namespace = new_ns; - if (rootmnt) mntput(rootmnt); if (pwdmnt) @@ -1405,12 +1393,40 @@ int copy_namespace(int flags, struct task_struct *tsk) if (altrootmnt) mntput(altrootmnt); - put_namespace(namespace); - return 0; +out: + return new_ns; +} + +int copy_namespace(int flags, struct task_struct *tsk) +{ + struct namespace *namespace = tsk->namespace; + struct namespace *new_ns; + int err = 0; + + if (!namespace) + return 0; + + get_namespace(namespace); + + if (!(flags & CLONE_NEWNS)) + return 0; + + if (!capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + + new_ns = dup_namespace(tsk, tsk->fs); + if (!new_ns) { + err = -ENOMEM; + goto out; + } + + tsk->namespace = new_ns; out: put_namespace(namespace); - return -ENOMEM; + return err; } asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index e897e00c2c9d..c0a754ecdee6 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -465,10 +465,11 @@ static int __init root_nfs_ports(void) "number from server, using default\n"); port = nfsd_port; } - nfs_port = htons(port); + nfs_port = port; dprintk("Root-NFS: Portmapper on server returned %d " "as nfsd port\n", port); } + nfs_port = htons(nfs_port); if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) { printk(KERN_ERR "Root-NFS: Unable to get mountd port " diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index a00fe8686293..6d63f1d9e5f5 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -195,10 +195,12 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open /* Openowner is now set, so sequence id will get bumped. Now we need * these checks before we do any creates: */ + status = nfserr_grace; if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) - return nfserr_grace; + goto out; + status = nfserr_no_grace; if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) - return nfserr_no_grace; + goto out; switch (open->op_claim_type) { case NFS4_OPEN_CLAIM_DELEGATE_CUR: diff --git a/fs/reiserfs/hashes.c b/fs/reiserfs/hashes.c index a3ec238fd9e0..e664ac16fad9 100644 --- a/fs/reiserfs/hashes.c +++ b/fs/reiserfs/hashes.c @@ -21,7 +21,6 @@ #include <linux/kernel.h> #include <linux/reiserfs_fs.h> #include <asm/types.h> -#include <asm/bug.h> #define DELTA 0x9E3779B9 #define FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */ diff --git a/fs/select.c b/fs/select.c index c0f02d36c60e..bc60a3e14ef3 100644 --- a/fs/select.c +++ b/fs/select.c @@ -510,9 +510,9 @@ asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, if (sig) { if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t)) - || __get_user(up, (sigset_t * __user *)sig) + || __get_user(up, (sigset_t __user * __user *)sig) || __get_user(sigsetsize, - (size_t * __user)(sig+sizeof(void *)))) + (size_t __user *)(sig+sizeof(void *)))) return -EFAULT; } diff --git a/fs/super.c b/fs/super.c index c177b92419c5..30294218fa63 100644 --- a/fs/super.c +++ b/fs/super.c @@ -247,8 +247,9 @@ void generic_shutdown_super(struct super_block *sb) /* Forget any remaining inodes */ if (invalidate_inodes(sb)) { - printk("VFS: Busy inodes after unmount. " - "Self-destruct in 5 seconds. Have a nice day...\n"); + printk("VFS: Busy inodes after unmount of %s. " + "Self-destruct in 5 seconds. Have a nice day...\n", + sb->s_id); } unlock_kernel(); diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 9892268e3005..8f2beec526cf 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -747,10 +747,11 @@ xfs_convert_page( struct backing_dev_info *bdi; bdi = inode->i_mapping->backing_dev_info; + wbc->nr_to_write--; if (bdi_write_congested(bdi)) { wbc->encountered_congestion = 1; done = 1; - } else if (--wbc->nr_to_write <= 0) { + } else if (wbc->nr_to_write <= 0) { done = 1; } } diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index eda7919b70a1..d7f6f2d8ac8e 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -673,6 +673,8 @@ linvfs_setattr( if (ia_valid & ATTR_ATIME) { vattr.va_mask |= XFS_AT_ATIME; vattr.va_atime = attr->ia_atime; + if (ia_valid & ATTR_ATIME_SET) + inode->i_atime = attr->ia_atime; } if (ia_valid & ATTR_MTIME) { vattr.va_mask |= XFS_AT_MTIME; |