Blame view

drivers/mtd/mtdsuper.c 5.43 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
17
   * 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>
  #include <linux/ctype.h>
6de940025   Jörn Engel   Fix JFFS2 sync si...
18
  #include <linux/slab.h>
acaebfd8a   David Howells   [MTD] generalise ...
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  
  /*
   * 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) {
  		DEBUG(2, "MTDSB: Match on device %d (\"%s\")
  ",
  		      mtd->index, mtd->name);
  		return 1;
  	}
  
  	DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")
  ",
  	      sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);
  	return 0;
  }
  
  /*
   * 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);
6de940025   Jörn Engel   Fix JFFS2 sync si...
52
  	sb->s_bdi = mtd->backing_dev_info;
acaebfd8a   David Howells   [MTD] generalise ...
53
54
55
56
57
58
  	return 0;
  }
  
  /*
   * get a superblock on an MTD-backed filesystem
   */
848b83a59   Al Viro   convert get_sb_mt...
59
  static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,
acaebfd8a   David Howells   [MTD] generalise ...
60
61
  			  const char *dev_name, void *data,
  			  struct mtd_info *mtd,
848b83a59   Al Viro   convert get_sb_mt...
62
  			  int (*fill_super)(struct super_block *, void *, int))
acaebfd8a   David Howells   [MTD] generalise ...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  {
  	struct super_block *sb;
  	int ret;
  
  	sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, mtd);
  	if (IS_ERR(sb))
  		goto out_error;
  
  	if (sb->s_root)
  		goto already_mounted;
  
  	/* fresh new superblock */
  	DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")
  ",
  	      mtd->index, mtd->name);
48440e893   David Howells   [MTD] Initialise ...
78
  	sb->s_flags = flags;
acaebfd8a   David Howells   [MTD] generalise ...
79
80
  	ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
  	if (ret < 0) {
6f5bbff9a   Al Viro   Convert obvious p...
81
  		deactivate_locked_super(sb);
848b83a59   Al Viro   convert get_sb_mt...
82
  		return ERR_PTR(ret);
acaebfd8a   David Howells   [MTD] generalise ...
83
84
85
86
  	}
  
  	/* go */
  	sb->s_flags |= MS_ACTIVE;
848b83a59   Al Viro   convert get_sb_mt...
87
  	return dget(sb->s_root);
acaebfd8a   David Howells   [MTD] generalise ...
88
89
90
91
92
93
  
  	/* new mountpoint for an already mounted superblock */
  already_mounted:
  	DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted
  ",
  	      mtd->index, mtd->name);
848b83a59   Al Viro   convert get_sb_mt...
94
95
  	put_mtd_device(mtd);
  	return dget(sb->s_root);
acaebfd8a   David Howells   [MTD] generalise ...
96
97
  
  out_error:
acaebfd8a   David Howells   [MTD] generalise ...
98
  	put_mtd_device(mtd);
848b83a59   Al Viro   convert get_sb_mt...
99
  	return ERR_CAST(sb);
acaebfd8a   David Howells   [MTD] generalise ...
100
101
102
103
104
  }
  
  /*
   * get a superblock on an MTD-backed filesystem by MTD device number
   */
848b83a59   Al Viro   convert get_sb_mt...
105
  static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags,
acaebfd8a   David Howells   [MTD] generalise ...
106
  			 const char *dev_name, void *data, int mtdnr,
848b83a59   Al Viro   convert get_sb_mt...
107
  			 int (*fill_super)(struct super_block *, void *, int))
acaebfd8a   David Howells   [MTD] generalise ...
108
109
110
111
  {
  	struct mtd_info *mtd;
  
  	mtd = get_mtd_device(NULL, mtdnr);
718ea8361   David Woodhouse   [MTD] Fix error c...
112
  	if (IS_ERR(mtd)) {
acaebfd8a   David Howells   [MTD] generalise ...
113
114
  		DEBUG(0, "MTDSB: Device #%u doesn't appear to exist
  ", mtdnr);
848b83a59   Al Viro   convert get_sb_mt...
115
  		return ERR_CAST(mtd);
acaebfd8a   David Howells   [MTD] generalise ...
116
  	}
848b83a59   Al Viro   convert get_sb_mt...
117
  	return mount_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super);
acaebfd8a   David Howells   [MTD] generalise ...
118
119
120
121
122
  }
  
  /*
   * set up an MTD-based superblock
   */
