Blame view

drivers/base/devtmpfs.c 8.99 KB
2b2af54a5   Kay Sievers   Driver Core: devt...
1
2
3
4
5
6
7
8
  /*
   * devtmpfs - kernel-maintained tmpfs-based /dev
   *
   * Copyright (C) 2009, Kay Sievers <kay.sievers@vrfy.org>
   *
   * During bootup, before any driver core device is registered,
   * devtmpfs, a tmpfs-based filesystem is created. Every driver-core
   * device which requests a device node, will add a node in this
e454cea20   Kay Sievers   Driver-Core: exte...
9
   * filesystem.
02fbe5e61   Peter Korsgaard   devtmpfs: fix 'th...
10
11
12
   * By default, all devices are named after the name of the device,
   * owned by root and have a default mode of 0600. Subsystems can
   * overwrite the default setting if needed.
2b2af54a5   Kay Sievers   Driver Core: devt...
13
14
15
16
17
18
19
20
21
22
   */
  
  #include <linux/kernel.h>
  #include <linux/syscalls.h>
  #include <linux/mount.h>
  #include <linux/device.h>
  #include <linux/genhd.h>
  #include <linux/namei.h>
  #include <linux/fs.h>
  #include <linux/shmem_fs.h>
da5e4ef7f   Peter Korsgaard   devtmpfs: support...
23
  #include <linux/ramfs.h>
e454cea20   Kay Sievers   Driver-Core: exte...
24
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
2780f1ff6   Al Viro   switch devtmpfs o...
26
  #include <linux/kthread.h>
c3a304209   Greg Kroah-Hartman   devtmpfs: add bas...
27
  #include "base.h"
2b2af54a5   Kay Sievers   Driver Core: devt...
28

2780f1ff6   Al Viro   switch devtmpfs o...
29
  static struct task_struct *thread;
2b2af54a5   Kay Sievers   Driver Core: devt...
30
31
  
  #if defined CONFIG_DEVTMPFS_MOUNT
fc14f2fef   Al Viro   convert get_sb_si...
32
  static int mount_dev = 1;
2b2af54a5   Kay Sievers   Driver Core: devt...
33
  #else
fc14f2fef   Al Viro   convert get_sb_si...
34
  static int mount_dev;
2b2af54a5   Kay Sievers   Driver Core: devt...
35
  #endif
2780f1ff6   Al Viro   switch devtmpfs o...
36
37
38
39
40
41
42
  static DEFINE_SPINLOCK(req_lock);
  
  static struct req {
  	struct req *next;
  	struct completion done;
  	int err;
  	const char *name;
2c9ede55e   Al Viro   switch device_get...
43
  	umode_t mode;	/* 0 => delete */
4e4098a3e   Greg Kroah-Hartman   driver core: hand...
44
45
  	kuid_t uid;
  	kgid_t gid;
2780f1ff6   Al Viro   switch devtmpfs o...
46
47
  	struct device *dev;
  } *requests;
ed413ae6e   Kay Sievers   Driver core: devt...
48

2b2af54a5   Kay Sievers   Driver Core: devt...
49
50
  static int __init mount_param(char *str)
  {
fc14f2fef   Al Viro   convert get_sb_si...
51
  	mount_dev = simple_strtoul(str, NULL, 0);
2b2af54a5   Kay Sievers   Driver Core: devt...
52
53
54
  	return 1;
  }
  __setup("devtmpfs.mount=", mount_param);
fc14f2fef   Al Viro   convert get_sb_si...
55
56
  static struct dentry *dev_mount(struct file_system_type *fs_type, int flags,
  		      const char *dev_name, void *data)
