b4d0d230ccfb5 (Thomas Gleixner 2019-05-20 19:08:01 +0200 1) // SPDX-License-Identifier: GPL-2.0-or-later
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 2) /* Provide a way to create a superblock configuration context within the kernel
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 3) * that allows a superblock to be set up prior to mounting.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 4) *
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 5) * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 6) * Written by David Howells (dhowells@redhat.com)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 7) */
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 8)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 9) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 10) #include <linux/module.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 11) #include <linux/fs_context.h>
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 12) #include <linux/fs_parser.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 13) #include <linux/fs.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 14) #include <linux/mount.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 15) #include <linux/nsproxy.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 16) #include <linux/slab.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 17) #include <linux/magic.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 18) #include <linux/security.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 19) #include <linux/mnt_namespace.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 20) #include <linux/pid_namespace.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 21) #include <linux/user_namespace.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 22) #include <net/net_namespace.h>
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 23) #include <asm/sections.h>
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 24) #include "mount.h"
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 25) #include "internal.h"
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 26)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 27) enum legacy_fs_param {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 28) LEGACY_FS_UNSET_PARAMS,
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 29) LEGACY_FS_MONOLITHIC_PARAMS,
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 30) LEGACY_FS_INDIVIDUAL_PARAMS,
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 31) };
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 32)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 33) struct legacy_fs_context {
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 34) char *legacy_data; /* Data page for legacy filesystems */
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 35) size_t data_size;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 36) enum legacy_fs_param param_type;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 37) };
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 38)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 39) static int legacy_init_fs_context(struct fs_context *fc);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 40)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 41) static const struct constant_table common_set_sb_flag[] = {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 42) { "dirsync", SB_DIRSYNC },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 43) { "lazytime", SB_LAZYTIME },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 44) { "mand", SB_MANDLOCK },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 45) { "ro", SB_RDONLY },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 46) { "sync", SB_SYNCHRONOUS },
34264ae3fa224 (Al Viro 2019-12-16 13:45:41 -0500 47) { },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 48) };
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 49)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 50) static const struct constant_table common_clear_sb_flag[] = {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 51) { "async", SB_SYNCHRONOUS },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 52) { "nolazytime", SB_LAZYTIME },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 53) { "nomand", SB_MANDLOCK },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 54) { "rw", SB_RDONLY },
34264ae3fa224 (Al Viro 2019-12-16 13:45:41 -0500 55) { },
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 56) };
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 57)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 58) /*
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 59) * Check for a common mount option that manipulates s_flags.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 60) */
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 61) static int vfs_parse_sb_flag(struct fs_context *fc, const char *key)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 62) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 63) unsigned int token;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 64)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 65) token = lookup_constant(common_set_sb_flag, key, 0);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 66) if (token) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 67) fc->sb_flags |= token;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 68) fc->sb_flags_mask |= token;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 69) return 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 70) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 71)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 72) token = lookup_constant(common_clear_sb_flag, key, 0);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 73) if (token) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 74) fc->sb_flags &= ~token;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 75) fc->sb_flags_mask |= token;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 76) return 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 77) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 78)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 79) return -ENOPARAM;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 80) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 81)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 82) /**
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 83) * vfs_parse_fs_param - Add a single parameter to a superblock config
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 84) * @fc: The filesystem context to modify
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 85) * @param: The parameter
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 86) *
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 87) * A single mount option in string form is applied to the filesystem context
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 88) * being set up. Certain standard options (for example "ro") are translated
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 89) * into flag bits without going to the filesystem. The active security module
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 90) * is allowed to observe and poach options. Any other options are passed over
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 91) * to the filesystem to parse.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 92) *
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 93) * This may be called multiple times for a context.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 94) *
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 95) * Returns 0 on success and a negative error code on failure. In the event of
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 96) * failure, supplementary error information may have been set.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 97) */
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 98) int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 99) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 100) int ret;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 101)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 102) if (!param->key)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 103) return invalf(fc, "Unnamed parameter\n");
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 104)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 105) ret = vfs_parse_sb_flag(fc, param->key);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 106) if (ret != -ENOPARAM)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 107) return ret;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 108)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 109) ret = security_fs_context_parse_param(fc, param);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 110) if (ret != -ENOPARAM)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 111) /* Param belongs to the LSM or is disallowed by the LSM; so
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 112) * don't pass to the FS.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 113) */
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 114) return ret;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 115)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 116) if (fc->ops->parse_param) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 117) ret = fc->ops->parse_param(fc, param);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 118) if (ret != -ENOPARAM)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 119) return ret;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 120) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 121)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 122) /* If the filesystem doesn't take any arguments, give it the
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 123) * default handling of source.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 124) */
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 125) if (strcmp(param->key, "source") == 0) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 126) if (param->type != fs_value_is_string)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 127) return invalf(fc, "VFS: Non-string source");
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 128) if (fc->source)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 129) return invalf(fc, "VFS: Multiple sources");
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 130) fc->source = param->string;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 131) param->string = NULL;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 132) return 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 133) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 134)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 135) return invalf(fc, "%s: Unknown parameter '%s'",
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 136) fc->fs_type->name, param->key);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 137) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 138) EXPORT_SYMBOL(vfs_parse_fs_param);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 139)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 140) /**
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 141) * vfs_parse_fs_string - Convenience function to just parse a string.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 142) */
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 143) int vfs_parse_fs_string(struct fs_context *fc, const char *key,
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 144) const char *value, size_t v_size)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 145) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 146) int ret;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 147)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 148) struct fs_parameter param = {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 149) .key = key,
0f89589a8c6f1 (Al Viro 2019-12-17 14:15:04 -0500 150) .type = fs_value_is_flag,
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 151) .size = v_size,
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 152) };
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 153)
0f89589a8c6f1 (Al Viro 2019-12-17 14:15:04 -0500 154) if (value) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 155) param.string = kmemdup_nul(value, v_size, GFP_KERNEL);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 156) if (!param.string)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 157) return -ENOMEM;
0f89589a8c6f1 (Al Viro 2019-12-17 14:15:04 -0500 158) param.type = fs_value_is_string;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 159) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 160)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 161) ret = vfs_parse_fs_param(fc, ¶m);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 162) kfree(param.string);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 163) return ret;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 164) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 165) EXPORT_SYMBOL(vfs_parse_fs_string);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 166)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 167) /**
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 168) * generic_parse_monolithic - Parse key[=val][,key[=val]]* mount data
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 169) * @ctx: The superblock configuration to fill in.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 170) * @data: The data to parse
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 171) *
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 172) * Parse a blob of data that's in key[=val][,key[=val]]* form. This can be
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 173) * called from the ->monolithic_mount_data() fs_context operation.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 174) *
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 175) * Returns 0 on success or the error returned by the ->parse_option() fs_context
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 176) * operation on failure.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 177) */
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 178) int generic_parse_monolithic(struct fs_context *fc, void *data)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 179) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 180) char *options = data, *key;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 181) int ret = 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 182)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 183) if (!options)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 184) return 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 185)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 186) ret = security_sb_eat_lsm_opts(options, &fc->security);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 187) if (ret)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 188) return ret;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 189)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 190) while ((key = strsep(&options, ",")) != NULL) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 191) if (*key) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 192) size_t v_len = 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 193) char *value = strchr(key, '=');
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 194)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 195) if (value) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 196) if (value == key)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 197) continue;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 198) *value++ = 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 199) v_len = strlen(value);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 200) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 201) ret = vfs_parse_fs_string(fc, key, value, v_len);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 202) if (ret < 0)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 203) break;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 204) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 205) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 206)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 207) return ret;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 208) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 209) EXPORT_SYMBOL(generic_parse_monolithic);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 210)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 211) /**
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 212) * alloc_fs_context - Create a filesystem context.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 213) * @fs_type: The filesystem type.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 214) * @reference: The dentry from which this one derives (or NULL)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 215) * @sb_flags: Filesystem/superblock flags (SB_*)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 216) * @sb_flags_mask: Applicable members of @sb_flags
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 217) * @purpose: The purpose that this configuration shall be used for.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 218) *
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 219) * Open a filesystem and create a mount context. The mount context is
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 220) * initialised with the supplied flags and, if a submount/automount from
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 221) * another superblock (referred to by @reference) is supplied, may have
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 222) * parameters such as namespaces copied across from that superblock.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 223) */
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 224) static struct fs_context *alloc_fs_context(struct file_system_type *fs_type,
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 225) struct dentry *reference,
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 226) unsigned int sb_flags,
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 227) unsigned int sb_flags_mask,
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 228) enum fs_context_purpose purpose)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 229) {
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 230) int (*init_fs_context)(struct fs_context *);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 231) struct fs_context *fc;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 232) int ret = -ENOMEM;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 233)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 234) fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 235) if (!fc)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 236) return ERR_PTR(-ENOMEM);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 237)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 238) fc->purpose = purpose;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 239) fc->sb_flags = sb_flags;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 240) fc->sb_flags_mask = sb_flags_mask;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 241) fc->fs_type = get_filesystem(fs_type);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 242) fc->cred = get_current_cred();
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 243) fc->net_ns = get_net(current->nsproxy->net_ns);
cc3c0b533ab91 (Al Viro 2019-12-21 00:16:49 -0500 244) fc->log.prefix = fs_type->name;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 245)
24dcb3d90a1f6 (David Howells 2018-11-01 23:33:31 +0000 246) mutex_init(&fc->uapi_mutex);
24dcb3d90a1f6 (David Howells 2018-11-01 23:33:31 +0000 247)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 248) switch (purpose) {
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 249) case FS_CONTEXT_FOR_MOUNT:
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 250) fc->user_ns = get_user_ns(fc->cred->user_ns);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 251) break;
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 252) case FS_CONTEXT_FOR_SUBMOUNT:
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 253) fc->user_ns = get_user_ns(reference->d_sb->s_user_ns);
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 254) break;
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 255) case FS_CONTEXT_FOR_RECONFIGURE:
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 256) atomic_inc(&reference->d_sb->s_active);
1dd9bc08cf142 (Eric Biggers 2019-08-21 22:16:33 -0700 257) fc->user_ns = get_user_ns(reference->d_sb->s_user_ns);
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 258) fc->root = dget(reference);
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 259) break;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 260) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 261)
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 262) /* TODO: Make all filesystems support this unconditionally */
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 263) init_fs_context = fc->fs_type->init_fs_context;
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 264) if (!init_fs_context)
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 265) init_fs_context = legacy_init_fs_context;
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 266)
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 267) ret = init_fs_context(fc);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 268) if (ret < 0)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 269) goto err_fc;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 270) fc->need_free = true;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 271) return fc;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 272)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 273) err_fc:
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 274) put_fs_context(fc);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 275) return ERR_PTR(ret);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 276) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 277)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 278) struct fs_context *fs_context_for_mount(struct file_system_type *fs_type,
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 279) unsigned int sb_flags)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 280) {
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 281) return alloc_fs_context(fs_type, NULL, sb_flags, 0,
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 282) FS_CONTEXT_FOR_MOUNT);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 283) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 284) EXPORT_SYMBOL(fs_context_for_mount);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 285)
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 286) struct fs_context *fs_context_for_reconfigure(struct dentry *dentry,
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 287) unsigned int sb_flags,
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 288) unsigned int sb_flags_mask)
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 289) {
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 290) return alloc_fs_context(dentry->d_sb->s_type, dentry, sb_flags,
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 291) sb_flags_mask, FS_CONTEXT_FOR_RECONFIGURE);
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 292) }
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 293) EXPORT_SYMBOL(fs_context_for_reconfigure);
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 294)
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 295) struct fs_context *fs_context_for_submount(struct file_system_type *type,
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 296) struct dentry *reference)
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 297) {
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 298) return alloc_fs_context(type, reference, 0, 0, FS_CONTEXT_FOR_SUBMOUNT);
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 299) }
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 300) EXPORT_SYMBOL(fs_context_for_submount);
e1a91586d5da6 (Al Viro 2018-12-23 16:25:31 -0500 301)
c9ce29ed795fa (Al Viro 2018-12-20 15:04:50 -0500 302) void fc_drop_locked(struct fs_context *fc)
c9ce29ed795fa (Al Viro 2018-12-20 15:04:50 -0500 303) {
c9ce29ed795fa (Al Viro 2018-12-20 15:04:50 -0500 304) struct super_block *sb = fc->root->d_sb;
c9ce29ed795fa (Al Viro 2018-12-20 15:04:50 -0500 305) dput(fc->root);
c9ce29ed795fa (Al Viro 2018-12-20 15:04:50 -0500 306) fc->root = NULL;
c9ce29ed795fa (Al Viro 2018-12-20 15:04:50 -0500 307) deactivate_locked_super(sb);
c9ce29ed795fa (Al Viro 2018-12-20 15:04:50 -0500 308) }
c9ce29ed795fa (Al Viro 2018-12-20 15:04:50 -0500 309)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 310) static void legacy_fs_context_free(struct fs_context *fc);
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 311)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 312) /**
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 313) * vfs_dup_fc_config: Duplicate a filesystem context.
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 314) * @src_fc: The context to copy.
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 315) */
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 316) struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 317) {
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 318) struct fs_context *fc;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 319) int ret;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 320)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 321) if (!src_fc->ops->dup)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 322) return ERR_PTR(-EOPNOTSUPP);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 323)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 324) fc = kmemdup(src_fc, sizeof(struct fs_context), GFP_KERNEL);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 325) if (!fc)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 326) return ERR_PTR(-ENOMEM);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 327)
24dcb3d90a1f6 (David Howells 2018-11-01 23:33:31 +0000 328) mutex_init(&fc->uapi_mutex);
24dcb3d90a1f6 (David Howells 2018-11-01 23:33:31 +0000 329)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 330) fc->fs_private = NULL;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 331) fc->s_fs_info = NULL;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 332) fc->source = NULL;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 333) fc->security = NULL;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 334) get_filesystem(fc->fs_type);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 335) get_net(fc->net_ns);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 336) get_user_ns(fc->user_ns);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 337) get_cred(fc->cred);
cc3c0b533ab91 (Al Viro 2019-12-21 00:16:49 -0500 338) if (fc->log.log)
cc3c0b533ab91 (Al Viro 2019-12-21 00:16:49 -0500 339) refcount_inc(&fc->log.log->usage);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 340)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 341) /* Can't call put until we've called ->dup */
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 342) ret = fc->ops->dup(fc, src_fc);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 343) if (ret < 0)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 344) goto err_fc;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 345)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 346) ret = security_fs_context_dup(fc, src_fc);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 347) if (ret < 0)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 348) goto err_fc;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 349) return fc;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 350)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 351) err_fc:
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 352) put_fs_context(fc);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 353) return ERR_PTR(ret);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 354) }
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 355) EXPORT_SYMBOL(vfs_dup_fs_context);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 356)
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 357) /**
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 358) * logfc - Log a message to a filesystem context
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 359) * @fc: The filesystem context to log to.
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 360) * @fmt: The format of the buffer.
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 361) */
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 362) void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, ...)
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 363) {
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 364) va_list va;
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 365) struct va_format vaf = {.fmt = fmt, .va = &va};
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 366)
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 367) va_start(va, fmt);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 368) if (!log) {
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 369) switch (level) {
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 370) case 'w':
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 371) printk(KERN_WARNING "%s%s%pV\n", prefix ? prefix : "",
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 372) prefix ? ": " : "", &vaf);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 373) break;
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 374) case 'e':
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 375) printk(KERN_ERR "%s%s%pV\n", prefix ? prefix : "",
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 376) prefix ? ": " : "", &vaf);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 377) break;
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 378) default:
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 379) printk(KERN_NOTICE "%s%s%pV\n", prefix ? prefix : "",
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 380) prefix ? ": " : "", &vaf);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 381) break;
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 382) }
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 383) } else {
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 384) unsigned int logsize = ARRAY_SIZE(log->buffer);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 385) u8 index;
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 386) char *q = kasprintf(GFP_KERNEL, "%c %s%s%pV\n", level,
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 387) prefix ? prefix : "",
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 388) prefix ? ": " : "", &vaf);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 389)
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 390) index = log->head & (logsize - 1);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 391) BUILD_BUG_ON(sizeof(log->head) != sizeof(u8) ||
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 392) sizeof(log->tail) != sizeof(u8));
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 393) if ((u8)(log->head - log->tail) == logsize) {
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 394) /* The buffer is full, discard the oldest message */
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 395) if (log->need_free & (1 << index))
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 396) kfree(log->buffer[index]);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 397) log->tail++;
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 398) }
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 399)
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 400) log->buffer[index] = q ? q : "OOM: Can't store error string";
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 401) if (q)
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 402) log->need_free |= 1 << index;
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 403) else
9f09f649ca335 (Al Viro 2019-12-20 22:10:36 -0500 404) log->need_free &= ~(1 << index);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 405) log->head++;
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 406) }
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 407) va_end(va);
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 408) }
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 409) EXPORT_SYMBOL(logfc);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 410)
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 411) /*
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 412) * Free a logging structure.
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 413) */
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 414) static void put_fc_log(struct fs_context *fc)
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 415) {
cc3c0b533ab91 (Al Viro 2019-12-21 00:16:49 -0500 416) struct fc_log *log = fc->log.log;
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 417) int i;
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 418)
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 419) if (log) {
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 420) if (refcount_dec_and_test(&log->usage)) {
cc3c0b533ab91 (Al Viro 2019-12-21 00:16:49 -0500 421) fc->log.log = NULL;
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 422) for (i = 0; i <= 7; i++)
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 423) if (log->need_free & (1 << i))
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 424) kfree(log->buffer[i]);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 425) kfree(log);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 426) }
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 427) }
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 428) }
e7582e16a170d (David Howells 2018-11-01 23:07:26 +0000 429)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 430) /**
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 431) * put_fs_context - Dispose of a superblock configuration context.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 432) * @fc: The context to dispose of.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 433) */
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 434) void put_fs_context(struct fs_context *fc)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 435) {
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 436) struct super_block *sb;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 437)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 438) if (fc->root) {
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 439) sb = fc->root->d_sb;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 440) dput(fc->root);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 441) fc->root = NULL;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 442) deactivate_super(sb);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 443) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 444)
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 445) if (fc->need_free && fc->ops && fc->ops->free)
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 446) fc->ops->free(fc);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 447)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 448) security_free_mnt_opts(&fc->security);
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 449) put_net(fc->net_ns);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 450) put_user_ns(fc->user_ns);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 451) put_cred(fc->cred);
007ec26cdc9fe (David Howells 2018-11-01 23:34:29 +0000 452) put_fc_log(fc);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 453) put_filesystem(fc->fs_type);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 454) kfree(fc->source);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 455) kfree(fc);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 456) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 457) EXPORT_SYMBOL(put_fs_context);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 458)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 459) /*
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 460) * Free the config for a filesystem that doesn't support fs_context.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 461) */
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 462) static void legacy_fs_context_free(struct fs_context *fc)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 463) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 464) struct legacy_fs_context *ctx = fc->fs_private;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 465)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 466) if (ctx) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 467) if (ctx->param_type == LEGACY_FS_INDIVIDUAL_PARAMS)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 468) kfree(ctx->legacy_data);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 469) kfree(ctx);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 470) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 471) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 472)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 473) /*
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 474) * Duplicate a legacy config.
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 475) */
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 476) static int legacy_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 477) {
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 478) struct legacy_fs_context *ctx;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 479) struct legacy_fs_context *src_ctx = src_fc->fs_private;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 480)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 481) ctx = kmemdup(src_ctx, sizeof(*src_ctx), GFP_KERNEL);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 482) if (!ctx)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 483) return -ENOMEM;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 484)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 485) if (ctx->param_type == LEGACY_FS_INDIVIDUAL_PARAMS) {
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 486) ctx->legacy_data = kmemdup(src_ctx->legacy_data,
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 487) src_ctx->data_size, GFP_KERNEL);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 488) if (!ctx->legacy_data) {
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 489) kfree(ctx);
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 490) return -ENOMEM;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 491) }
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 492) }
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 493)
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 494) fc->fs_private = ctx;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 495) return 0;
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 496) }
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 497)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 498) /*
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 499) * Add a parameter to a legacy config. We build up a comma-separated list of
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 500) * options.
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 501) */
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 502) static int legacy_parse_param(struct fs_context *fc, struct fs_parameter *param)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 503) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 504) struct legacy_fs_context *ctx = fc->fs_private;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 505) unsigned int size = ctx->data_size;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 506) size_t len = 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 507)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 508) if (strcmp(param->key, "source") == 0) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 509) if (param->type != fs_value_is_string)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 510) return invalf(fc, "VFS: Legacy: Non-string source");
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 511) if (fc->source)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 512) return invalf(fc, "VFS: Legacy: Multiple sources");
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 513) fc->source = param->string;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 514) param->string = NULL;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 515) return 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 516) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 517)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 518) if (ctx->param_type == LEGACY_FS_MONOLITHIC_PARAMS)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 519) return invalf(fc, "VFS: Legacy: Can't mix monolithic and individual options");
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 520)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 521) switch (param->type) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 522) case fs_value_is_string:
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 523) len = 1 + param->size;
df561f6688fef (Gustavo A. R. Silva 2020-08-23 17:36:59 -0500 524) fallthrough;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 525) case fs_value_is_flag:
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 526) len += strlen(param->key);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 527) break;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 528) default:
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 529) return invalf(fc, "VFS: Legacy: Parameter type for '%s' not supported",
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 530) param->key);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 531) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 532)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 533) if (len > PAGE_SIZE - 2 - size)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 534) return invalf(fc, "VFS: Legacy: Cumulative options too large");
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 535) if (strchr(param->key, ',') ||
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 536) (param->type == fs_value_is_string &&
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 537) memchr(param->string, ',', param->size)))
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 538) return invalf(fc, "VFS: Legacy: Option '%s' contained comma",
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 539) param->key);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 540) if (!ctx->legacy_data) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 541) ctx->legacy_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 542) if (!ctx->legacy_data)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 543) return -ENOMEM;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 544) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 545)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 546) ctx->legacy_data[size++] = ',';
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 547) len = strlen(param->key);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 548) memcpy(ctx->legacy_data + size, param->key, len);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 549) size += len;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 550) if (param->type == fs_value_is_string) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 551) ctx->legacy_data[size++] = '=';
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 552) memcpy(ctx->legacy_data + size, param->string, param->size);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 553) size += param->size;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 554) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 555) ctx->legacy_data[size] = '\0';
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 556) ctx->data_size = size;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 557) ctx->param_type = LEGACY_FS_INDIVIDUAL_PARAMS;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 558) return 0;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 559) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 560)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 561) /*
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 562) * Add monolithic mount data.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 563) */
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 564) static int legacy_parse_monolithic(struct fs_context *fc, void *data)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 565) {
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 566) struct legacy_fs_context *ctx = fc->fs_private;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 567)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 568) if (ctx->param_type != LEGACY_FS_UNSET_PARAMS) {
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 569) pr_warn("VFS: Can't mix monolithic and individual options\n");
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 570) return -EINVAL;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 571) }
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 572)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 573) ctx->legacy_data = data;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 574) ctx->param_type = LEGACY_FS_MONOLITHIC_PARAMS;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 575) if (!ctx->legacy_data)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 576) return 0;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 577)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 578) if (fc->fs_type->fs_flags & FS_BINARY_MOUNTDATA)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 579) return 0;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 580) return security_sb_eat_lsm_opts(ctx->legacy_data, &fc->security);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 581) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 582)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 583) /*
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 584) * Get a mountable root with the legacy mount command.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 585) */
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 586) static int legacy_get_tree(struct fs_context *fc)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 587) {
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 588) struct legacy_fs_context *ctx = fc->fs_private;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 589) struct super_block *sb;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 590) struct dentry *root;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 591)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 592) root = fc->fs_type->mount(fc->fs_type, fc->sb_flags,
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 593) fc->source, ctx->legacy_data);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 594) if (IS_ERR(root))
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 595) return PTR_ERR(root);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 596)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 597) sb = root->d_sb;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 598) BUG_ON(!sb);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 599)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 600) fc->root = root;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 601) return 0;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 602) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 603)
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 604) /*
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 605) * Handle remount.
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 606) */
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 607) static int legacy_reconfigure(struct fs_context *fc)
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 608) {
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 609) struct legacy_fs_context *ctx = fc->fs_private;
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 610) struct super_block *sb = fc->root->d_sb;
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 611)
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 612) if (!sb->s_op->remount_fs)
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 613) return 0;
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 614)
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 615) return sb->s_op->remount_fs(sb, &fc->sb_flags,
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 616) ctx ? ctx->legacy_data : NULL);
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 617) }
8d0347f6c3a9d (David Howells 2018-11-04 09:28:36 -0500 618)
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 619) const struct fs_context_operations legacy_fs_context_ops = {
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 620) .free = legacy_fs_context_free,
0b52075ee6230 (Al Viro 2018-12-23 16:02:47 -0500 621) .dup = legacy_fs_context_dup,
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 622) .parse_param = legacy_parse_param,
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 623) .parse_monolithic = legacy_parse_monolithic,
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 624) .get_tree = legacy_get_tree,
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 625) .reconfigure = legacy_reconfigure,
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 626) };
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 627)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 628) /*
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 629) * Initialise a legacy context for a filesystem that doesn't support
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 630) * fs_context.
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 631) */
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 632) static int legacy_init_fs_context(struct fs_context *fc)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 633) {
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 634) fc->fs_private = kzalloc(sizeof(struct legacy_fs_context), GFP_KERNEL);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 635) if (!fc->fs_private)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 636) return -ENOMEM;
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 637) fc->ops = &legacy_fs_context_ops;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 638) return 0;
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 639) }
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 640)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 641) int parse_monolithic_mount_data(struct fs_context *fc, void *data)
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 642) {
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 643) int (*monolithic_mount_data)(struct fs_context *, void *);
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 644)
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 645) monolithic_mount_data = fc->ops->parse_monolithic;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 646) if (!monolithic_mount_data)
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 647) monolithic_mount_data = generic_parse_monolithic;
3e1aeb00e6d13 (David Howells 2018-11-01 23:07:25 +0000 648)
f3a09c92018a9 (Al Viro 2018-12-23 18:55:56 -0500 649) return monolithic_mount_data(fc, data);
9bc61ab18b1d4 (David Howells 2018-11-04 03:19:03 -0500 650) }
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 651)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 652) /*
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 653) * Clean up a context after performing an action on it and put it into a state
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 654) * from where it can be used to reconfigure a superblock.
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 655) *
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 656) * Note that here we do only the parts that can't fail; the rest is in
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 657) * finish_clean_context() below and in between those fs_context is marked
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 658) * FS_CONTEXT_AWAITING_RECONF. The reason for splitup is that after
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 659) * successful mount or remount we need to report success to userland.
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 660) * Trying to do full reinit (for the sake of possible subsequent remount)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 661) * and failing to allocate memory would've put us into a nasty situation.
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 662) * So here we only discard the old state and reinitialization is left
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 663) * until we actually try to reconfigure.
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 664) */
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 665) void vfs_clean_context(struct fs_context *fc)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 666) {
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 667) if (fc->need_free && fc->ops && fc->ops->free)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 668) fc->ops->free(fc);
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 669) fc->need_free = false;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 670) fc->fs_private = NULL;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 671) fc->s_fs_info = NULL;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 672) fc->sb_flags = 0;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 673) security_free_mnt_opts(&fc->security);
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 674) kfree(fc->source);
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 675) fc->source = NULL;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 676)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 677) fc->purpose = FS_CONTEXT_FOR_RECONFIGURE;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 678) fc->phase = FS_CONTEXT_AWAITING_RECONF;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 679) }
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 680)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 681) int finish_clean_context(struct fs_context *fc)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 682) {
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 683) int error;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 684)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 685) if (fc->phase != FS_CONTEXT_AWAITING_RECONF)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 686) return 0;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 687)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 688) if (fc->fs_type->init_fs_context)
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 689) error = fc->fs_type->init_fs_context(fc);
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 690) else
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 691) error = legacy_init_fs_context(fc);
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 692) if (unlikely(error)) {
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 693) fc->phase = FS_CONTEXT_FAILED;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 694) return error;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 695) }
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 696) fc->need_free = true;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 697) fc->phase = FS_CONTEXT_RECONF_PARAMS;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 698) return 0;
ecdab150fddb4 (David Howells 2018-11-01 23:36:09 +0000 699) }