aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/devtmpfs.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/base/devtmpfs.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/base/devtmpfs.c')
-rw-r--r--drivers/base/devtmpfs.c116
1 files changed, 66 insertions, 50 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index a1cb5afe6801..057cf11326bf 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -23,6 +23,7 @@
23#include <linux/cred.h> 23#include <linux/cred.h>
24#include <linux/sched.h> 24#include <linux/sched.h>
25#include <linux/init_task.h> 25#include <linux/init_task.h>
26#include <linux/slab.h>
26 27
27static struct vfsmount *dev_mnt; 28static struct vfsmount *dev_mnt;
28 29
@@ -32,6 +33,8 @@ static int dev_mount = 1;
32static int dev_mount; 33static int dev_mount;
33#endif 34#endif
34 35
36static DEFINE_MUTEX(dirlock);
37
35static int __init mount_param(char *str) 38static int __init mount_param(char *str)
36{ 39{
37 dev_mount = simple_strtoul(str, NULL, 0); 40 dev_mount = simple_strtoul(str, NULL, 0);
@@ -74,47 +77,37 @@ static int dev_mkdir(const char *name, mode_t mode)
74 dentry = lookup_create(&nd, 1); 77 dentry = lookup_create(&nd, 1);
75 if (!IS_ERR(dentry)) { 78 if (!IS_ERR(dentry)) {
76 err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); 79 err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
80 if (!err)
81 /* mark as kernel-created inode */
82 dentry->d_inode->i_private = &dev_mnt;
77 dput(dentry); 83 dput(dentry);
78 } else { 84 } else {
79 err = PTR_ERR(dentry); 85 err = PTR_ERR(dentry);
80 } 86 }
81 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
82 87
88 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
83 path_put(&nd.path); 89 path_put(&nd.path);
84 return err; 90 return err;
85} 91}
86 92
87static int create_path(const char *nodepath) 93static int create_path(const char *nodepath)
88{ 94{
89 char *path; 95 int err;
90 struct nameidata nd;
91 int err = 0;
92
93 path = kstrdup(nodepath, GFP_KERNEL);
94 if (!path)
95 return -ENOMEM;
96
97 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
98 path, LOOKUP_PARENT, &nd);
99 if (err == 0) {
100 struct dentry *dentry;
101
102 /* create directory right away */
103 dentry = lookup_create(&nd, 1);
104 if (!IS_ERR(dentry)) {
105 err = vfs_mkdir(nd.path.dentry->d_inode,
106 dentry, 0755);
107 dput(dentry);
108 }
109 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
110 96
111 path_put(&nd.path); 97 mutex_lock(&dirlock);
112 } else if (err == -ENOENT) { 98 err = dev_mkdir(nodepath, 0755);
99 if (err == -ENOENT) {
100 char *path;
113 char *s; 101 char *s;
114 102
115 /* parent directories do not exist, create them */ 103 /* parent directories do not exist, create them */
104 path = kstrdup(nodepath, GFP_KERNEL);
105 if (!path) {
106 err = -ENOMEM;
107 goto out;
108 }
116 s = path; 109 s = path;
117 while (1) { 110 for (;;) {
118 s = strchr(s, '/'); 111 s = strchr(s, '/');
119 if (!s) 112 if (!s)
120 break; 113 break;
@@ -125,9 +118,10 @@ static int create_path(const char *nodepath)
125 s[0] = '/'; 118 s[0] = '/';
126 s++; 119 s++;
127 } 120 }
121 kfree(path);
128 } 122 }
129 123out:
130 kfree(path); 124 mutex_unlock(&dirlock);
131 return err; 125 return err;
132} 126}
133 127
@@ -156,34 +150,40 @@ int devtmpfs_create_node(struct device *dev)
156 mode |= S_IFCHR; 150 mode |= S_IFCHR;
157 151
158 curr_cred = override_creds(&init_cred); 152 curr_cred = override_creds(&init_cred);
153
159 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, 154 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
160 nodename, LOOKUP_PARENT, &nd); 155 nodename, LOOKUP_PARENT, &nd);
161 if (err == -ENOENT) { 156 if (err == -ENOENT) {
162 /* create missing parent directories */
163 create_path(nodename); 157 create_path(nodename);
164 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, 158 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
165 nodename, LOOKUP_PARENT, &nd); 159 nodename, LOOKUP_PARENT, &nd);
166 if (err)
167 goto out;
168 } 160 }
161 if (err)
162 goto out;
169 163
170 dentry = lookup_create(&nd, 0); 164 dentry = lookup_create(&nd, 0);
171 if (!IS_ERR(dentry)) { 165 if (!IS_ERR(dentry)) {
172 int umask;
173
174 umask = sys_umask(0000);
175 err = vfs_mknod(nd.path.dentry->d_inode, 166 err = vfs_mknod(nd.path.dentry->d_inode,
176 dentry, mode, dev->devt); 167 dentry, mode, dev->devt);
177 sys_umask(umask); 168 if (!err) {
178 /* mark as kernel created inode */ 169 struct iattr newattrs;
179 if (!err) 170
171 /* fixup possibly umasked mode */
172 newattrs.ia_mode = mode;
173 newattrs.ia_valid = ATTR_MODE;
174 mutex_lock(&dentry->d_inode->i_mutex);
175 notify_change(dentry, &newattrs);
176 mutex_unlock(&dentry->d_inode->i_mutex);
177
178 /* mark as kernel-created inode */
180 dentry->d_inode->i_private = &dev_mnt; 179 dentry->d_inode->i_private = &dev_mnt;
180 }
181 dput(dentry); 181 dput(dentry);
182 } else { 182 } else {
183 err = PTR_ERR(dentry); 183 err = PTR_ERR(dentry);
184 } 184 }
185 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
186 185
186 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
187 path_put(&nd.path); 187 path_put(&nd.path);
188out: 188out:
189 kfree(tmp); 189 kfree(tmp);
@@ -205,16 +205,21 @@ static int dev_rmdir(const char *name)
205 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); 205 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
206 dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); 206 dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
207 if (!IS_ERR(dentry)) { 207 if (!IS_ERR(dentry)) {
208 if (dentry->d_inode) 208 if (dentry->d_inode) {
209 err = vfs_rmdir(nd.path.dentry->d_inode, dentry); 209 if (dentry->d_inode->i_private == &dev_mnt)
210 else 210 err = vfs_rmdir(nd.path.dentry->d_inode,
211 dentry);
212 else
213 err = -EPERM;
214 } else {
211 err = -ENOENT; 215 err = -ENOENT;
216 }
212 dput(dentry); 217 dput(dentry);
213 } else { 218 } else {
214 err = PTR_ERR(dentry); 219 err = PTR_ERR(dentry);
215 } 220 }
216 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
217 221
222 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
218 path_put(&nd.path); 223 path_put(&nd.path);
219 return err; 224 return err;
220} 225}
@@ -228,7 +233,8 @@ static int delete_path(const char *nodepath)
228 if (!path) 233 if (!path)
229 return -ENOMEM; 234 return -ENOMEM;
230 235
231 while (1) { 236 mutex_lock(&dirlock);
237 for (;;) {
232 char *base; 238 char *base;
233 239
234 base = strrchr(path, '/'); 240 base = strrchr(path, '/');
@@ -239,6 +245,7 @@ static int delete_path(const char *nodepath)
239 if (err) 245 if (err)
240 break; 246 break;
241 } 247 }
248 mutex_unlock(&dirlock);
242 249
243 kfree(path); 250 kfree(path);
244 return err; 251 return err;
@@ -295,6 +302,19 @@ int devtmpfs_delete_node(struct device *dev)
295 if (dentry->d_inode) { 302 if (dentry->d_inode) {
296 err = vfs_getattr(nd.path.mnt, dentry, &stat); 303 err = vfs_getattr(nd.path.mnt, dentry, &stat);
297 if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { 304 if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
305 struct iattr newattrs;
306 /*
307 * before unlinking this node, reset permissions
308 * of possible references like hardlinks
309 */
310 newattrs.ia_uid = 0;
311 newattrs.ia_gid = 0;
312 newattrs.ia_mode = stat.mode & ~0777;
313 newattrs.ia_valid =
314 ATTR_UID|ATTR_GID|ATTR_MODE;
315 mutex_lock(&dentry->d_inode->i_mutex);
316 notify_change(dentry, &newattrs);
317 mutex_unlock(&dentry->d_inode->i_mutex);
298 err = vfs_unlink(nd.path.dentry->d_inode, 318 err = vfs_unlink(nd.path.dentry->d_inode,
299 dentry); 319 dentry);
300 if (!err || err == -ENOENT) 320 if (!err || err == -ENOENT)
@@ -322,9 +342,8 @@ out:
322 * If configured, or requested by the commandline, devtmpfs will be 342 * If configured, or requested by the commandline, devtmpfs will be
323 * auto-mounted after the kernel mounted the root filesystem. 343 * auto-mounted after the kernel mounted the root filesystem.
324 */ 344 */
325int devtmpfs_mount(const char *mountpoint) 345int devtmpfs_mount(const char *mntdir)
326{ 346{
327 struct path path;
328 int err; 347 int err;
329 348
330 if (!dev_mount) 349 if (!dev_mount)
@@ -333,15 +352,11 @@ int devtmpfs_mount(const char *mountpoint)
333 if (!dev_mnt) 352 if (!dev_mnt)
334 return 0; 353 return 0;
335 354
336 err = kern_path(mountpoint, LOOKUP_FOLLOW, &path); 355 err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
337 if (err)
338 return err;
339 err = do_add_mount(dev_mnt, &path, 0, NULL);
340 if (err) 356 if (err)
341 printk(KERN_INFO "devtmpfs: error mounting %i\n", err); 357 printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
342 else 358 else
343 printk(KERN_INFO "devtmpfs: mounted\n"); 359 printk(KERN_INFO "devtmpfs: mounted\n");
344 path_put(&path);
345 return err; 360 return err;
346} 361}
347 362
@@ -353,6 +368,7 @@ int __init devtmpfs_init(void)
353{ 368{
354 int err; 369 int err;
355 struct vfsmount *mnt; 370 struct vfsmount *mnt;
371 char options[] = "mode=0755";
356 372
357 err = register_filesystem(&dev_fs_type); 373 err = register_filesystem(&dev_fs_type);
358 if (err) { 374 if (err) {
@@ -361,7 +377,7 @@ int __init devtmpfs_init(void)
361 return err; 377 return err;
362 } 378 }
363 379
364 mnt = kern_mount(&dev_fs_type); 380 mnt = kern_mount_data(&dev_fs_type, options);
365 if (IS_ERR(mnt)) { 381 if (IS_ERR(mnt)) {
366 err = PTR_ERR(mnt); 382 err = PTR_ERR(mnt);
367 printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); 383 printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);