0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/mtd/super.h>
0012 #include <linux/namei.h>
0013 #include <linux/export.h>
0014 #include <linux/ctype.h>
0015 #include <linux/slab.h>
0016 #include <linux/major.h>
0017 #include <linux/backing-dev.h>
0018 #include <linux/blkdev.h>
0019 #include <linux/fs_context.h>
0020 #include "mtdcore.h"
0021
0022
0023
0024
0025
0026 static int mtd_test_super(struct super_block *sb, struct fs_context *fc)
0027 {
0028 struct mtd_info *mtd = fc->sget_key;
0029
0030 if (sb->s_mtd == fc->sget_key) {
0031 pr_debug("MTDSB: Match on device %d (\"%s\")\n",
0032 mtd->index, mtd->name);
0033 return 1;
0034 }
0035
0036 pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n",
0037 sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);
0038 return 0;
0039 }
0040
0041
0042
0043
0044
0045
0046 static int mtd_set_super(struct super_block *sb, struct fs_context *fc)
0047 {
0048 sb->s_mtd = fc->sget_key;
0049 sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, sb->s_mtd->index);
0050 sb->s_bdi = bdi_get(mtd_bdi);
0051 return 0;
0052 }
0053
0054
0055
0056
0057 static int mtd_get_sb(struct fs_context *fc,
0058 struct mtd_info *mtd,
0059 int (*fill_super)(struct super_block *,
0060 struct fs_context *))
0061 {
0062 struct super_block *sb;
0063 int ret;
0064
0065 fc->sget_key = mtd;
0066 sb = sget_fc(fc, mtd_test_super, mtd_set_super);
0067 if (IS_ERR(sb))
0068 return PTR_ERR(sb);
0069
0070 if (sb->s_root) {
0071
0072 pr_debug("MTDSB: Device %d (\"%s\") is already mounted\n",
0073 mtd->index, mtd->name);
0074 put_mtd_device(mtd);
0075 } else {
0076
0077 pr_debug("MTDSB: New superblock for device %d (\"%s\")\n",
0078 mtd->index, mtd->name);
0079
0080 ret = fill_super(sb, fc);
0081 if (ret < 0)
0082 goto error_sb;
0083
0084 sb->s_flags |= SB_ACTIVE;
0085 }
0086
0087 BUG_ON(fc->root);
0088 fc->root = dget(sb->s_root);
0089 return 0;
0090
0091 error_sb:
0092 deactivate_locked_super(sb);
0093 return ret;
0094 }
0095
0096
0097
0098
0099 static int mtd_get_sb_by_nr(struct fs_context *fc, int mtdnr,
0100 int (*fill_super)(struct super_block *,
0101 struct fs_context *))
0102 {
0103 struct mtd_info *mtd;
0104
0105 mtd = get_mtd_device(NULL, mtdnr);
0106 if (IS_ERR(mtd)) {
0107 errorf(fc, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr);
0108 return PTR_ERR(mtd);
0109 }
0110
0111 return mtd_get_sb(fc, mtd, fill_super);
0112 }
0113
0114
0115
0116
0117
0118
0119 int get_tree_mtd(struct fs_context *fc,
0120 int (*fill_super)(struct super_block *sb,
0121 struct fs_context *fc))
0122 {
0123 #ifdef CONFIG_BLOCK
0124 dev_t dev;
0125 int ret;
0126 #endif
0127 int mtdnr;
0128
0129 if (!fc->source)
0130 return invalf(fc, "No source specified");
0131
0132 pr_debug("MTDSB: dev_name \"%s\"\n", fc->source);
0133
0134
0135
0136
0137
0138
0139 if (fc->source[0] == 'm' &&
0140 fc->source[1] == 't' &&
0141 fc->source[2] == 'd') {
0142 if (fc->source[3] == ':') {
0143 struct mtd_info *mtd;
0144
0145
0146 pr_debug("MTDSB: mtd:%%s, name \"%s\"\n",
0147 fc->source + 4);
0148
0149 mtd = get_mtd_device_nm(fc->source + 4);
0150 if (!IS_ERR(mtd))
0151 return mtd_get_sb(fc, mtd, fill_super);
0152
0153 errorf(fc, "MTD: MTD device with name \"%s\" not found",
0154 fc->source + 4);
0155
0156 } else if (isdigit(fc->source[3])) {
0157
0158 char *endptr;
0159
0160 mtdnr = simple_strtoul(fc->source + 3, &endptr, 0);
0161 if (!*endptr) {
0162
0163 pr_debug("MTDSB: mtd%%d, mtdnr %d\n", mtdnr);
0164 return mtd_get_sb_by_nr(fc, mtdnr, fill_super);
0165 }
0166 }
0167 }
0168
0169 #ifdef CONFIG_BLOCK
0170
0171
0172
0173 ret = lookup_bdev(fc->source, &dev);
0174 if (ret) {
0175 errorf(fc, "MTD: Couldn't look up '%s': %d", fc->source, ret);
0176 return ret;
0177 }
0178 pr_debug("MTDSB: lookup_bdev() returned 0\n");
0179
0180 if (MAJOR(dev) == MTD_BLOCK_MAJOR)
0181 return mtd_get_sb_by_nr(fc, MINOR(dev), fill_super);
0182
0183 #endif
0184
0185 if (!(fc->sb_flags & SB_SILENT))
0186 errorf(fc, "MTD: Attempt to mount non-MTD device \"%s\"",
0187 fc->source);
0188 return -EINVAL;
0189 }
0190 EXPORT_SYMBOL_GPL(get_tree_mtd);
0191
0192
0193
0194
0195 void kill_mtd_super(struct super_block *sb)
0196 {
0197 generic_shutdown_super(sb);
0198 put_mtd_device(sb->s_mtd);
0199 sb->s_mtd = NULL;
0200 }
0201
0202 EXPORT_SYMBOL_GPL(kill_mtd_super);