cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mtdsuper.c (5058B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* MTD-based superblock management
      3 *
      4 * Copyright © 2001-2007 Red Hat, Inc. All Rights Reserved.
      5 * Copyright © 2001-2010 David Woodhouse <dwmw2@infradead.org>
      6 *
      7 * Written by:  David Howells <dhowells@redhat.com>
      8 *              David Woodhouse <dwmw2@infradead.org>
      9 */
     10
     11#include <linux/mtd/super.h>
     12#include <linux/namei.h>
     13#include <linux/export.h>
     14#include <linux/ctype.h>
     15#include <linux/slab.h>
     16#include <linux/major.h>
     17#include <linux/backing-dev.h>
     18#include <linux/blkdev.h>
     19#include <linux/fs_context.h>
     20#include "mtdcore.h"
     21
     22/*
     23 * compare superblocks to see if they're equivalent
     24 * - they are if the underlying MTD device is the same
     25 */
     26static int mtd_test_super(struct super_block *sb, struct fs_context *fc)
     27{
     28	struct mtd_info *mtd = fc->sget_key;
     29
     30	if (sb->s_mtd == fc->sget_key) {
     31		pr_debug("MTDSB: Match on device %d (\"%s\")\n",
     32			 mtd->index, mtd->name);
     33		return 1;
     34	}
     35
     36	pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n",
     37		 sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);
     38	return 0;
     39}
     40
     41/*
     42 * mark the superblock by the MTD device it is using
     43 * - set the device number to be the correct MTD block device for pesuperstence
     44 *   of NFS exports
     45 */
     46static int mtd_set_super(struct super_block *sb, struct fs_context *fc)
     47{
     48	sb->s_mtd = fc->sget_key;
     49	sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, sb->s_mtd->index);
     50	sb->s_bdi = bdi_get(mtd_bdi);
     51	return 0;
     52}
     53
     54/*
     55 * get a superblock on an MTD-backed filesystem
     56 */
     57static int mtd_get_sb(struct fs_context *fc,
     58		      struct mtd_info *mtd,
     59		      int (*fill_super)(struct super_block *,
     60					struct fs_context *))
     61{
     62	struct super_block *sb;
     63	int ret;
     64
     65	fc->sget_key = mtd;
     66	sb = sget_fc(fc, mtd_test_super, mtd_set_super);
     67	if (IS_ERR(sb))
     68		return PTR_ERR(sb);
     69
     70	if (sb->s_root) {
     71		/* new mountpoint for an already mounted superblock */
     72		pr_debug("MTDSB: Device %d (\"%s\") is already mounted\n",
     73			 mtd->index, mtd->name);
     74		put_mtd_device(mtd);
     75	} else {
     76		/* fresh new superblock */
     77		pr_debug("MTDSB: New superblock for device %d (\"%s\")\n",
     78			 mtd->index, mtd->name);
     79
     80		ret = fill_super(sb, fc);
     81		if (ret < 0)
     82			goto error_sb;
     83
     84		sb->s_flags |= SB_ACTIVE;
     85	}
     86
     87	BUG_ON(fc->root);
     88	fc->root = dget(sb->s_root);
     89	return 0;
     90
     91error_sb:
     92	deactivate_locked_super(sb);
     93	return ret;
     94}
     95
     96/*
     97 * get a superblock on an MTD-backed filesystem by MTD device number
     98 */
     99static int mtd_get_sb_by_nr(struct fs_context *fc, int mtdnr,
    100			    int (*fill_super)(struct super_block *,
    101					      struct fs_context *))
    102{
    103	struct mtd_info *mtd;
    104
    105	mtd = get_mtd_device(NULL, mtdnr);
    106	if (IS_ERR(mtd)) {
    107		errorf(fc, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr);
    108		return PTR_ERR(mtd);
    109	}
    110
    111	return mtd_get_sb(fc, mtd, fill_super);
    112}
    113
    114/**
    115 * get_tree_mtd - Get a superblock based on a single MTD device
    116 * @fc: The filesystem context holding the parameters
    117 * @fill_super: Helper to initialise a new superblock
    118 */
    119int get_tree_mtd(struct fs_context *fc,
    120	      int (*fill_super)(struct super_block *sb,
    121				struct fs_context *fc))
    122{
    123#ifdef CONFIG_BLOCK
    124	dev_t dev;
    125	int ret;
    126#endif
    127	int mtdnr;
    128
    129	if (!fc->source)
    130		return invalf(fc, "No source specified");
    131
    132	pr_debug("MTDSB: dev_name \"%s\"\n", fc->source);
    133
    134	/* the preferred way of mounting in future; especially when
    135	 * CONFIG_BLOCK=n - we specify the underlying MTD device by number or
    136	 * by name, so that we don't require block device support to be present
    137	 * in the kernel.
    138	 */
    139	if (fc->source[0] == 'm' &&
    140	    fc->source[1] == 't' &&
    141	    fc->source[2] == 'd') {
    142		if (fc->source[3] == ':') {
    143			struct mtd_info *mtd;
    144
    145			/* mount by MTD device name */
    146			pr_debug("MTDSB: mtd:%%s, name \"%s\"\n",
    147				 fc->source + 4);
    148
    149			mtd = get_mtd_device_nm(fc->source + 4);
    150			if (!IS_ERR(mtd))
    151				return mtd_get_sb(fc, mtd, fill_super);
    152
    153			errorf(fc, "MTD: MTD device with name \"%s\" not found",
    154			       fc->source + 4);
    155
    156		} else if (isdigit(fc->source[3])) {
    157			/* mount by MTD device number name */
    158			char *endptr;
    159
    160			mtdnr = simple_strtoul(fc->source + 3, &endptr, 0);
    161			if (!*endptr) {
    162				/* It was a valid number */
    163				pr_debug("MTDSB: mtd%%d, mtdnr %d\n", mtdnr);
    164				return mtd_get_sb_by_nr(fc, mtdnr, fill_super);
    165			}
    166		}
    167	}
    168
    169#ifdef CONFIG_BLOCK
    170	/* try the old way - the hack where we allowed users to mount
    171	 * /dev/mtdblock$(n) but didn't actually _use_ the blockdev
    172	 */
    173	ret = lookup_bdev(fc->source, &dev);
    174	if (ret) {
    175		errorf(fc, "MTD: Couldn't look up '%s': %d", fc->source, ret);
    176		return ret;
    177	}
    178	pr_debug("MTDSB: lookup_bdev() returned 0\n");
    179
    180	if (MAJOR(dev) == MTD_BLOCK_MAJOR)
    181		return mtd_get_sb_by_nr(fc, MINOR(dev), fill_super);
    182
    183#endif /* CONFIG_BLOCK */
    184
    185	if (!(fc->sb_flags & SB_SILENT))
    186		errorf(fc, "MTD: Attempt to mount non-MTD device \"%s\"",
    187		       fc->source);
    188	return -EINVAL;
    189}
    190EXPORT_SYMBOL_GPL(get_tree_mtd);
    191
    192/*
    193 * destroy an MTD-based superblock
    194 */
    195void kill_mtd_super(struct super_block *sb)
    196{
    197	generic_shutdown_super(sb);
    198	put_mtd_device(sb->s_mtd);
    199	sb->s_mtd = NULL;
    200}
    201
    202EXPORT_SYMBOL_GPL(kill_mtd_super);