Blame view

drivers/mtd/mtdsuper.c 5.53 KB
acaebfd8a   David Howells   [MTD] generalise ...
1
2
3
  /* MTD-based superblock management
   *
   * Copyright © 2001-2007 Red Hat, Inc. All Rights Reserved.
a1452a377   David Woodhouse   mtd: Update copyr...
4
5
   * Copyright © 2001-2010 David Woodhouse <dwmw2@infradead.org>
   *
acaebfd8a   David Howells   [MTD] generalise ...
6
7
8
9
10
11
12
13
14
15
16
   * Written by:  David Howells <dhowells@redhat.com>
   *              David Woodhouse <dwmw2@infradead.org>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
  
  #include <linux/mtd/super.h>
  #include <linux/namei.h>
f3bcc0179   Paul Gortmaker   mtd: Add export.h...
17
  #include <linux/export.h>
acaebfd8a   David Howells   [MTD] generalise ...
18
  #include <linux/ctype.h>
6de940025   Jörn Engel   Fix JFFS2 sync si...
19
  #include <linux/slab.h>
f83c3838b   Ezequiel Garcia   mtd: Move major n...
20
  #include <linux/major.h>
fa06052d6   Jan Kara   mtd: Convert to d...
21
  #include <linux/backing-dev.h>
acaebfd8a   David Howells   [MTD] generalise ...
22
23
24
25
26
27
28
29
30
31
  
  /*
   * compare superblocks to see if they're equivalent
   * - they are if the underlying MTD device is the same
   */
  static int get_sb_mtd_compare(struct super_block *sb, void *_mtd)
  {
  	struct mtd_info *mtd = _mtd;
  
  	if (sb->s_mtd == mtd) {
289c05222   Brian Norris   mtd: replace DEBU...
32
33
  		pr_debug("MTDSB: Match on device %d (\"%s\")
  ",
acaebfd8a   David Howells   [MTD] generalise ...
34
35
36
  		      mtd->index, mtd->name);
  		return 1;
  	}
289c05222   Brian Norris   mtd: replace DEBU...
37
38
  	pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")
  ",
acaebfd8a   David Howells   [MTD] generalise ...
39
40
41
  	      sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);
  	return 0;
  }
fa06052d6   Jan Kara   mtd: Convert to d...
42
  extern struct backing_dev_info *mtd_bdi;
acaebfd8a   David Howells   [MTD] generalise ...
43
44
45
46
47
48
49
50
51
52
53
  /*
   * mark the superblock by the MTD device it is using
   * - set the device number to be the correct MTD block device for pesuperstence
   *   of NFS exports
   */
  static int get_sb_mtd_set(struct super_block *sb, void *_mtd)
  {
  	struct mtd_info *mtd = _mtd;
  
  	sb->s_mtd = mtd;
  	sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
fa06052d6   Jan Kara   mtd: Convert to d...
54
  	sb->s_bdi = bdi_get(mtd_bdi);
fa06052d6   Jan Kara   mtd: Convert to d...
55

acaebfd8a   David Howells   [MTD] generalise ...
56
57
58
59
60
61
  	return 0;
  }
  
  /*
   * get a superblock on an MTD-backed filesystem
   */
848b83a59   Al Viro   convert get_sb_mt...
62
  static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,
acaebfd8a   David Howells   [MTD] generalise ...
63
64
  			  const char *dev_name, void *data,
  			  struct mtd_info *mtd,
848b83a59   Al Viro   convert get_sb_mt...
65
  			  int (*fill_super)(struct super_block *, void *, int))
acaebfd8a   David Howells   [MTD] generalise ...
66
67
68
  {
  	struct super_block *sb;
  	int ret;
9249e17fe   David Howells   VFS: Pass mount f...
69
  	sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, flags, mtd);
acaebfd8a   David Howells   [MTD] generalise ...
70
71
72
73
74
75
76
  	if (IS_ERR(sb))
  		goto out_error;
  
  	if (sb->s_root)
  		goto already_mounted;
  
  	/* fresh new superblock */
289c05222   Brian Norris   mtd: replace DEBU...
77
78
  	pr_debug("MTDSB: New superblock for device %d (\"%s\")
  ",
acaebfd8a   David Howells   [MTD] generalise ...
79
80
81
82
  	      mtd->index, mtd->name);
  
  	ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
  	if (ret < 0) {
6f5bbff9a   Al Viro   Convert obvious p...
83
  		deactivate_locked_super(sb);
848b83a59   Al Viro   convert get_sb_mt...
84
  		return ERR_PTR(ret);
acaebfd8a   David Howells   [MTD] generalise ...
85
86
87
88
  	}
  
  	/* go */
  	sb->s_flags |= MS_ACTIVE;
