summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/compat_ioctl.c8
-rw-r--r--fs/debugfs/file.c6
-rw-r--r--fs/file.c3
-rw-r--r--fs/fuse/dev.c40
-rw-r--r--fs/inotify.c2
-rw-r--r--fs/jbd/transaction.c10
-rw-r--r--fs/namei.c43
-rw-r--r--fs/namespace.c58
-rw-r--r--fs/nfs/nfsroot.c3
-rw-r--r--fs/nfsd/nfs4proc.c6
-rw-r--r--fs/reiserfs/hashes.c1
-rw-r--r--fs/select.c4
-rw-r--r--fs/super.c5
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c2
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(&current->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;