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