root/drivers/mtd/mtdsuper.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mtd_test_super
  2. mtd_set_super
  3. mtd_get_sb
  4. mtd_get_sb_by_nr
  5. get_tree_mtd
  6. kill_mtd_super

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

/* [<][>][^][v][top][bottom][index][help] */