2b2af54a5   Kay Sievers   Driver Core: devt...
57
  {
da5e4ef7f   Peter Korsgaard   devtmpfs: support...
58
  #ifdef CONFIG_TMPFS
fc14f2fef   Al Viro   convert get_sb_si...
59
  	return mount_single(fs_type, flags, data, shmem_fill_super);
da5e4ef7f   Peter Korsgaard   devtmpfs: support...
60
  #else
fc14f2fef   Al Viro   convert get_sb_si...
61
  	return mount_single(fs_type, flags, data, ramfs_fill_super);
da5e4ef7f   Peter Korsgaard   devtmpfs: support...
62
  #endif
2b2af54a5   Kay Sievers   Driver Core: devt...
63
64
65
66
  }
  
  static struct file_system_type dev_fs_type = {
  	.name = "devtmpfs",
fc14f2fef   Al Viro   convert get_sb_si...
67
  	.mount = dev_mount,
2b2af54a5   Kay Sievers   Driver Core: devt...
68
69
70
71
72
73
74
75
76
77
78
  	.kill_sb = kill_litter_super,
  };
  
  #ifdef CONFIG_BLOCK
  static inline int is_blockdev(struct device *dev)
  {
  	return dev->class == &block_class;
  }
  #else
  static inline int is_blockdev(struct device *dev) { return 0; }
  #endif
2780f1ff6   Al Viro   switch devtmpfs o...
79
80
81
82
83
84
85
86
87
  int devtmpfs_create_node(struct device *dev)
  {
  	const char *tmp = NULL;
  	struct req req;
  
  	if (!thread)
  		return 0;
  
  	req.mode = 0;
4e4098a3e   Greg Kroah-Hartman   driver core: hand...
88
89
  	req.uid = GLOBAL_ROOT_UID;
  	req.gid = GLOBAL_ROOT_GID;
3c2670e65   Kay Sievers   driver core: add ...
90
  	req.name = device_get_devnode(dev, &req.mode, &req.uid, &req.gid, &tmp);
2780f1ff6   Al Viro   switch devtmpfs o...
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  	if (!req.name)
  		return -ENOMEM;
  
  	if (req.mode == 0)
  		req.mode = 0600;
  	if (is_blockdev(dev))
  		req.mode |= S_IFBLK;
  	else
  		req.mode |= S_IFCHR;
  
  	req.dev = dev;
  
  	init_completion(&req.done);
  
  	spin_lock(&req_lock);
  	req.next = requests;
  	requests = &req;
  	spin_unlock(&req_lock);
  
  	wake_up_process(thread);
  	wait_for_completion(&req.done);
  
  	kfree(tmp);
  
  	return req.err;
  }
  
  int devtmpfs_delete_node(struct device *dev)
  {
  	const char *tmp = NULL;
  	struct req req;
  
  	if (!thread)
  		return 0;
3c2670e65   Kay Sievers   driver core: add ...
125
  	req.name = device_get_devnode(dev, NULL, NULL, NULL, &tmp);
2780f1ff6   Al Viro   switch devtmpfs o...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  	if (!req.name)
  		return -ENOMEM;
  
  	req.mode = 0;
  	req.dev = dev;
  
  	init_completion(&req.done);
  
  	spin_lock(&req_lock);
  	req.next = requests;
  	requests = &req;
  	spin_unlock(&req_lock);
  
  	wake_up_process(thread);
  	wait_for_completion(&req.done);
  
  	kfree(tmp);
  	return req.err;
  }
fbd48a69a   Al Viro   switch devtmpfs t...
145
  static int dev_mkdir(const char *name, umode_t mode)
2b2af54a5   Kay Sievers   Driver Core: devt...
146
  {
2b2af54a5   Kay Sievers   Driver Core: devt...
147
  	struct dentry *dentry;
69753a0f1   Al Viro   switch devtmpfs t...
148
  	struct path path;
2b2af54a5   Kay Sievers   Driver Core: devt...
149
  	int err;
1ac12b4b6   Jeff Layton   vfs: turn is_dir ...
150
  	dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY);
69753a0f1   Al Viro   switch devtmpfs t...
151
152
  	if (IS_ERR(dentry))
  		return PTR_ERR(dentry);
