diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-31 09:25:20 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-31 09:25:20 -0800 |
commit | 19e7b5f99474107e8d0b4b3e4652fa19ddb87efc (patch) | |
tree | 49f15b76c07b4c90d6fbd17b49d69017c81a4b58 /fs | |
parent | 26064ea409b4d4acb05903a36f3fe2fdccb3d8aa (diff) | |
parent | ce4c253573ad184603e0fa77876ba155b0cde46d (diff) | |
download | lwn-19e7b5f99474107e8d0b4b3e4652fa19ddb87efc.tar.gz lwn-19e7b5f99474107e8d0b4b3e4652fa19ddb87efc.zip |
Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc vfs updates from Al Viro:
"All kinds of misc stuff, without any unifying topic, from various
people.
Neil's d_anon patch, several bugfixes, introduction of kvmalloc
analogue of kmemdup_user(), extending bitfield.h to deal with
fixed-endians, assorted cleanups all over the place..."
* 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (28 commits)
alpha: osf_sys.c: use timespec64 where appropriate
alpha: osf_sys.c: fix put_tv32 regression
jffs2: Fix use-after-free bug in jffs2_iget()'s error handling path
dcache: delete unused d_hash_mask
dcache: subtract d_hash_shift from 32 in advance
fs/buffer.c: fold init_buffer() into init_page_buffers()
fs: fold __inode_permission() into inode_permission()
fs: add RWF_APPEND
sctp: use vmemdup_user() rather than badly open-coding memdup_user()
snd_ctl_elem_init_enum_names(): switch to vmemdup_user()
replace_user_tlv(): switch to vmemdup_user()
new primitive: vmemdup_user()
memdup_user(): switch to GFP_USER
eventfd: fold eventfd_ctx_get() into eventfd_ctx_fileget()
eventfd: fold eventfd_ctx_read() into eventfd_read()
eventfd: convert to use anon_inode_getfd()
nfs4file: get rid of pointless include of btrfs.h
uvc_v4l2: clean copyin/copyout up
vme_user: don't use __copy_..._user()
usx2y: don't bother with memdup_user() for 16-byte structure
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/buffer.c | 10 | ||||
-rw-r--r-- | fs/dcache.c | 32 | ||||
-rw-r--r-- | fs/eventfd.c | 127 | ||||
-rw-r--r-- | fs/file.c | 5 | ||||
-rw-r--r-- | fs/file_table.c | 1 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 1 | ||||
-rw-r--r-- | fs/namei.c | 71 | ||||
-rw-r--r-- | fs/nfs/nfs4file.c | 1 | ||||
-rw-r--r-- | fs/super.c | 2 |
9 files changed, 74 insertions, 176 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 8b26295a56fe..9a73924db22f 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -53,13 +53,6 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers) -void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private) -{ - bh->b_end_io = handler; - bh->b_private = private; -} -EXPORT_SYMBOL(init_buffer); - inline void touch_buffer(struct buffer_head *bh) { trace_block_touch_buffer(bh); @@ -922,7 +915,8 @@ init_page_buffers(struct page *page, struct block_device *bdev, do { if (!buffer_mapped(bh)) { - init_buffer(bh, NULL, NULL); + bh->b_end_io = NULL; + bh->b_private = NULL; bh->b_bdev = bdev; bh->b_blocknr = block; if (uptodate) diff --git a/fs/dcache.c b/fs/dcache.c index 379dce86f001..c6d996ee2d61 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -32,7 +32,6 @@ #include <linux/swap.h> #include <linux/bootmem.h> #include <linux/fs_struct.h> -#include <linux/hardirq.h> #include <linux/bit_spinlock.h> #include <linux/rculist_bl.h> #include <linux/prefetch.h> @@ -49,8 +48,8 @@ * - i_dentry, d_u.d_alias, d_inode of aliases * dcache_hash_bucket lock protects: * - the dcache hash table - * s_anon bl list spinlock protects: - * - the s_anon list (see __d_drop) + * s_roots bl list spinlock protects: + * - the s_roots list (see __d_drop) * dentry->d_sb->s_dentry_lru_lock protects: * - the dcache lru lists and counters * d_lock protects: @@ -68,7 +67,7 @@ * dentry->d_lock * dentry->d_sb->s_dentry_lru_lock * dcache_hash_bucket lock - * s_anon lock + * s_roots lock * * If there is an ancestor relationship: * dentry->d_parent->...->d_parent->d_lock @@ -104,14 +103,13 @@ EXPORT_SYMBOL(slash_name); * information, yet avoid using a prime hash-size or similar. */ -static unsigned int d_hash_mask __read_mostly; static unsigned int d_hash_shift __read_mostly; static struct hlist_bl_head *dentry_hashtable __read_mostly; static inline struct hlist_bl_head *d_hash(unsigned int hash) { - return dentry_hashtable + (hash >> (32 - d_hash_shift)); + return dentry_hashtable + (hash >> d_hash_shift); } #define IN_LOOKUP_SHIFT 10 @@ -477,10 +475,10 @@ void __d_drop(struct dentry *dentry) /* * Hashed dentries are normally on the dentry hashtable, * with the exception of those newly allocated by - * d_obtain_alias, which are always IS_ROOT: + * d_obtain_root, which are always IS_ROOT: */ if (unlikely(IS_ROOT(dentry))) - b = &dentry->d_sb->s_anon; + b = &dentry->d_sb->s_roots; else b = d_hash(dentry->d_name.hash); @@ -1500,8 +1498,8 @@ void shrink_dcache_for_umount(struct super_block *sb) sb->s_root = NULL; do_one_tree(dentry); - while (!hlist_bl_empty(&sb->s_anon)) { - dentry = dget(hlist_bl_entry(hlist_bl_first(&sb->s_anon), struct dentry, d_hash)); + while (!hlist_bl_empty(&sb->s_roots)) { + dentry = dget(hlist_bl_entry(hlist_bl_first(&sb->s_roots), struct dentry, d_hash)); do_one_tree(dentry); } } @@ -1964,9 +1962,11 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected) spin_lock(&tmp->d_lock); __d_set_inode_and_type(tmp, inode, add_flags); hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry); - hlist_bl_lock(&tmp->d_sb->s_anon); - hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); - hlist_bl_unlock(&tmp->d_sb->s_anon); + if (!disconnected) { + hlist_bl_lock(&tmp->d_sb->s_roots); + hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_roots); + hlist_bl_unlock(&tmp->d_sb->s_roots); + } spin_unlock(&tmp->d_lock); spin_unlock(&inode->i_lock); @@ -3585,9 +3585,10 @@ static void __init dcache_init_early(void) 13, HASH_EARLY | HASH_ZERO, &d_hash_shift, - &d_hash_mask, + NULL, 0, 0); + d_hash_shift = 32 - d_hash_shift; } static void __init dcache_init(void) @@ -3611,9 +3612,10 @@ static void __init dcache_init(void) 13, HASH_ZERO, &d_hash_shift, - &d_hash_mask, + NULL, 0, 0); + d_hash_shift = 32 - d_hash_shift; } /* SLAB cache for __getname() consumers */ diff --git a/fs/eventfd.c b/fs/eventfd.c index 6318a9b57e53..04fd824142a1 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c @@ -80,24 +80,11 @@ static void eventfd_free(struct kref *kref) } /** - * eventfd_ctx_get - Acquires a reference to the internal eventfd context. - * @ctx: [in] Pointer to the eventfd context. - * - * Returns: In case of success, returns a pointer to the eventfd context. - */ -struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx) -{ - kref_get(&ctx->kref); - return ctx; -} -EXPORT_SYMBOL_GPL(eventfd_ctx_get); - -/** * eventfd_ctx_put - Releases a reference to the internal eventfd context. * @ctx: [in] Pointer to eventfd context. * * The eventfd context reference must have been previously acquired either - * with eventfd_ctx_get() or eventfd_ctx_fdget(). + * with eventfd_ctx_fdget() or eventfd_ctx_fileget(). */ void eventfd_ctx_put(struct eventfd_ctx *ctx) { @@ -207,36 +194,27 @@ int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_entry_t *w } EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue); -/** - * eventfd_ctx_read - Reads the eventfd counter or wait if it is zero. - * @ctx: [in] Pointer to eventfd context. - * @no_wait: [in] Different from zero if the operation should not block. - * @cnt: [out] Pointer to the 64-bit counter value. - * - * Returns %0 if successful, or the following error codes: - * - * - -EAGAIN : The operation would have blocked but @no_wait was non-zero. - * - -ERESTARTSYS : A signal interrupted the wait operation. - * - * If @no_wait is zero, the function might sleep until the eventfd internal - * counter becomes greater than zero. - */ -ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt) +static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) { + struct eventfd_ctx *ctx = file->private_data; ssize_t res; + __u64 ucnt = 0; DECLARE_WAITQUEUE(wait, current); + if (count < sizeof(ucnt)) + return -EINVAL; + spin_lock_irq(&ctx->wqh.lock); - *cnt = 0; res = -EAGAIN; if (ctx->count > 0) - res = 0; - else if (!no_wait) { + res = sizeof(ucnt); + else if (!(file->f_flags & O_NONBLOCK)) { __add_wait_queue(&ctx->wqh, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (ctx->count > 0) { - res = 0; + res = sizeof(ucnt); break; } if (signal_pending(current)) { @@ -250,31 +228,17 @@ ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt) __remove_wait_queue(&ctx->wqh, &wait); __set_current_state(TASK_RUNNING); } - if (likely(res == 0)) { - eventfd_ctx_do_read(ctx, cnt); + if (likely(res > 0)) { + eventfd_ctx_do_read(ctx, &ucnt); if (waitqueue_active(&ctx->wqh)) wake_up_locked_poll(&ctx->wqh, POLLOUT); } spin_unlock_irq(&ctx->wqh.lock); - return res; -} -EXPORT_SYMBOL_GPL(eventfd_ctx_read); - -static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct eventfd_ctx *ctx = file->private_data; - ssize_t res; - __u64 cnt; - - if (count < sizeof(cnt)) - return -EINVAL; - res = eventfd_ctx_read(ctx, file->f_flags & O_NONBLOCK, &cnt); - if (res < 0) - return res; + if (res > 0 && put_user(ucnt, (__u64 __user *)buf)) + return -EFAULT; - return put_user(cnt, (__u64 __user *) buf) ? -EFAULT : sizeof(cnt); + return res; } static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count, @@ -405,79 +369,44 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_fdget); */ struct eventfd_ctx *eventfd_ctx_fileget(struct file *file) { + struct eventfd_ctx *ctx; + if (file->f_op != &eventfd_fops) return ERR_PTR(-EINVAL); - return eventfd_ctx_get(file->private_data); + ctx = file->private_data; + kref_get(&ctx->kref); + return ctx; } EXPORT_SYMBOL_GPL(eventfd_ctx_fileget); -/** - * eventfd_file_create - Creates an eventfd file pointer. - * @count: Initial eventfd counter value. - * @flags: Flags for the eventfd file. - * - * This function creates an eventfd file pointer, w/out installing it into - * the fd table. This is useful when the eventfd file is used during the - * initialization of data structures that require extra setup after the eventfd - * creation. So the eventfd creation is split into the file pointer creation - * phase, and the file descriptor installation phase. - * In this way races with userspace closing the newly installed file descriptor - * can be avoided. - * Returns an eventfd file pointer, or a proper error pointer. - */ -struct file *eventfd_file_create(unsigned int count, int flags) +SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) { - struct file *file; struct eventfd_ctx *ctx; + int fd; /* Check the EFD_* constants for consistency. */ BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK); if (flags & ~EFD_FLAGS_SET) - return ERR_PTR(-EINVAL); + return -EINVAL; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) - return ERR_PTR(-ENOMEM); + return -ENOMEM; kref_init(&ctx->kref); init_waitqueue_head(&ctx->wqh); ctx->count = count; ctx->flags = flags; - file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx, - O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS)); - if (IS_ERR(file)) + fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx, + O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS)); + if (fd < 0) eventfd_free_ctx(ctx); - return file; -} - -SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) -{ - int fd, error; - struct file *file; - - error = get_unused_fd_flags(flags & EFD_SHARED_FCNTL_FLAGS); - if (error < 0) - return error; - fd = error; - - file = eventfd_file_create(count, flags); - if (IS_ERR(file)) { - error = PTR_ERR(file); - goto err_put_unused_fd; - } - fd_install(fd, file); - return fd; - -err_put_unused_fd: - put_unused_fd(fd); - - return error; } SYSCALL_DEFINE1(eventfd, unsigned int, count) diff --git a/fs/file.c b/fs/file.c index fc0eeb812e2c..42f0db4bd0fb 100644 --- a/fs/file.c +++ b/fs/file.c @@ -11,18 +11,13 @@ #include <linux/export.h> #include <linux/fs.h> #include <linux/mm.h> -#include <linux/mmzone.h> -#include <linux/time.h> #include <linux/sched/signal.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/file.h> #include <linux/fdtable.h> #include <linux/bitops.h> -#include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/rcupdate.h> -#include <linux/workqueue.h> unsigned int sysctl_nr_open __read_mostly = 1024*1024; unsigned int sysctl_nr_open_min = BITS_PER_LONG; diff --git a/fs/file_table.c b/fs/file_table.c index 2dc9f38bd195..7ec0b3e5f05d 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -23,7 +23,6 @@ #include <linux/sysctl.h> #include <linux/percpu_counter.h> #include <linux/percpu.h> -#include <linux/hardirq.h> #include <linux/task_work.h> #include <linux/ima.h> #include <linux/swap.h> diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index d8c274d39ddb..eab04eca95a3 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -362,7 +362,6 @@ error_io: ret = -EIO; error: mutex_unlock(&f->sem); - jffs2_do_clear_inode(c, f); iget_failed(inode); return ERR_PTR(ret); } diff --git a/fs/namei.c b/fs/namei.c index 7c221fb0836b..921ae32dbc80 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -391,50 +391,6 @@ static inline int do_inode_permission(struct inode *inode, int mask) } /** - * __inode_permission - Check for access rights to a given inode - * @inode: Inode to check permission on - * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) - * - * Check for read/write/execute permissions on an inode. - * - * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. - * - * This does not check for a read-only file system. You probably want - * inode_permission(). - */ -int __inode_permission(struct inode *inode, int mask) -{ - int retval; - - if (unlikely(mask & MAY_WRITE)) { - /* - * Nobody gets write access to an immutable file. - */ - if (IS_IMMUTABLE(inode)) - return -EPERM; - - /* - * Updating mtime will likely cause i_uid and i_gid to be - * written back improperly if their true value is unknown - * to the vfs. - */ - if (HAS_UNMAPPED_ID(inode)) - return -EACCES; - } - - retval = do_inode_permission(inode, mask); - if (retval) - return retval; - - retval = devcgroup_inode_permission(inode, mask); - if (retval) - return retval; - - return security_inode_permission(inode, mask); -} -EXPORT_SYMBOL(__inode_permission); - -/** * sb_permission - Check superblock-level permissions * @sb: Superblock of inode to check permission on * @inode: Inode to check permission on @@ -472,7 +428,32 @@ int inode_permission(struct inode *inode, int mask) retval = sb_permission(inode->i_sb, inode, mask); if (retval) return retval; - return __inode_permission(inode, mask); + + if (unlikely(mask & MAY_WRITE)) { + /* + * Nobody gets write access to an immutable file. + */ + if (IS_IMMUTABLE(inode)) + return -EPERM; + + /* + * Updating mtime will likely cause i_uid and i_gid to be + * written back improperly if their true value is unknown + * to the vfs. + */ + if (HAS_UNMAPPED_ID(inode)) + return -EACCES; + } + + retval = do_inode_permission(inode, mask); + if (retval) + return retval; + + retval = devcgroup_inode_permission(inode, mask); + if (retval) + return retval; + + return security_inode_permission(inode, mask); } EXPORT_SYMBOL(inode_permission); diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 626d1382002e..6b3b372b59b9 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -8,7 +8,6 @@ #include <linux/file.h> #include <linux/falloc.h> #include <linux/nfs_fs.h> -#include <uapi/linux/btrfs.h> /* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */ #include "delegation.h" #include "internal.h" #include "iostat.h" diff --git a/fs/super.c b/fs/super.c index 06bd25d90ba5..672538ca9831 100644 --- a/fs/super.c +++ b/fs/super.c @@ -225,7 +225,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, if (s->s_user_ns != &init_user_ns) s->s_iflags |= SB_I_NODEV; INIT_HLIST_NODE(&s->s_instances); - INIT_HLIST_BL_HEAD(&s->s_anon); + INIT_HLIST_BL_HEAD(&s->s_roots); mutex_init(&s->s_sync_lock); INIT_LIST_HEAD(&s->s_inodes); spin_lock_init(&s->s_inode_list_lock); |