848b83a59   Al Viro   convert get_sb_mt...
123
  struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,
acaebfd8a   David Howells   [MTD] generalise ...
124
  	       const char *dev_name, void *data,
848b83a59   Al Viro   convert get_sb_mt...
125
  	       int (*fill_super)(struct super_block *, void *, int))
acaebfd8a   David Howells   [MTD] generalise ...
126
  {
f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
127
  #ifdef CONFIG_BLOCK
d5686b444   Al Viro   [PATCH] switch mt...
128
  	struct block_device *bdev;
f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
129
130
131
  	int ret, major;
  #endif
  	int mtdnr;
acaebfd8a   David Howells   [MTD] generalise ...
132
133
  
  	if (!dev_name)
848b83a59   Al Viro   convert get_sb_mt...
134
  		return ERR_PTR(-EINVAL);
acaebfd8a   David Howells   [MTD] generalise ...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  
  	DEBUG(2, "MTDSB: dev_name \"%s\"
  ", dev_name);
  
  	/* 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 */
  			DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"
  ",
  			      dev_name + 4);
677c2aec8   Ben Hutchings   mtd: Use get_mtd_...
151
152
  			mtd = get_mtd_device_nm(dev_name + 4);
  			if (!IS_ERR(mtd))
848b83a59   Al Viro   convert get_sb_mt...
153
  				return mount_mtd_aux(
677c2aec8   Ben Hutchings   mtd: Use get_mtd_...
154
155
  					fs_type, flags,
  					dev_name, data, mtd,
848b83a59   Al Viro   convert get_sb_mt...
156
  					fill_super);
acaebfd8a   David Howells   [MTD] generalise ...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  
  			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 */
  				DEBUG(1, "MTDSB: mtd%%d, mtdnr %d
  ",
  				      mtdnr);
848b83a59   Al Viro   convert get_sb_mt...
173
  				return mount_mtd_nr(fs_type, flags,
acaebfd8a   David Howells   [MTD] generalise ...
174
  						     dev_name, data,
848b83a59   Al Viro   convert get_sb_mt...
175
  						     mtdnr, fill_super);
acaebfd8a   David Howells   [MTD] generalise ...
176
177
178
  			}
  		}
  	}
f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
179
  #ifdef CONFIG_BLOCK
acaebfd8a   David Howells   [MTD] generalise ...
180
181
182
  	/* 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...
183
184
185
186
187
  	bdev = lookup_bdev(dev_name);
  	if (IS_ERR(bdev)) {
  		ret = PTR_ERR(bdev);
  		DEBUG(1, "MTDSB: lookup_bdev() returned %d
  ", ret);
848b83a59   Al Viro   convert get_sb_mt...
188
  		return ERR_PTR(ret);
acaebfd8a   David Howells   [MTD] generalise ...
189
  	}
d5686b444   Al Viro   [PATCH] switch mt...
190
191
  	DEBUG(1, "MTDSB: lookup_bdev() returned 0
  ");
acaebfd8a   David Howells   [MTD] generalise ...
192

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

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

f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
199
200
  	if (major != MTD_BLOCK_MAJOR)
  		goto not_an_MTD_device;
848b83a59   Al Viro   convert get_sb_mt...
201
  	return mount_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super);
acaebfd8a   David Howells   [MTD] generalise ...
202
203
  
  not_an_MTD_device:
f1136d022   David Woodhouse   [MTD] Fix !CONFIG...
204
  #endif /* CONFIG_BLOCK */
acaebfd8a   David Howells   [MTD] generalise ...
205
206
207
208
209
  	if (!(flags & MS_SILENT))
  		printk(KERN_NOTICE
  		       "MTD: Attempt to mount non-MTD device \"%s\"
  ",
  		       dev_name);
848b83a59   Al Viro   convert get_sb_mt...
210
  	return ERR_PTR(-EINVAL);
acaebfd8a   David Howells   [MTD] generalise ...
211
  }
848b83a59   Al Viro   convert get_sb_mt...
212
  EXPORT_SYMBOL_GPL(mount_mtd);
acaebfd8a   David Howells   [MTD] generalise ...
213
214
215
216
217
218
219
220
221
222
223
224
  
  /*
   * 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);