75c3cfa85   David Howells   VFS: assorted wei...
153
  	err = vfs_mkdir(d_inode(path.dentry), dentry, mode);
69753a0f1   Al Viro   switch devtmpfs t...
154
155
  	if (!err)
  		/* mark as kernel-created inode */
75c3cfa85   David Howells   VFS: assorted wei...
156
  		d_inode(dentry)->i_private = &thread;
921a1650d   Al Viro   new helper: done_...
157
  	done_path_create(&path, dentry);
2b2af54a5   Kay Sievers   Driver Core: devt...
158
159
160
161
162
  	return err;
  }
  
  static int create_path(const char *nodepath)
  {
5da4e6894   Al Viro   devtmpfs: get rid...
163
164
  	char *path;
  	char *s;
9d108d254   Al Viro   devtmpfs: missing...
165
  	int err = 0;
2b2af54a5   Kay Sievers   Driver Core: devt...
166

5da4e6894   Al Viro   devtmpfs: get rid...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  	/* parent directories do not exist, create them */
  	path = kstrdup(nodepath, GFP_KERNEL);
  	if (!path)
  		return -ENOMEM;
  
  	s = path;
  	for (;;) {
  		s = strchr(s, '/');
  		if (!s)
  			break;
  		s[0] = '\0';
  		err = dev_mkdir(path, 0755);
  		if (err && err != -EEXIST)
  			break;
  		s[0] = '/';
  		s++;
2b2af54a5   Kay Sievers   Driver Core: devt...
183
  	}
5da4e6894   Al Viro   devtmpfs: get rid...
184
  	kfree(path);
2b2af54a5   Kay Sievers   Driver Core: devt...
185
186
  	return err;
  }
4e4098a3e   Greg Kroah-Hartman   driver core: hand...
187
188
  static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
  			 kgid_t gid, struct device *dev)
2b2af54a5   Kay Sievers   Driver Core: devt...
189
  {
2b2af54a5   Kay Sievers   Driver Core: devt...
190
  	struct dentry *dentry;
69753a0f1   Al Viro   switch devtmpfs t...
191
  	struct path path;
2b2af54a5   Kay Sievers   Driver Core: devt...
192
  	int err;
69753a0f1   Al Viro   switch devtmpfs t...
193
194
  	dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);
  	if (dentry == ERR_PTR(-ENOENT)) {
2b2af54a5   Kay Sievers   Driver Core: devt...
195
  		create_path(nodename);
69753a0f1   Al Viro   switch devtmpfs t...
196
  		dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);
2b2af54a5   Kay Sievers   Driver Core: devt...
197
  	}
69753a0f1   Al Viro   switch devtmpfs t...
198
199
  	if (IS_ERR(dentry))
  		return PTR_ERR(dentry);
75c3cfa85   David Howells   VFS: assorted wei...
200
  	err = vfs_mknod(d_inode(path.dentry), dentry, mode, dev->devt);
69753a0f1   Al Viro   switch devtmpfs t...
201
202
  	if (!err) {
  		struct iattr newattrs;
69753a0f1   Al Viro   switch devtmpfs t...
203
  		newattrs.ia_mode = mode;
4e4098a3e   Greg Kroah-Hartman   driver core: hand...
204
205
  		newattrs.ia_uid = uid;
  		newattrs.ia_gid = gid;
3c2670e65   Kay Sievers   driver core: add ...
206
  		newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
5955102c9   Al Viro   wrappers for ->i_...
207
  		inode_lock(d_inode(dentry));
27ac0ffea   J. Bruce Fields   locks: break dele...
208
  		notify_change(dentry, &newattrs, NULL);
5955102c9   Al Viro   wrappers for ->i_...
209
  		inode_unlock(d_inode(dentry));
69753a0f1   Al Viro   switch devtmpfs t...
210
211
  
  		/* mark as kernel-created inode */
75c3cfa85   David Howells   VFS: assorted wei...
212
  		d_inode(dentry)->i_private = &thread;
2b2af54a5   Kay Sievers   Driver Core: devt...
213
  	}