848b83a59   Al Viro   convert get_sb_mt...
89
  	return dget(sb->s_root);
acaebfd8a   David Howells   [MTD] generalise ...
90
91
92
  
  	/* new mountpoint for an already mounted superblock */
  already_mounted:
289c05222   Brian Norris   mtd: replace DEBU...
93
94
  	pr_debug("MTDSB: Device %d (\"%s\") is already mounted
  ",
acaebfd8a   David Howells   [MTD] generalise ...
95
  	      mtd->index, mtd->name);
848b83a59   Al Viro   convert get_sb_mt...
96
97
  	put_mtd_device(mtd);
  	return dget(sb->s_root);
acaebfd8a   David Howells   [MTD] generalise ...
98
99
  
  out_error:
acaebfd8a   David Howells   [MTD] generalise ...
100
  	put_mtd_device(mtd);
848b83a59   Al Viro   convert get_sb_mt...
101
  	return ERR_CAST(sb);
acaebfd8a   David Howells   [MTD] generalise ...
102
103
104
105
106
  }
  
  /*
   * get a superblock on an MTD-backed filesystem by MTD device number
   */
848b83a59   Al Viro   convert get_sb_mt...
107
  static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags,
acaebfd8a   David Howells   [MTD] generalise ...
108
  			 const char *dev_name, void *data, int mtdnr,
848b83a59   Al Viro   convert get_sb_mt...
109
  			 int (*fill_super)(struct super_block *, void *, int))
acaebfd8a   David Howells   [MTD] generalise ...
110
111
112
113
  {
  	struct mtd_info *mtd;
  
  	mtd = get_mtd_device(NULL, mtdnr);
718ea8361   David Woodhouse   [MTD] Fix error c...
114
  	if (IS_ERR(mtd)) {
289c05222   Brian Norris   mtd: replace DEBU...
115
116
  		pr_debug("MTDSB: Device #%u doesn't appear to exist
  ", mtdnr);
848b83a59   Al Viro   convert get_sb_mt...
117
  		return ERR_CAST(mtd);
acaebfd8a   David Howells   [MTD] generalise ...
118
  	}
848b83a59   Al Viro   convert get_sb_mt...
119
  	return mount_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super);
acaebfd8a   David Howells   [MTD] generalise ...
120
121
122
123
124
  }
  
  /*
   * set up an MTD-based superblock
   */
848b83a59   Al Viro   convert get_sb_mt...
125
  struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,
acaebfd8a   David Howells   [MTD] generalise ...
126
  	       const char *dev_name, void *data,
848b83a59   Al Viro   convert get_sb_mt...
127
  	       int (*fill_super)(struct super_block *, void *, int))
