diff options
Diffstat (limited to 'fs/fsopen.c')
| -rw-r--r-- | fs/fsopen.c | 103 |
1 files changed, 49 insertions, 54 deletions
diff --git a/fs/fsopen.c b/fs/fsopen.c index 6593ae518115..f645c99204eb 100644 --- a/fs/fsopen.c +++ b/fs/fsopen.c @@ -18,50 +18,56 @@ #include "internal.h" #include "mount.h" +static inline const char *fetch_message_locked(struct fc_log *log, size_t len, + bool *need_free) +{ + const char *p; + int index; + + if (unlikely(log->head == log->tail)) + return ERR_PTR(-ENODATA); + + index = log->tail & (ARRAY_SIZE(log->buffer) - 1); + p = log->buffer[index]; + if (unlikely(strlen(p) > len)) + return ERR_PTR(-EMSGSIZE); + + log->buffer[index] = NULL; + *need_free = log->need_free & (1 << index); + log->need_free &= ~(1 << index); + log->tail++; + + return p; +} + /* * Allow the user to read back any error, warning or informational messages. + * Only one message is returned for each read(2) call. */ static ssize_t fscontext_read(struct file *file, char __user *_buf, size_t len, loff_t *pos) { struct fs_context *fc = file->private_data; - struct fc_log *log = fc->log.log; - unsigned int logsize = ARRAY_SIZE(log->buffer); - ssize_t ret; - char *p; + ssize_t err; + const char *p __free(kfree) = NULL, *message; bool need_free; - int index, n; - - ret = mutex_lock_interruptible(&fc->uapi_mutex); - if (ret < 0) - return ret; + int n; - if (log->head == log->tail) { - mutex_unlock(&fc->uapi_mutex); - return -ENODATA; - } - - index = log->tail & (logsize - 1); - p = log->buffer[index]; - need_free = log->need_free & (1 << index); - log->buffer[index] = NULL; - log->need_free &= ~(1 << index); - log->tail++; + err = mutex_lock_interruptible(&fc->uapi_mutex); + if (err < 0) + return err; + message = fetch_message_locked(fc->log.log, len, &need_free); mutex_unlock(&fc->uapi_mutex); + if (IS_ERR(message)) + return PTR_ERR(message); - ret = -EMSGSIZE; - n = strlen(p); - if (n > len) - goto err_free; - ret = -EFAULT; - if (copy_to_user(_buf, p, n) != 0) - goto err_free; - ret = n; - -err_free: if (need_free) - kfree(p); - return ret; + p = message; + + n = strlen(message); + if (copy_to_user(_buf, message, n)) + return -EFAULT; + return n; } static int fscontext_release(struct inode *inode, struct file *file) @@ -78,7 +84,6 @@ static int fscontext_release(struct inode *inode, struct file *file) const struct file_operations fscontext_fops = { .read = fscontext_read, .release = fscontext_release, - .llseek = no_llseek, }; /* @@ -220,10 +225,6 @@ static int vfs_cmd_create(struct fs_context *fc, bool exclusive) if (!mount_capable(fc)) return -EPERM; - /* require the new mount api */ - if (exclusive && fc->ops == &legacy_fs_context_ops) - return -EOPNOTSUPP; - fc->phase = FS_CONTEXT_CREATING; fc->exclusive = exclusive; @@ -354,7 +355,6 @@ SYSCALL_DEFINE5(fsconfig, int, aux) { struct fs_context *fc; - struct fd f; int ret; int lookup_flags = 0; @@ -397,31 +397,28 @@ SYSCALL_DEFINE5(fsconfig, return -EOPNOTSUPP; } - f = fdget(fd); - if (!f.file) + CLASS(fd, f)(fd); + if (fd_empty(f)) return -EBADF; - ret = -EINVAL; - if (f.file->f_op != &fscontext_fops) - goto out_f; + if (fd_file(f)->f_op != &fscontext_fops) + return -EINVAL; - fc = f.file->private_data; + fc = fd_file(f)->private_data; if (fc->ops == &legacy_fs_context_ops) { switch (cmd) { case FSCONFIG_SET_BINARY: case FSCONFIG_SET_PATH: case FSCONFIG_SET_PATH_EMPTY: case FSCONFIG_SET_FD: - ret = -EOPNOTSUPP; - goto out_f; + case FSCONFIG_CMD_CREATE_EXCL: + return -EOPNOTSUPP; } } if (_key) { param.key = strndup_user(_key, 256); - if (IS_ERR(param.key)) { - ret = PTR_ERR(param.key); - goto out_f; - } + if (IS_ERR(param.key)) + return PTR_ERR(param.key); } switch (cmd) { @@ -451,7 +448,7 @@ SYSCALL_DEFINE5(fsconfig, fallthrough; case FSCONFIG_SET_PATH: param.type = fs_value_is_filename; - param.name = getname_flags(_value, lookup_flags, NULL); + param.name = getname_flags(_value, lookup_flags); if (IS_ERR(param.name)) { ret = PTR_ERR(param.name); goto out_key; @@ -462,7 +459,7 @@ SYSCALL_DEFINE5(fsconfig, case FSCONFIG_SET_FD: param.type = fs_value_is_file; ret = -EBADF; - param.file = fget(aux); + param.file = fget_raw(aux); if (!param.file) goto out_key; param.dirfd = aux; @@ -500,7 +497,5 @@ SYSCALL_DEFINE5(fsconfig, } out_key: kfree(param.key); -out_f: - fdput(f); return ret; } |