921a1650d   Al Viro   new helper: done_...
214
  	done_path_create(&path, dentry);
2b2af54a5   Kay Sievers   Driver Core: devt...
215
216
217
218
219
  	return err;
  }
  
  static int dev_rmdir(const char *name)
  {
79714f72d   Al Viro   get rid of kern_p...
220
  	struct path parent;
2b2af54a5   Kay Sievers   Driver Core: devt...
221
222
  	struct dentry *dentry;
  	int err;
79714f72d   Al Viro   get rid of kern_p...
223
224
225
  	dentry = kern_path_locked(name, &parent);
  	if (IS_ERR(dentry))
  		return PTR_ERR(dentry);
75c3cfa85   David Howells   VFS: assorted wei...
226
227
228
  	if (d_really_is_positive(dentry)) {
  		if (d_inode(dentry)->i_private == &thread)
  			err = vfs_rmdir(d_inode(parent.dentry), dentry);
79714f72d   Al Viro   get rid of kern_p...
229
230
  		else
  			err = -EPERM;
2b2af54a5   Kay Sievers   Driver Core: devt...
231
  	} else {
79714f72d   Al Viro   get rid of kern_p...
232
  		err = -ENOENT;
2b2af54a5   Kay Sievers   Driver Core: devt...
233
  	}
79714f72d   Al Viro   get rid of kern_p...
234
  	dput(dentry);
5955102c9   Al Viro   wrappers for ->i_...
235
  	inode_unlock(d_inode(parent.dentry));
79714f72d   Al Viro   get rid of kern_p...
236
  	path_put(&parent);
2b2af54a5   Kay Sievers   Driver Core: devt...
237
238
239
240
241
242
243
244
245
246
247
  	return err;
  }
  
  static int delete_path(const char *nodepath)
  {
  	const char *path;
  	int err = 0;
  
  	path = kstrdup(nodepath, GFP_KERNEL);
  	if (!path)
  		return -ENOMEM;
ed413ae6e   Kay Sievers   Driver core: devt...
248
  	for (;;) {
2b2af54a5   Kay Sievers   Driver Core: devt...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  		char *base;
  
  		base = strrchr(path, '/');
  		if (!base)
  			break;
  		base[0] = '\0';
  		err = dev_rmdir(path);
  		if (err)
  			break;
  	}
  
  	kfree(path);
  	return err;
  }
  
  static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
  {
  	/* did we create it */
2780f1ff6   Al Viro   switch devtmpfs o...
267
  	if (inode->i_private != &thread)
2b2af54a5   Kay Sievers   Driver Core: devt...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  		return 0;
  
  	/* does the dev_t match */
  	if (is_blockdev(dev)) {
  		if (!S_ISBLK(stat->mode))
  			return 0;
  	} else {
  		if (!S_ISCHR(stat->mode))
  			return 0;
  	}
  	if (stat->rdev != dev->devt)
  		return 0;
  
  	/* ours */
  	return 1;
  }
2780f1ff6   Al Viro   switch devtmpfs o...
284
  static int handle_remove(const char *nodename, struct device *dev)