acaebfd8a   David Howells   [MTD] generalise ...
128
  {
f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
129
  #ifdef CONFIG_BLOCK
d5686b444   Al Viro   [PATCH] switch mt...
130
  	struct block_device *bdev;
f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
131
132
133
  	int ret, major;
  #endif
  	int mtdnr;
acaebfd8a   David Howells   [MTD] generalise ...
134
135
  
  	if (!dev_name)
848b83a59   Al Viro   convert get_sb_mt...
136
  		return ERR_PTR(-EINVAL);
acaebfd8a   David Howells   [MTD] generalise ...
137

289c05222   Brian Norris   mtd: replace DEBU...
138
139
  	pr_debug("MTDSB: dev_name \"%s\"
  ", dev_name);
acaebfd8a   David Howells   [MTD] generalise ...
140
141
142
143
144
145
146
147
148
149
  
  	/* the preferred way of mounting in future; especially when
  	 * CONFIG_BLOCK=n - we specify the underlying MTD device by number or
  	 * by name, so that we don't require block device support to be present
  	 * in the kernel. */
  	if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') {
  		if (dev_name[3] == ':') {
  			struct mtd_info *mtd;
  
  			/* mount by MTD device name */
289c05222   Brian Norris   mtd: replace DEBU...
150
151
  			pr_debug("MTDSB: mtd:%%s, name \"%s\"
  ",
acaebfd8a   David Howells   [MTD] generalise ...
152
  			      dev_name + 4);
677c2aec8   Ben Hutchings   mtd: Use get_mtd_...
153
154
  			mtd = get_mtd_device_nm(dev_name + 4);
  			if (!IS_ERR(mtd))
848b83a59   Al Viro   convert get_sb_mt...
155
  				return mount_mtd_aux(
677c2aec8   Ben Hutchings   mtd: Use get_mtd_...
156
157
  					fs_type, flags,
  					dev_name, data, mtd,
848b83a59   Al Viro   convert get_sb_mt...
158
  					fill_super);
acaebfd8a   David Howells   [MTD] generalise ...
159
160
161
162
163
164
165
166
167
168
169
170
171
  
  			printk(KERN_NOTICE "MTD:"
  			       " MTD device with name \"%s\" not found.
  ",
  			       dev_name + 4);
  
  		} else if (isdigit(dev_name[3])) {
  			/* mount by MTD device number name */
  			char *endptr;
  
  			mtdnr = simple_strtoul(dev_name + 3, &endptr, 0);
  			if (!*endptr) {
  				/* It was a valid number */
289c05222   Brian Norris   mtd: replace DEBU...
172
173
  				pr_debug("MTDSB: mtd%%d, mtdnr %d
  ",
acaebfd8a   David Howells   [MTD] generalise ...
174
  				      mtdnr);
848b83a59   Al Viro   convert get_sb_mt...
175
  				return mount_mtd_nr(fs_type, flags,
acaebfd8a   David Howells   [MTD] generalise ...
176
  						     dev_name, data,
848b83a59   Al Viro   convert get_sb_mt...
177
  						     mtdnr, fill_super);
acaebfd8a   David Howells   [MTD] generalise ...
178
179
180
  			}
  		}
  	}
f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
181
  #ifdef CONFIG_BLOCK
acaebfd8a   David Howells   [MTD] generalise ...
182
183
184
  	/* try the old way - the hack where we allowed users to mount
  	 * /dev/mtdblock$(n) but didn't actually _use_ the blockdev
  	 */
d5686b444   Al Viro   [PATCH] switch mt...
185
186
187
  	bdev = lookup_bdev(dev_name);
  	if (IS_ERR(bdev)) {
  		ret = PTR_ERR(bdev);
289c05222   Brian Norris   mtd: replace DEBU...
188
189
  		pr_debug("MTDSB: lookup_bdev() returned %d
  ", ret);
848b83a59   Al Viro   convert get_sb_mt...
190
  		return ERR_PTR(ret);
acaebfd8a   David Howells   [MTD] generalise ...
191
  	}
289c05222   Brian Norris   mtd: replace DEBU...
192
193
  	pr_debug("MTDSB: lookup_bdev() returned 0
  ");
acaebfd8a   David Howells   [MTD] generalise ...
194

d5686b444   Al Viro   [PATCH] switch mt...
195
  	ret = -EINVAL;
acaebfd8a   David Howells   [MTD] generalise ...
196

f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
197
  	major = MAJOR(bdev->bd_dev);
d5686b444   Al Viro   [PATCH] switch mt...
198
199
  	mtdnr = MINOR(bdev->bd_dev);
  	bdput(bdev);
acaebfd8a   David Howells   [MTD] generalise ...
200

f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
201
202
  	if (major != MTD_BLOCK_MAJOR)
  		goto not_an_MTD_device;
848b83a59   Al Viro   convert get_sb_mt...
203
  	return mount_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super);
acaebfd8a   David Howells   [MTD] generalise ...
204
205
  
  not_an_MTD_device:
f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
206
  #endif /* CONFIG_BLOCK */
acaebfd8a   David Howells   [MTD] generalise ...
207
208
209
210
211
  	if (!(flags & MS_SILENT))
  		printk(KERN_NOTICE
  		       "MTD: Attempt to mount non-MTD device \"%s\"
  ",
  		       dev_name);
848b83a59   Al Viro   convert get_sb_mt...
212
  	return ERR_PTR(-EINVAL);
acaebfd8a   David Howells   [MTD] generalise ...
213
  }
848b83a59   Al Viro   convert get_sb_mt...
214
  EXPORT_SYMBOL_GPL(mount_mtd);
acaebfd8a   David Howells   [MTD] generalise ...
215
216
217
218
219
220
221
222
223
224
225
226
  
  /*
   * destroy an MTD-based superblock
   */
  void kill_mtd_super(struct super_block *sb)
  {
  	generic_shutdown_super(sb);
  	put_mtd_device(sb->s_mtd);
  	sb->s_mtd = NULL;
  }
  
  EXPORT_SYMBOL_GPL(kill_mtd_super);