From bb458c644a59dbba3a1fe59b27106c5e68e1c4bd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 13 Jul 2013 13:26:37 +0400 Subject: Safer ABI for O_TMPFILE [suggested by Rasmus Villemoes] make O_DIRECTORY | O_RDWR part of O_TMPFILE; that will fail on old kernels in a lot more cases than what I came up with. And make sure O_CREAT doesn't get there... Signed-off-by: Al Viro --- fs/namei.c | 2 +- fs/open.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/namei.c b/fs/namei.c index b2beee7a733f..8b61d103a8a7 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2977,7 +2977,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, file->f_flags = op->open_flag; - if (unlikely(file->f_flags & O_TMPFILE)) { + if (unlikely(file->f_flags & __O_TMPFILE)) { error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened); goto out; } diff --git a/fs/open.c b/fs/open.c index fca72c4d3f17..9156cb050d08 100644 --- a/fs/open.c +++ b/fs/open.c @@ -840,8 +840,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o if (flags & __O_SYNC) flags |= O_DSYNC; - if (flags & O_TMPFILE) { - if (!(flags & O_CREAT)) + if (flags & __O_TMPFILE) { + if ((flags & O_TMPFILE_MASK) != O_TMPFILE) return -EINVAL; acc_mode = MAY_OPEN | ACC_MODE(flags); } else if (flags & O_PATH) { -- cgit v1.2.3 From 64372501e2af9b11e2ffd1ff79345dc4b1abe539 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 8 Jul 2013 14:24:15 -0700 Subject: fs/file_table.c:fput(): add comment A missed update to "fput: task_work_add() can fail if the caller has passed exit_task_work()". Cc: "Eric W. Biederman" Cc: Al Viro Cc: Andrey Vagin Cc: David Howells Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Al Viro --- fs/file_table.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'fs') diff --git a/fs/file_table.c b/fs/file_table.c index 08e719b884ca..b9a77ad08b4d 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -313,6 +313,12 @@ void fput(struct file *file) init_task_work(&file->f_u.fu_rcuhead, ____fput); if (!task_work_add(task, &file->f_u.fu_rcuhead, true)) return; + /* + * After this task has run exit_task_work(), + * task_work_add() will fail. free_ipc_ns()-> + * shm_destroy() can do this. Fall through to delayed + * fput to avoid leaking *file. + */ } spin_lock_irqsave(&delayed_fput_lock, flags); list_add(&file->f_u.fu_list, &delayed_fput_list); -- cgit v1.2.3 From 4f5e65a1cc90bbb15b9f6cdc362922af1bcc155a Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 8 Jul 2013 14:24:16 -0700 Subject: fput: turn "list_head delayed_fput_list" into llist_head fput() and delayed_fput() can use llist and avoid the locking. This is unlikely path, it is not that this change can improve the performance, but this way the code looks simpler. Signed-off-by: Oleg Nesterov Suggested-by: Andrew Morton Cc: Al Viro Cc: Andrey Vagin Cc: "Eric W. Biederman" Cc: David Howells Cc: Huang Ying Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Al Viro --- fs/file_table.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/file_table.c b/fs/file_table.c index b9a77ad08b4d..b44e4c559786 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -265,18 +265,15 @@ static void __fput(struct file *file) mntput(mnt); } -static DEFINE_SPINLOCK(delayed_fput_lock); -static LIST_HEAD(delayed_fput_list); +static LLIST_HEAD(delayed_fput_list); static void delayed_fput(struct work_struct *unused) { - LIST_HEAD(head); - spin_lock_irq(&delayed_fput_lock); - list_splice_init(&delayed_fput_list, &head); - spin_unlock_irq(&delayed_fput_lock); - while (!list_empty(&head)) { - struct file *f = list_first_entry(&head, struct file, f_u.fu_list); - list_del_init(&f->f_u.fu_list); - __fput(f); + struct llist_node *node = llist_del_all(&delayed_fput_list); + struct llist_node *next; + + for (; node; node = next) { + next = llist_next(node); + __fput(llist_entry(node, struct file, f_u.fu_llist)); } } @@ -306,7 +303,6 @@ void fput(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { struct task_struct *task = current; - unsigned long flags; file_sb_list_del(file); if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { @@ -320,10 +316,9 @@ void fput(struct file *file) * fput to avoid leaking *file. */ } - spin_lock_irqsave(&delayed_fput_lock, flags); - list_add(&file->f_u.fu_list, &delayed_fput_list); - schedule_work(&delayed_fput_work); - spin_unlock_irqrestore(&delayed_fput_lock, flags); + + if (llist_add(&file->f_u.fu_llist, &delayed_fput_list)) + schedule_work(&delayed_fput_work); } } -- cgit v1.2.3 From ec193cf5af0a8dc35c3975ca0aca8e7b7f3e3464 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Jul 2013 17:16:52 +0400 Subject: configfs: don't open-code d_alloc_name() Signed-off-by: Al Viro --- fs/configfs/dir.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 64e5323cbbb0..437b0d535b33 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -660,19 +660,15 @@ static int create_default_group(struct config_group *parent_group, struct config_group *group) { int ret; - struct qstr name; struct configfs_dirent *sd; /* We trust the caller holds a reference to parent */ struct dentry *child, *parent = parent_group->cg_item.ci_dentry; if (!group->cg_item.ci_name) group->cg_item.ci_name = group->cg_item.ci_namebuf; - name.name = group->cg_item.ci_name; - name.len = strlen(name.name); - name.hash = full_name_hash(name.name, name.len); ret = -ENOMEM; - child = d_alloc(parent, &name); + child = d_alloc_name(parent, group->cg_item.ci_name); if (child) { d_add(child, NULL); @@ -1650,7 +1646,6 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) { int err; struct config_group *group = &subsys->su_group; - struct qstr name; struct dentry *dentry; struct dentry *root; struct configfs_dirent *sd; @@ -1667,12 +1662,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); - name.name = group->cg_item.ci_name; - name.len = strlen(name.name); - name.hash = full_name_hash(name.name, name.len); - err = -ENOMEM; - dentry = d_alloc(root, &name); + dentry = d_alloc_name(root, group->cg_item.ci_name); if (dentry) { d_add(dentry, NULL); -- cgit v1.2.3 From 74931da7a6d341c137f1564a47f36fda68ad21e6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Jul 2013 17:43:25 +0400 Subject: make simple_lookup() usable for filesystems that set ->s_d_op Signed-off-by: Al Viro --- fs/libfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/libfs.c b/fs/libfs.c index c3a0837fb861..3a3a9b53bf5a 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -61,7 +61,8 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); - d_set_d_op(dentry, &simple_dentry_operations); + if (!dentry->d_sb->s_d_op) + d_set_d_op(dentry, &simple_dentry_operations); d_add(dentry, NULL); return NULL; } -- cgit v1.2.3 From 6e8cd2cb46e3c772871c86de2ffb718f911f9b59 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Jul 2013 17:48:35 +0400 Subject: efivarfs: we can use simple_lookup() now Signed-off-by: Al Viro --- fs/efivarfs/inode.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index 7e787fb90293..07ab49745e31 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -155,20 +155,8 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) return 0; }; -/* - * Handle negative dentry. - */ -static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry, - unsigned int flags) -{ - if (dentry->d_name.len > NAME_MAX) - return ERR_PTR(-ENAMETOOLONG); - d_add(dentry, NULL); - return NULL; -} - const struct inode_operations efivarfs_dir_inode_operations = { - .lookup = efivarfs_lookup, + .lookup = simple_lookup, .unlink = efivarfs_unlink, .create = efivarfs_create, }; -- cgit v1.2.3