2b2af54a5   Kay Sievers   Driver Core: devt...
285
  {
79714f72d   Al Viro   get rid of kern_p...
286
  	struct path parent;
2b2af54a5   Kay Sievers   Driver Core: devt...
287
  	struct dentry *dentry;
fbde7c611   Axel Lin   devtmpfs: Calling...
288
  	int deleted = 0;
2b2af54a5   Kay Sievers   Driver Core: devt...
289
  	int err;
79714f72d   Al Viro   get rid of kern_p...
290
291
292
  	dentry = kern_path_locked(nodename, &parent);
  	if (IS_ERR(dentry))
  		return PTR_ERR(dentry);
75c3cfa85   David Howells   VFS: assorted wei...
293
  	if (d_really_is_positive(dentry)) {
79714f72d   Al Viro   get rid of kern_p...
294
  		struct kstat stat;
3dadecce2   Al Viro   switch vfs_getatt...
295
296
  		struct path p = {.mnt = parent.mnt, .dentry = dentry};
  		err = vfs_getattr(&p, &stat);
75c3cfa85   David Howells   VFS: assorted wei...
297
  		if (!err && dev_mynode(dev, d_inode(dentry), &stat)) {
79714f72d   Al Viro   get rid of kern_p...
298
299
300
301
302
  			struct iattr newattrs;
  			/*
  			 * before unlinking this node, reset permissions
  			 * of possible references like hardlinks
  			 */
91fa2ccaa   Eric W. Biederman   userns: Convert d...
303
304
  			newattrs.ia_uid = GLOBAL_ROOT_UID;
  			newattrs.ia_gid = GLOBAL_ROOT_GID;
79714f72d   Al Viro   get rid of kern_p...
305
306
307
  			newattrs.ia_mode = stat.mode & ~0777;
  			newattrs.ia_valid =
  				ATTR_UID|ATTR_GID|ATTR_MODE;
5955102c9   Al Viro   wrappers for ->i_...
308
  			inode_lock(d_inode(dentry));
27ac0ffea   J. Bruce Fields   locks: break dele...
309
  			notify_change(dentry, &newattrs, NULL);
5955102c9   Al Viro   wrappers for ->i_...
310
  			inode_unlock(d_inode(dentry));
75c3cfa85   David Howells   VFS: assorted wei...
311
  			err = vfs_unlink(d_inode(parent.dentry), dentry, NULL);
79714f72d   Al Viro   get rid of kern_p...
312
313
  			if (!err || err == -ENOENT)
  				deleted = 1;
2b2af54a5   Kay Sievers   Driver Core: devt...
314
  		}
2b2af54a5   Kay Sievers   Driver Core: devt...
315
  	} else {
79714f72d   Al Viro   get rid of kern_p...
316
  		err = -ENOENT;
2b2af54a5   Kay Sievers   Driver Core: devt...
317
  	}
79714f72d   Al Viro   get rid of kern_p...
318
  	dput(dentry);
5955102c9   Al Viro   wrappers for ->i_...
319
  	inode_unlock(d_inode(parent.dentry));
2b2af54a5   Kay Sievers   Driver Core: devt...
320

79714f72d   Al Viro   get rid of kern_p...
321
  	path_put(&parent);
2b2af54a5   Kay Sievers   Driver Core: devt...
322
323
  	if (deleted && strchr(nodename, '/'))
  		delete_path(nodename);
2b2af54a5   Kay Sievers   Driver Core: devt...
324
325
326
327
328
329
330
  	return err;
  }
  
  /*
   * If configured, or requested by the commandline, devtmpfs will be
   * auto-mounted after the kernel mounted the root filesystem.
   */
073120cc2   Kay Sievers   Driver Core: devt...
331
  int devtmpfs_mount(const char *mntdir)
