summaryrefslogtreecommitdiff
path: root/fs/fsopen.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fsopen.c')
-rw-r--r--fs/fsopen.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/fs/fsopen.c b/fs/fsopen.c
index d256f1ac9ff1..5fce6347de7a 100644
--- a/fs/fsopen.c
+++ b/fs/fsopen.c
@@ -20,6 +20,52 @@
#include <uapi/linux/mount.h>
#include "mount.h"
+/*
+ * Allow the user to read back any error, warning or informational messages.
+ */
+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;
+ unsigned int logsize = ARRAY_SIZE(log->buffer);
+ ssize_t ret;
+ char *p;
+ bool need_free;
+ int index, n;
+
+ ret = mutex_lock_interruptible(&fc->uapi_mutex);
+ if (ret < 0)
+ return ret;
+
+ 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++;
+ mutex_unlock(&fc->uapi_mutex);
+
+ 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;
+}
+
static int fscontext_release(struct inode *inode, struct file *file)
{
struct fs_context *fc = file->private_data;
@@ -32,6 +78,7 @@ 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,
};
@@ -50,6 +97,16 @@ static int fscontext_create_fd(struct fs_context *fc, unsigned int o_flags)
return fd;
}
+static int fscontext_alloc_log(struct fs_context *fc)
+{
+ fc->log = kzalloc(sizeof(*fc->log), GFP_KERNEL);
+ if (!fc->log)
+ return -ENOMEM;
+ refcount_set(&fc->log->usage, 1);
+ fc->log->owner = fc->fs_type->owner;
+ return 0;
+}
+
/*
* Open a filesystem by name so that it can be configured for mounting.
*
@@ -62,6 +119,7 @@ SYSCALL_DEFINE2(fsopen, const char __user *, _fs_name, unsigned int, flags)
struct file_system_type *fs_type;
struct fs_context *fc;
const char *fs_name;
+ int ret;
if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN))
return -EPERM;
@@ -84,5 +142,14 @@ SYSCALL_DEFINE2(fsopen, const char __user *, _fs_name, unsigned int, flags)
return PTR_ERR(fc);
fc->phase = FS_CONTEXT_CREATE_PARAMS;
+
+ ret = fscontext_alloc_log(fc);
+ if (ret < 0)
+ goto err_fc;
+
return fscontext_create_fd(fc, flags & FSOPEN_CLOEXEC ? O_CLOEXEC : 0);
+
+err_fc:
+ put_fs_context(fc);
+ return ret;
}