2b2af54a5   Kay Sievers   Driver Core: devt...
332
  {
2b2af54a5   Kay Sievers   Driver Core: devt...
333
  	int err;
fc14f2fef   Al Viro   convert get_sb_si...
334
  	if (!mount_dev)
2b2af54a5   Kay Sievers   Driver Core: devt...
335
  		return 0;
2780f1ff6   Al Viro   switch devtmpfs o...
336
  	if (!thread)
2b2af54a5   Kay Sievers   Driver Core: devt...
337
  		return 0;
073120cc2   Kay Sievers   Driver Core: devt...
338
  	err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
2b2af54a5   Kay Sievers   Driver Core: devt...
339
340
341
342
343
344
  	if (err)
  		printk(KERN_INFO "devtmpfs: error mounting %i
  ", err);
  	else
  		printk(KERN_INFO "devtmpfs: mounted
  ");
2b2af54a5   Kay Sievers   Driver Core: devt...
345
346
  	return err;
  }
f9e0b159d   Arnaud Lacombe   drivers/base/devt...
347
  static DECLARE_COMPLETION(setup_done);
2780f1ff6   Al Viro   switch devtmpfs o...
348

4e4098a3e   Greg Kroah-Hartman   driver core: hand...
349
  static int handle(const char *name, umode_t mode, kuid_t uid, kgid_t gid,
3c2670e65   Kay Sievers   driver core: add ...
350
  		  struct device *dev)
2780f1ff6   Al Viro   switch devtmpfs o...
351
352
  {
  	if (mode)
3c2670e65   Kay Sievers   driver core: add ...
353
  		return handle_create(name, mode, uid, gid, dev);
2780f1ff6   Al Viro   switch devtmpfs o...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  	else
  		return handle_remove(name, dev);
  }
  
  static int devtmpfsd(void *p)
  {
  	char options[] = "mode=0755";
  	int *err = p;
  	*err = sys_unshare(CLONE_NEWNS);
  	if (*err)
  		goto out;
  	*err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);
  	if (*err)
  		goto out;
  	sys_chdir("/.."); /* will traverse into overmounted root */
  	sys_chroot(".");
  	complete(&setup_done);
  	while (1) {
  		spin_lock(&req_lock);
  		while (requests) {
  			struct req *req = requests;
  			requests = NULL;
  			spin_unlock(&req_lock);
  			while (req) {
e13889bab   Al Viro   fix devtmpfs race
378
  				struct req *next = req->next;
3c2670e65   Kay Sievers   driver core: add ...
379
380
  				req->err = handle(req->name, req->mode,
  						  req->uid, req->gid, req->dev);
2780f1ff6   Al Viro   switch devtmpfs o...
381
  				complete(&req->done);
e13889bab   Al Viro   fix devtmpfs race
382
  				req = next;
2780f1ff6   Al Viro   switch devtmpfs o...
383
384
385
  			}
  			spin_lock(&req_lock);
  		}
65e6757be   Kautuk Consul   devtmpfsd: fix ta...
386
  		__set_current_state(TASK_INTERRUPTIBLE);
2780f1ff6   Al Viro   switch devtmpfs o...
387
388
  		spin_unlock(&req_lock);
  		schedule();
2780f1ff6   Al Viro   switch devtmpfs o...
389
390
391
392
393
394
  	}
  	return 0;
  out:
  	complete(&setup_done);
  	return *err;
  }
2b2af54a5   Kay Sievers   Driver Core: devt...
395
396
397
398
399
400
  /*
   * Create devtmpfs instance, driver-core devices will add their device
   * nodes here.
   */
  int __init devtmpfs_init(void)
  {
2780f1ff6   Al Viro   switch devtmpfs o...
401
  	int err = register_filesystem(&dev_fs_type);
2b2af54a5   Kay Sievers   Driver Core: devt...
402
403
404
405
406
407
  	if (err) {
  		printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
  		       "type %i
  ", err);
  		return err;
  	}
2780f1ff6   Al Viro   switch devtmpfs o...
408
409
410
411
412
413
414
415
416
  	thread = kthread_run(devtmpfsd, &err, "kdevtmpfs");
  	if (!IS_ERR(thread)) {
  		wait_for_completion(&setup_done);
  	} else {
  		err = PTR_ERR(thread);
  		thread = NULL;
  	}
  
  	if (err) {
2b2af54a5   Kay Sievers   Driver Core: devt...
417
418
419
420
421
  		printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i
  ", err);
  		unregister_filesystem(&dev_fs_type);
  		return err;
  	}
2b2af54a5   Kay Sievers   Driver Core: devt...
422
423
424
425
426
  
  	printk(KERN_INFO "devtmpfs: initialized
  ");
  	return 0;
  }