Commit 8dac6bee32425dd5145b40fa2307648cb7fb4d4a
Exists in
master
and in
4 other branches
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: AFS: Use i_generation not i_version for the vnode uniquifier AFS: Set s_id in the superblock to the volume name vfs: Fix data corruption after failed write in __block_write_begin() afs: afs_fill_page reads too much, or wrong data VFS: Fix vfsmount overput on simultaneous automount fix wrong iput on d_inode introduced by e6bc45d65d Delay struct net freeing while there's a sysfs instance refering to it afs: fix sget() races, close leak on umount ubifs: fix sget races ubifs: split allocation of ubifs_info into a separate function fix leak in proc_set_super()
Showing 17 changed files Side-by-side Diff
- fs/afs/dir.c
- fs/afs/fsclient.c
- fs/afs/inode.c
- fs/afs/super.c
- fs/afs/write.c
- fs/buffer.c
- fs/namei.c
- fs/proc/root.c
- fs/sysfs/mount.c
- fs/sysfs/sysfs.h
- fs/ubifs/super.c
- include/linux/kobject_ns.h
- include/linux/sysfs.h
- include/net/net_namespace.h
- lib/kobject.c
- net/core/net-sysfs.c
- net/core/net_namespace.c
fs/afs/dir.c
... | ... | @@ -584,11 +584,11 @@ |
584 | 584 | |
585 | 585 | success: |
586 | 586 | d_add(dentry, inode); |
587 | - _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%llu }", | |
587 | + _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }", | |
588 | 588 | fid.vnode, |
589 | 589 | fid.unique, |
590 | 590 | dentry->d_inode->i_ino, |
591 | - (unsigned long long)dentry->d_inode->i_version); | |
591 | + dentry->d_inode->i_generation); | |
592 | 592 | |
593 | 593 | return NULL; |
594 | 594 | } |
595 | 595 | |
... | ... | @@ -671,10 +671,10 @@ |
671 | 671 | * been deleted and replaced, and the original vnode ID has |
672 | 672 | * been reused */ |
673 | 673 | if (fid.unique != vnode->fid.unique) { |
674 | - _debug("%s: file deleted (uq %u -> %u I:%llu)", | |
674 | + _debug("%s: file deleted (uq %u -> %u I:%u)", | |
675 | 675 | dentry->d_name.name, fid.unique, |
676 | 676 | vnode->fid.unique, |
677 | - (unsigned long long)dentry->d_inode->i_version); | |
677 | + dentry->d_inode->i_generation); | |
678 | 678 | spin_lock(&vnode->lock); |
679 | 679 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
680 | 680 | spin_unlock(&vnode->lock); |
fs/afs/fsclient.c
... | ... | @@ -89,7 +89,7 @@ |
89 | 89 | i_size_write(&vnode->vfs_inode, size); |
90 | 90 | vnode->vfs_inode.i_uid = status->owner; |
91 | 91 | vnode->vfs_inode.i_gid = status->group; |
92 | - vnode->vfs_inode.i_version = vnode->fid.unique; | |
92 | + vnode->vfs_inode.i_generation = vnode->fid.unique; | |
93 | 93 | vnode->vfs_inode.i_nlink = status->nlink; |
94 | 94 | |
95 | 95 | mode = vnode->vfs_inode.i_mode; |
... | ... | @@ -102,6 +102,7 @@ |
102 | 102 | vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server; |
103 | 103 | vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; |
104 | 104 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; |
105 | + vnode->vfs_inode.i_version = data_version; | |
105 | 106 | } |
106 | 107 | |
107 | 108 | expected_version = status->data_version; |
fs/afs/inode.c
... | ... | @@ -75,7 +75,8 @@ |
75 | 75 | inode->i_ctime.tv_nsec = 0; |
76 | 76 | inode->i_atime = inode->i_mtime = inode->i_ctime; |
77 | 77 | inode->i_blocks = 0; |
78 | - inode->i_version = vnode->fid.unique; | |
78 | + inode->i_generation = vnode->fid.unique; | |
79 | + inode->i_version = vnode->status.data_version; | |
79 | 80 | inode->i_mapping->a_ops = &afs_fs_aops; |
80 | 81 | |
81 | 82 | /* check to see whether a symbolic link is really a mountpoint */ |
... | ... | @@ -100,7 +101,7 @@ |
100 | 101 | struct afs_iget_data *data = opaque; |
101 | 102 | |
102 | 103 | return inode->i_ino == data->fid.vnode && |
103 | - inode->i_version == data->fid.unique; | |
104 | + inode->i_generation == data->fid.unique; | |
104 | 105 | } |
105 | 106 | |
106 | 107 | /* |
... | ... | @@ -122,7 +123,7 @@ |
122 | 123 | struct afs_vnode *vnode = AFS_FS_I(inode); |
123 | 124 | |
124 | 125 | inode->i_ino = data->fid.vnode; |
125 | - inode->i_version = data->fid.unique; | |
126 | + inode->i_generation = data->fid.unique; | |
126 | 127 | vnode->fid = data->fid; |
127 | 128 | vnode->volume = data->volume; |
128 | 129 | |
... | ... | @@ -380,8 +381,7 @@ |
380 | 381 | |
381 | 382 | inode = dentry->d_inode; |
382 | 383 | |
383 | - _enter("{ ino=%lu v=%llu }", inode->i_ino, | |
384 | - (unsigned long long)inode->i_version); | |
384 | + _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation); | |
385 | 385 | |
386 | 386 | generic_fillattr(inode, stat); |
387 | 387 | return 0; |
fs/afs/super.c
... | ... | @@ -31,8 +31,8 @@ |
31 | 31 | static void afs_i_init_once(void *foo); |
32 | 32 | static struct dentry *afs_mount(struct file_system_type *fs_type, |
33 | 33 | int flags, const char *dev_name, void *data); |
34 | +static void afs_kill_super(struct super_block *sb); | |
34 | 35 | static struct inode *afs_alloc_inode(struct super_block *sb); |
35 | -static void afs_put_super(struct super_block *sb); | |
36 | 36 | static void afs_destroy_inode(struct inode *inode); |
37 | 37 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); |
38 | 38 | |
... | ... | @@ -40,7 +40,7 @@ |
40 | 40 | .owner = THIS_MODULE, |
41 | 41 | .name = "afs", |
42 | 42 | .mount = afs_mount, |
43 | - .kill_sb = kill_anon_super, | |
43 | + .kill_sb = afs_kill_super, | |
44 | 44 | .fs_flags = 0, |
45 | 45 | }; |
46 | 46 | |
... | ... | @@ -50,7 +50,6 @@ |
50 | 50 | .drop_inode = afs_drop_inode, |
51 | 51 | .destroy_inode = afs_destroy_inode, |
52 | 52 | .evict_inode = afs_evict_inode, |
53 | - .put_super = afs_put_super, | |
54 | 53 | .show_options = generic_show_options, |
55 | 54 | }; |
56 | 55 | |
57 | 56 | |
58 | 57 | |
59 | 58 | |
60 | 59 | |
... | ... | @@ -282,19 +281,25 @@ |
282 | 281 | */ |
283 | 282 | static int afs_test_super(struct super_block *sb, void *data) |
284 | 283 | { |
285 | - struct afs_mount_params *params = data; | |
284 | + struct afs_super_info *as1 = data; | |
286 | 285 | struct afs_super_info *as = sb->s_fs_info; |
287 | 286 | |
288 | - return as->volume == params->volume; | |
287 | + return as->volume == as1->volume; | |
289 | 288 | } |
290 | 289 | |
290 | +static int afs_set_super(struct super_block *sb, void *data) | |
291 | +{ | |
292 | + sb->s_fs_info = data; | |
293 | + return set_anon_super(sb, NULL); | |
294 | +} | |
295 | + | |
291 | 296 | /* |
292 | 297 | * fill in the superblock |
293 | 298 | */ |
294 | -static int afs_fill_super(struct super_block *sb, void *data) | |
299 | +static int afs_fill_super(struct super_block *sb, | |
300 | + struct afs_mount_params *params) | |
295 | 301 | { |
296 | - struct afs_mount_params *params = data; | |
297 | - struct afs_super_info *as = NULL; | |
302 | + struct afs_super_info *as = sb->s_fs_info; | |
298 | 303 | struct afs_fid fid; |
299 | 304 | struct dentry *root = NULL; |
300 | 305 | struct inode *inode = NULL; |
301 | 306 | |
302 | 307 | |
... | ... | @@ -302,23 +307,13 @@ |
302 | 307 | |
303 | 308 | _enter(""); |
304 | 309 | |
305 | - /* allocate a superblock info record */ | |
306 | - as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); | |
307 | - if (!as) { | |
308 | - _leave(" = -ENOMEM"); | |
309 | - return -ENOMEM; | |
310 | - } | |
311 | - | |
312 | - afs_get_volume(params->volume); | |
313 | - as->volume = params->volume; | |
314 | - | |
315 | 310 | /* fill in the superblock */ |
316 | 311 | sb->s_blocksize = PAGE_CACHE_SIZE; |
317 | 312 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
318 | 313 | sb->s_magic = AFS_FS_MAGIC; |
319 | 314 | sb->s_op = &afs_super_ops; |
320 | - sb->s_fs_info = as; | |
321 | 315 | sb->s_bdi = &as->volume->bdi; |
316 | + strlcpy(sb->s_id, as->volume->vlocation->vldb.name, sizeof(sb->s_id)); | |
322 | 317 | |
323 | 318 | /* allocate the root inode and dentry */ |
324 | 319 | fid.vid = as->volume->vid; |
... | ... | @@ -326,7 +321,7 @@ |
326 | 321 | fid.unique = 1; |
327 | 322 | inode = afs_iget(sb, params->key, &fid, NULL, NULL); |
328 | 323 | if (IS_ERR(inode)) |
329 | - goto error_inode; | |
324 | + return PTR_ERR(inode); | |
330 | 325 | |
331 | 326 | if (params->autocell) |
332 | 327 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); |
333 | 328 | |
... | ... | @@ -342,16 +337,8 @@ |
342 | 337 | _leave(" = 0"); |
343 | 338 | return 0; |
344 | 339 | |
345 | -error_inode: | |
346 | - ret = PTR_ERR(inode); | |
347 | - inode = NULL; | |
348 | 340 | error: |
349 | 341 | iput(inode); |
350 | - afs_put_volume(as->volume); | |
351 | - kfree(as); | |
352 | - | |
353 | - sb->s_fs_info = NULL; | |
354 | - | |
355 | 342 | _leave(" = %d", ret); |
356 | 343 | return ret; |
357 | 344 | } |
... | ... | @@ -367,6 +354,7 @@ |
367 | 354 | struct afs_volume *vol; |
368 | 355 | struct key *key; |
369 | 356 | char *new_opts = kstrdup(options, GFP_KERNEL); |
357 | + struct afs_super_info *as; | |
370 | 358 | int ret; |
371 | 359 | |
372 | 360 | _enter(",,%s,%p", dev_name, options); |
373 | 361 | |
374 | 362 | |
375 | 363 | |
... | ... | @@ -399,12 +387,22 @@ |
399 | 387 | ret = PTR_ERR(vol); |
400 | 388 | goto error; |
401 | 389 | } |
402 | - params.volume = vol; | |
403 | 390 | |
391 | + /* allocate a superblock info record */ | |
392 | + as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); | |
393 | + if (!as) { | |
394 | + ret = -ENOMEM; | |
395 | + afs_put_volume(vol); | |
396 | + goto error; | |
397 | + } | |
398 | + as->volume = vol; | |
399 | + | |
404 | 400 | /* allocate a deviceless superblock */ |
405 | - sb = sget(fs_type, afs_test_super, set_anon_super, ¶ms); | |
401 | + sb = sget(fs_type, afs_test_super, afs_set_super, as); | |
406 | 402 | if (IS_ERR(sb)) { |
407 | 403 | ret = PTR_ERR(sb); |
404 | + afs_put_volume(vol); | |
405 | + kfree(as); | |
408 | 406 | goto error; |
409 | 407 | } |
410 | 408 | |
411 | 409 | |
412 | 410 | |
... | ... | @@ -422,16 +420,16 @@ |
422 | 420 | } else { |
423 | 421 | _debug("reuse"); |
424 | 422 | ASSERTCMP(sb->s_flags, &, MS_ACTIVE); |
423 | + afs_put_volume(vol); | |
424 | + kfree(as); | |
425 | 425 | } |
426 | 426 | |
427 | - afs_put_volume(params.volume); | |
428 | 427 | afs_put_cell(params.cell); |
429 | 428 | kfree(new_opts); |
430 | 429 | _leave(" = 0 [%p]", sb); |
431 | 430 | return dget(sb->s_root); |
432 | 431 | |
433 | 432 | error: |
434 | - afs_put_volume(params.volume); | |
435 | 433 | afs_put_cell(params.cell); |
436 | 434 | key_put(params.key); |
437 | 435 | kfree(new_opts); |
438 | 436 | |
439 | 437 | |
... | ... | @@ -439,18 +437,12 @@ |
439 | 437 | return ERR_PTR(ret); |
440 | 438 | } |
441 | 439 | |
442 | -/* | |
443 | - * finish the unmounting process on the superblock | |
444 | - */ | |
445 | -static void afs_put_super(struct super_block *sb) | |
440 | +static void afs_kill_super(struct super_block *sb) | |
446 | 441 | { |
447 | 442 | struct afs_super_info *as = sb->s_fs_info; |
448 | - | |
449 | - _enter(""); | |
450 | - | |
443 | + kill_anon_super(sb); | |
451 | 444 | afs_put_volume(as->volume); |
452 | - | |
453 | - _leave(""); | |
445 | + kfree(as); | |
454 | 446 | } |
455 | 447 | |
456 | 448 | /* |
fs/afs/write.c
... | ... | @@ -84,23 +84,21 @@ |
84 | 84 | * partly or wholly fill a page that's under preparation for writing |
85 | 85 | */ |
86 | 86 | static int afs_fill_page(struct afs_vnode *vnode, struct key *key, |
87 | - loff_t pos, unsigned len, struct page *page) | |
87 | + loff_t pos, struct page *page) | |
88 | 88 | { |
89 | 89 | loff_t i_size; |
90 | - unsigned eof; | |
91 | 90 | int ret; |
91 | + int len; | |
92 | 92 | |
93 | - _enter(",,%llu,%u", (unsigned long long)pos, len); | |
93 | + _enter(",,%llu", (unsigned long long)pos); | |
94 | 94 | |
95 | - ASSERTCMP(len, <=, PAGE_CACHE_SIZE); | |
96 | - | |
97 | 95 | i_size = i_size_read(&vnode->vfs_inode); |
98 | - if (pos + len > i_size) | |
99 | - eof = i_size; | |
96 | + if (pos + PAGE_CACHE_SIZE > i_size) | |
97 | + len = i_size - pos; | |
100 | 98 | else |
101 | - eof = PAGE_CACHE_SIZE; | |
99 | + len = PAGE_CACHE_SIZE; | |
102 | 100 | |
103 | - ret = afs_vnode_fetch_data(vnode, key, 0, eof, page); | |
101 | + ret = afs_vnode_fetch_data(vnode, key, pos, len, page); | |
104 | 102 | if (ret < 0) { |
105 | 103 | if (ret == -ENOENT) { |
106 | 104 | _debug("got NOENT from server" |
... | ... | @@ -153,9 +151,8 @@ |
153 | 151 | *pagep = page; |
154 | 152 | /* page won't leak in error case: it eventually gets cleaned off LRU */ |
155 | 153 | |
156 | - if (!PageUptodate(page)) { | |
157 | - _debug("not up to date"); | |
158 | - ret = afs_fill_page(vnode, key, pos, len, page); | |
154 | + if (!PageUptodate(page) && len != PAGE_CACHE_SIZE) { | |
155 | + ret = afs_fill_page(vnode, key, index << PAGE_CACHE_SHIFT, page); | |
159 | 156 | if (ret < 0) { |
160 | 157 | kfree(candidate); |
161 | 158 | _leave(" = %d [prep]", ret); |
fs/buffer.c
... | ... | @@ -1902,10 +1902,8 @@ |
1902 | 1902 | if (!buffer_uptodate(*wait_bh)) |
1903 | 1903 | err = -EIO; |
1904 | 1904 | } |
1905 | - if (unlikely(err)) { | |
1905 | + if (unlikely(err)) | |
1906 | 1906 | page_zero_new_buffers(page, from, to); |
1907 | - ClearPageUptodate(page); | |
1908 | - } | |
1909 | 1907 | return err; |
1910 | 1908 | } |
1911 | 1909 | EXPORT_SYMBOL(__block_write_begin); |
fs/namei.c
... | ... | @@ -812,6 +812,11 @@ |
812 | 812 | if (!mnt) /* mount collision */ |
813 | 813 | return 0; |
814 | 814 | |
815 | + if (!*need_mntput) { | |
816 | + /* lock_mount() may release path->mnt on error */ | |
817 | + mntget(path->mnt); | |
818 | + *need_mntput = true; | |
819 | + } | |
815 | 820 | err = finish_automount(mnt, path); |
816 | 821 | |
817 | 822 | switch (err) { |
818 | 823 | |
... | ... | @@ -819,12 +824,9 @@ |
819 | 824 | /* Someone else made a mount here whilst we were busy */ |
820 | 825 | return 0; |
821 | 826 | case 0: |
822 | - dput(path->dentry); | |
823 | - if (*need_mntput) | |
824 | - mntput(path->mnt); | |
827 | + path_put(path); | |
825 | 828 | path->mnt = mnt; |
826 | 829 | path->dentry = dget(mnt->mnt_root); |
827 | - *need_mntput = true; | |
828 | 830 | return 0; |
829 | 831 | default: |
830 | 832 | return err; |
831 | 833 | |
... | ... | @@ -844,9 +846,10 @@ |
844 | 846 | */ |
845 | 847 | static int follow_managed(struct path *path, unsigned flags) |
846 | 848 | { |
849 | + struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */ | |
847 | 850 | unsigned managed; |
848 | 851 | bool need_mntput = false; |
849 | - int ret; | |
852 | + int ret = 0; | |
850 | 853 | |
851 | 854 | /* Given that we're not holding a lock here, we retain the value in a |
852 | 855 | * local variable for each dentry as we look at it so that we don't see |
... | ... | @@ -861,7 +864,7 @@ |
861 | 864 | BUG_ON(!path->dentry->d_op->d_manage); |
862 | 865 | ret = path->dentry->d_op->d_manage(path->dentry, false); |
863 | 866 | if (ret < 0) |
864 | - return ret == -EISDIR ? 0 : ret; | |
867 | + break; | |
865 | 868 | } |
866 | 869 | |
867 | 870 | /* Transit to a mounted filesystem. */ |
868 | 871 | |
... | ... | @@ -887,14 +890,19 @@ |
887 | 890 | if (managed & DCACHE_NEED_AUTOMOUNT) { |
888 | 891 | ret = follow_automount(path, flags, &need_mntput); |
889 | 892 | if (ret < 0) |
890 | - return ret == -EISDIR ? 0 : ret; | |
893 | + break; | |
891 | 894 | continue; |
892 | 895 | } |
893 | 896 | |
894 | 897 | /* We didn't change the current path point */ |
895 | 898 | break; |
896 | 899 | } |
897 | - return 0; | |
900 | + | |
901 | + if (need_mntput && path->mnt == mnt) | |
902 | + mntput(path->mnt); | |
903 | + if (ret == -EISDIR) | |
904 | + ret = 0; | |
905 | + return ret; | |
898 | 906 | } |
899 | 907 | |
900 | 908 | int follow_down_one(struct path *path) |
901 | 909 | |
... | ... | @@ -2713,8 +2721,10 @@ |
2713 | 2721 | error = PTR_ERR(dentry); |
2714 | 2722 | if (!IS_ERR(dentry)) { |
2715 | 2723 | /* Why not before? Because we want correct error value */ |
2724 | + if (nd.last.name[nd.last.len]) | |
2725 | + goto slashes; | |
2716 | 2726 | inode = dentry->d_inode; |
2717 | - if (nd.last.name[nd.last.len] || !inode) | |
2727 | + if (!inode) | |
2718 | 2728 | goto slashes; |
2719 | 2729 | ihold(inode); |
2720 | 2730 | error = mnt_want_write(nd.path.mnt); |
fs/proc/root.c
... | ... | @@ -28,11 +28,12 @@ |
28 | 28 | |
29 | 29 | static int proc_set_super(struct super_block *sb, void *data) |
30 | 30 | { |
31 | - struct pid_namespace *ns; | |
32 | - | |
33 | - ns = (struct pid_namespace *)data; | |
34 | - sb->s_fs_info = get_pid_ns(ns); | |
35 | - return set_anon_super(sb, NULL); | |
31 | + int err = set_anon_super(sb, NULL); | |
32 | + if (!err) { | |
33 | + struct pid_namespace *ns = (struct pid_namespace *)data; | |
34 | + sb->s_fs_info = get_pid_ns(ns); | |
35 | + } | |
36 | + return err; | |
36 | 37 | } |
37 | 38 | |
38 | 39 | static struct dentry *proc_mount(struct file_system_type *fs_type, |
fs/sysfs/mount.c
... | ... | @@ -95,6 +95,14 @@ |
95 | 95 | return error; |
96 | 96 | } |
97 | 97 | |
98 | +static void free_sysfs_super_info(struct sysfs_super_info *info) | |
99 | +{ | |
100 | + int type; | |
101 | + for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) | |
102 | + kobj_ns_drop(type, info->ns[type]); | |
103 | + kfree(info); | |
104 | +} | |
105 | + | |
98 | 106 | static struct dentry *sysfs_mount(struct file_system_type *fs_type, |
99 | 107 | int flags, const char *dev_name, void *data) |
100 | 108 | { |
101 | 109 | |
... | ... | @@ -108,11 +116,11 @@ |
108 | 116 | return ERR_PTR(-ENOMEM); |
109 | 117 | |
110 | 118 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) |
111 | - info->ns[type] = kobj_ns_current(type); | |
119 | + info->ns[type] = kobj_ns_grab_current(type); | |
112 | 120 | |
113 | 121 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info); |
114 | 122 | if (IS_ERR(sb) || sb->s_fs_info != info) |
115 | - kfree(info); | |
123 | + free_sysfs_super_info(info); | |
116 | 124 | if (IS_ERR(sb)) |
117 | 125 | return ERR_CAST(sb); |
118 | 126 | if (!sb->s_root) { |
119 | 127 | |
... | ... | @@ -131,12 +139,11 @@ |
131 | 139 | static void sysfs_kill_sb(struct super_block *sb) |
132 | 140 | { |
133 | 141 | struct sysfs_super_info *info = sysfs_info(sb); |
134 | - | |
135 | 142 | /* Remove the superblock from fs_supers/s_instances |
136 | 143 | * so we can't find it, before freeing sysfs_super_info. |
137 | 144 | */ |
138 | 145 | kill_anon_super(sb); |
139 | - kfree(info); | |
146 | + free_sysfs_super_info(info); | |
140 | 147 | } |
141 | 148 | |
142 | 149 | static struct file_system_type sysfs_fs_type = { |
... | ... | @@ -144,28 +151,6 @@ |
144 | 151 | .mount = sysfs_mount, |
145 | 152 | .kill_sb = sysfs_kill_sb, |
146 | 153 | }; |
147 | - | |
148 | -void sysfs_exit_ns(enum kobj_ns_type type, const void *ns) | |
149 | -{ | |
150 | - struct super_block *sb; | |
151 | - | |
152 | - mutex_lock(&sysfs_mutex); | |
153 | - spin_lock(&sb_lock); | |
154 | - list_for_each_entry(sb, &sysfs_fs_type.fs_supers, s_instances) { | |
155 | - struct sysfs_super_info *info = sysfs_info(sb); | |
156 | - /* | |
157 | - * If we see a superblock on the fs_supers/s_instances | |
158 | - * list the unmount has not completed and sb->s_fs_info | |
159 | - * points to a valid struct sysfs_super_info. | |
160 | - */ | |
161 | - /* Ignore superblocks with the wrong ns */ | |
162 | - if (info->ns[type] != ns) | |
163 | - continue; | |
164 | - info->ns[type] = NULL; | |
165 | - } | |
166 | - spin_unlock(&sb_lock); | |
167 | - mutex_unlock(&sysfs_mutex); | |
168 | -} | |
169 | 154 | |
170 | 155 | int __init sysfs_init(void) |
171 | 156 | { |
fs/sysfs/sysfs.h
fs/ubifs/super.c
... | ... | @@ -1848,7 +1848,6 @@ |
1848 | 1848 | bdi_destroy(&c->bdi); |
1849 | 1849 | ubi_close_volume(c->ubi); |
1850 | 1850 | mutex_unlock(&c->umount_mutex); |
1851 | - kfree(c); | |
1852 | 1851 | } |
1853 | 1852 | |
1854 | 1853 | static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) |
1855 | 1854 | |
1856 | 1855 | |
1857 | 1856 | |
1858 | 1857 | |
1859 | 1858 | |
1860 | 1859 | |
1861 | 1860 | |
1862 | 1861 | |
... | ... | @@ -1971,61 +1970,65 @@ |
1971 | 1970 | return ERR_PTR(-EINVAL); |
1972 | 1971 | } |
1973 | 1972 | |
1974 | -static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |
1973 | +static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi) | |
1975 | 1974 | { |
1976 | - struct ubi_volume_desc *ubi = sb->s_fs_info; | |
1977 | 1975 | struct ubifs_info *c; |
1978 | - struct inode *root; | |
1979 | - int err; | |
1980 | 1976 | |
1981 | 1977 | c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL); |
1982 | - if (!c) | |
1983 | - return -ENOMEM; | |
1978 | + if (c) { | |
1979 | + spin_lock_init(&c->cnt_lock); | |
1980 | + spin_lock_init(&c->cs_lock); | |
1981 | + spin_lock_init(&c->buds_lock); | |
1982 | + spin_lock_init(&c->space_lock); | |
1983 | + spin_lock_init(&c->orphan_lock); | |
1984 | + init_rwsem(&c->commit_sem); | |
1985 | + mutex_init(&c->lp_mutex); | |
1986 | + mutex_init(&c->tnc_mutex); | |
1987 | + mutex_init(&c->log_mutex); | |
1988 | + mutex_init(&c->mst_mutex); | |
1989 | + mutex_init(&c->umount_mutex); | |
1990 | + mutex_init(&c->bu_mutex); | |
1991 | + mutex_init(&c->write_reserve_mutex); | |
1992 | + init_waitqueue_head(&c->cmt_wq); | |
1993 | + c->buds = RB_ROOT; | |
1994 | + c->old_idx = RB_ROOT; | |
1995 | + c->size_tree = RB_ROOT; | |
1996 | + c->orph_tree = RB_ROOT; | |
1997 | + INIT_LIST_HEAD(&c->infos_list); | |
1998 | + INIT_LIST_HEAD(&c->idx_gc); | |
1999 | + INIT_LIST_HEAD(&c->replay_list); | |
2000 | + INIT_LIST_HEAD(&c->replay_buds); | |
2001 | + INIT_LIST_HEAD(&c->uncat_list); | |
2002 | + INIT_LIST_HEAD(&c->empty_list); | |
2003 | + INIT_LIST_HEAD(&c->freeable_list); | |
2004 | + INIT_LIST_HEAD(&c->frdi_idx_list); | |
2005 | + INIT_LIST_HEAD(&c->unclean_leb_list); | |
2006 | + INIT_LIST_HEAD(&c->old_buds); | |
2007 | + INIT_LIST_HEAD(&c->orph_list); | |
2008 | + INIT_LIST_HEAD(&c->orph_new); | |
2009 | + c->no_chk_data_crc = 1; | |
1984 | 2010 | |
1985 | - spin_lock_init(&c->cnt_lock); | |
1986 | - spin_lock_init(&c->cs_lock); | |
1987 | - spin_lock_init(&c->buds_lock); | |
1988 | - spin_lock_init(&c->space_lock); | |
1989 | - spin_lock_init(&c->orphan_lock); | |
1990 | - init_rwsem(&c->commit_sem); | |
1991 | - mutex_init(&c->lp_mutex); | |
1992 | - mutex_init(&c->tnc_mutex); | |
1993 | - mutex_init(&c->log_mutex); | |
1994 | - mutex_init(&c->mst_mutex); | |
1995 | - mutex_init(&c->umount_mutex); | |
1996 | - mutex_init(&c->bu_mutex); | |
1997 | - mutex_init(&c->write_reserve_mutex); | |
1998 | - init_waitqueue_head(&c->cmt_wq); | |
1999 | - c->buds = RB_ROOT; | |
2000 | - c->old_idx = RB_ROOT; | |
2001 | - c->size_tree = RB_ROOT; | |
2002 | - c->orph_tree = RB_ROOT; | |
2003 | - INIT_LIST_HEAD(&c->infos_list); | |
2004 | - INIT_LIST_HEAD(&c->idx_gc); | |
2005 | - INIT_LIST_HEAD(&c->replay_list); | |
2006 | - INIT_LIST_HEAD(&c->replay_buds); | |
2007 | - INIT_LIST_HEAD(&c->uncat_list); | |
2008 | - INIT_LIST_HEAD(&c->empty_list); | |
2009 | - INIT_LIST_HEAD(&c->freeable_list); | |
2010 | - INIT_LIST_HEAD(&c->frdi_idx_list); | |
2011 | - INIT_LIST_HEAD(&c->unclean_leb_list); | |
2012 | - INIT_LIST_HEAD(&c->old_buds); | |
2013 | - INIT_LIST_HEAD(&c->orph_list); | |
2014 | - INIT_LIST_HEAD(&c->orph_new); | |
2015 | - c->no_chk_data_crc = 1; | |
2011 | + c->highest_inum = UBIFS_FIRST_INO; | |
2012 | + c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; | |
2016 | 2013 | |
2017 | - c->vfs_sb = sb; | |
2018 | - c->highest_inum = UBIFS_FIRST_INO; | |
2019 | - c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; | |
2014 | + ubi_get_volume_info(ubi, &c->vi); | |
2015 | + ubi_get_device_info(c->vi.ubi_num, &c->di); | |
2016 | + } | |
2017 | + return c; | |
2018 | +} | |
2020 | 2019 | |
2021 | - ubi_get_volume_info(ubi, &c->vi); | |
2022 | - ubi_get_device_info(c->vi.ubi_num, &c->di); | |
2020 | +static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |
2021 | +{ | |
2022 | + struct ubifs_info *c = sb->s_fs_info; | |
2023 | + struct inode *root; | |
2024 | + int err; | |
2023 | 2025 | |
2026 | + c->vfs_sb = sb; | |
2024 | 2027 | /* Re-open the UBI device in read-write mode */ |
2025 | 2028 | c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); |
2026 | 2029 | if (IS_ERR(c->ubi)) { |
2027 | 2030 | err = PTR_ERR(c->ubi); |
2028 | - goto out_free; | |
2031 | + goto out; | |
2029 | 2032 | } |
2030 | 2033 | |
2031 | 2034 | /* |
2032 | 2035 | |
2033 | 2036 | |
2034 | 2037 | |
2035 | 2038 | |
... | ... | @@ -2091,24 +2094,29 @@ |
2091 | 2094 | bdi_destroy(&c->bdi); |
2092 | 2095 | out_close: |
2093 | 2096 | ubi_close_volume(c->ubi); |
2094 | -out_free: | |
2095 | - kfree(c); | |
2097 | +out: | |
2096 | 2098 | return err; |
2097 | 2099 | } |
2098 | 2100 | |
2099 | 2101 | static int sb_test(struct super_block *sb, void *data) |
2100 | 2102 | { |
2101 | - dev_t *dev = data; | |
2103 | + struct ubifs_info *c1 = data; | |
2102 | 2104 | struct ubifs_info *c = sb->s_fs_info; |
2103 | 2105 | |
2104 | - return c->vi.cdev == *dev; | |
2106 | + return c->vi.cdev == c1->vi.cdev; | |
2105 | 2107 | } |
2106 | 2108 | |
2109 | +static int sb_set(struct super_block *sb, void *data) | |
2110 | +{ | |
2111 | + sb->s_fs_info = data; | |
2112 | + return set_anon_super(sb, NULL); | |
2113 | +} | |
2114 | + | |
2107 | 2115 | static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, |
2108 | 2116 | const char *name, void *data) |
2109 | 2117 | { |
2110 | 2118 | struct ubi_volume_desc *ubi; |
2111 | - struct ubi_volume_info vi; | |
2119 | + struct ubifs_info *c; | |
2112 | 2120 | struct super_block *sb; |
2113 | 2121 | int err; |
2114 | 2122 | |
2115 | 2123 | |
2116 | 2124 | |
2117 | 2125 | |
2118 | 2126 | |
... | ... | @@ -2125,19 +2133,24 @@ |
2125 | 2133 | name, (int)PTR_ERR(ubi)); |
2126 | 2134 | return ERR_CAST(ubi); |
2127 | 2135 | } |
2128 | - ubi_get_volume_info(ubi, &vi); | |
2129 | 2136 | |
2130 | - dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id); | |
2137 | + c = alloc_ubifs_info(ubi); | |
2138 | + if (!c) { | |
2139 | + err = -ENOMEM; | |
2140 | + goto out_close; | |
2141 | + } | |
2131 | 2142 | |
2132 | - sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev); | |
2143 | + dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); | |
2144 | + | |
2145 | + sb = sget(fs_type, sb_test, sb_set, c); | |
2133 | 2146 | if (IS_ERR(sb)) { |
2134 | 2147 | err = PTR_ERR(sb); |
2135 | - goto out_close; | |
2148 | + kfree(c); | |
2136 | 2149 | } |
2137 | 2150 | |
2138 | 2151 | if (sb->s_root) { |
2139 | 2152 | struct ubifs_info *c1 = sb->s_fs_info; |
2140 | - | |
2153 | + kfree(c); | |
2141 | 2154 | /* A new mount point for already mounted UBIFS */ |
2142 | 2155 | dbg_gen("this ubi volume is already mounted"); |
2143 | 2156 | if (!!(flags & MS_RDONLY) != c1->ro_mount) { |
... | ... | @@ -2146,11 +2159,6 @@ |
2146 | 2159 | } |
2147 | 2160 | } else { |
2148 | 2161 | sb->s_flags = flags; |
2149 | - /* | |
2150 | - * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is | |
2151 | - * replaced by 'c'. | |
2152 | - */ | |
2153 | - sb->s_fs_info = ubi; | |
2154 | 2162 | err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); |
2155 | 2163 | if (err) |
2156 | 2164 | goto out_deact; |
2157 | 2165 | |
... | ... | @@ -2170,11 +2178,18 @@ |
2170 | 2178 | return ERR_PTR(err); |
2171 | 2179 | } |
2172 | 2180 | |
2181 | +static void kill_ubifs_super(struct super_block *s) | |
2182 | +{ | |
2183 | + struct ubifs_info *c = s->s_fs_info; | |
2184 | + kill_anon_super(s); | |
2185 | + kfree(c); | |
2186 | +} | |
2187 | + | |
2173 | 2188 | static struct file_system_type ubifs_fs_type = { |
2174 | 2189 | .name = "ubifs", |
2175 | 2190 | .owner = THIS_MODULE, |
2176 | 2191 | .mount = ubifs_mount, |
2177 | - .kill_sb = kill_anon_super, | |
2192 | + .kill_sb = kill_ubifs_super, | |
2178 | 2193 | }; |
2179 | 2194 | |
2180 | 2195 | /* |
include/linux/kobject_ns.h
... | ... | @@ -32,15 +32,17 @@ |
32 | 32 | |
33 | 33 | /* |
34 | 34 | * Callbacks so sysfs can determine namespaces |
35 | - * @current_ns: return calling task's namespace | |
35 | + * @grab_current_ns: return a new reference to calling task's namespace | |
36 | 36 | * @netlink_ns: return namespace to which a sock belongs (right?) |
37 | 37 | * @initial_ns: return the initial namespace (i.e. init_net_ns) |
38 | + * @drop_ns: drops a reference to namespace | |
38 | 39 | */ |
39 | 40 | struct kobj_ns_type_operations { |
40 | 41 | enum kobj_ns_type type; |
41 | - const void *(*current_ns)(void); | |
42 | + void *(*grab_current_ns)(void); | |
42 | 43 | const void *(*netlink_ns)(struct sock *sk); |
43 | 44 | const void *(*initial_ns)(void); |
45 | + void (*drop_ns)(void *); | |
44 | 46 | }; |
45 | 47 | |
46 | 48 | int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); |
47 | 49 | |
... | ... | @@ -48,10 +50,10 @@ |
48 | 50 | const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); |
49 | 51 | const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); |
50 | 52 | |
51 | -const void *kobj_ns_current(enum kobj_ns_type type); | |
53 | +void *kobj_ns_grab_current(enum kobj_ns_type type); | |
52 | 54 | const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); |
53 | 55 | const void *kobj_ns_initial(enum kobj_ns_type type); |
54 | -void kobj_ns_exit(enum kobj_ns_type type, const void *ns); | |
56 | +void kobj_ns_drop(enum kobj_ns_type type, void *ns); | |
55 | 57 | |
56 | 58 | #endif /* _LINUX_KOBJECT_NS_H */ |
include/linux/sysfs.h
... | ... | @@ -177,9 +177,6 @@ |
177 | 177 | struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); |
178 | 178 | void sysfs_put(struct sysfs_dirent *sd); |
179 | 179 | |
180 | -/* Called to clear a ns tag when it is no longer valid */ | |
181 | -void sysfs_exit_ns(enum kobj_ns_type type, const void *tag); | |
182 | - | |
183 | 180 | int __must_check sysfs_init(void); |
184 | 181 | |
185 | 182 | #else /* CONFIG_SYSFS */ |
... | ... | @@ -335,10 +332,6 @@ |
335 | 332 | return NULL; |
336 | 333 | } |
337 | 334 | static inline void sysfs_put(struct sysfs_dirent *sd) |
338 | -{ | |
339 | -} | |
340 | - | |
341 | -static inline void sysfs_exit_ns(int type, const void *tag) | |
342 | 335 | { |
343 | 336 | } |
344 | 337 |
include/net/net_namespace.h
... | ... | @@ -35,8 +35,11 @@ |
35 | 35 | #define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) |
36 | 36 | |
37 | 37 | struct net { |
38 | + atomic_t passive; /* To decided when the network | |
39 | + * namespace should be freed. | |
40 | + */ | |
38 | 41 | atomic_t count; /* To decided when the network |
39 | - * namespace should be freed. | |
42 | + * namespace should be shut down. | |
40 | 43 | */ |
41 | 44 | #ifdef NETNS_REFCNT_DEBUG |
42 | 45 | atomic_t use_count; /* To track references we |
... | ... | @@ -154,6 +157,9 @@ |
154 | 157 | { |
155 | 158 | return net1 == net2; |
156 | 159 | } |
160 | + | |
161 | +extern void net_drop_ns(void *); | |
162 | + | |
157 | 163 | #else |
158 | 164 | |
159 | 165 | static inline struct net *get_net(struct net *net) |
... | ... | @@ -175,6 +181,8 @@ |
175 | 181 | { |
176 | 182 | return 1; |
177 | 183 | } |
184 | + | |
185 | +#define net_drop_ns NULL | |
178 | 186 | #endif |
179 | 187 | |
180 | 188 |
lib/kobject.c
... | ... | @@ -948,14 +948,14 @@ |
948 | 948 | } |
949 | 949 | |
950 | 950 | |
951 | -const void *kobj_ns_current(enum kobj_ns_type type) | |
951 | +void *kobj_ns_grab_current(enum kobj_ns_type type) | |
952 | 952 | { |
953 | - const void *ns = NULL; | |
953 | + void *ns = NULL; | |
954 | 954 | |
955 | 955 | spin_lock(&kobj_ns_type_lock); |
956 | 956 | if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && |
957 | 957 | kobj_ns_ops_tbl[type]) |
958 | - ns = kobj_ns_ops_tbl[type]->current_ns(); | |
958 | + ns = kobj_ns_ops_tbl[type]->grab_current_ns(); | |
959 | 959 | spin_unlock(&kobj_ns_type_lock); |
960 | 960 | |
961 | 961 | return ns; |
962 | 962 | |
963 | 963 | |
... | ... | @@ -987,22 +987,14 @@ |
987 | 987 | return ns; |
988 | 988 | } |
989 | 989 | |
990 | -/* | |
991 | - * kobj_ns_exit - invalidate a namespace tag | |
992 | - * | |
993 | - * @type: the namespace type (i.e. KOBJ_NS_TYPE_NET) | |
994 | - * @ns: the actual namespace being invalidated | |
995 | - * | |
996 | - * This is called when a tag is no longer valid. For instance, | |
997 | - * when a network namespace exits, it uses this helper to | |
998 | - * make sure no sb's sysfs_info points to the now-invalidated | |
999 | - * netns. | |
1000 | - */ | |
1001 | -void kobj_ns_exit(enum kobj_ns_type type, const void *ns) | |
990 | +void kobj_ns_drop(enum kobj_ns_type type, void *ns) | |
1002 | 991 | { |
1003 | - sysfs_exit_ns(type, ns); | |
992 | + spin_lock(&kobj_ns_type_lock); | |
993 | + if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && | |
994 | + kobj_ns_ops_tbl[type] && kobj_ns_ops_tbl[type]->drop_ns) | |
995 | + kobj_ns_ops_tbl[type]->drop_ns(ns); | |
996 | + spin_unlock(&kobj_ns_type_lock); | |
1004 | 997 | } |
1005 | - | |
1006 | 998 | |
1007 | 999 | EXPORT_SYMBOL(kobject_get); |
1008 | 1000 | EXPORT_SYMBOL(kobject_put); |
net/core/net-sysfs.c
... | ... | @@ -1179,9 +1179,14 @@ |
1179 | 1179 | #endif |
1180 | 1180 | } |
1181 | 1181 | |
1182 | -static const void *net_current_ns(void) | |
1182 | +static void *net_grab_current_ns(void) | |
1183 | 1183 | { |
1184 | - return current->nsproxy->net_ns; | |
1184 | + struct net *ns = current->nsproxy->net_ns; | |
1185 | +#ifdef CONFIG_NET_NS | |
1186 | + if (ns) | |
1187 | + atomic_inc(&ns->passive); | |
1188 | +#endif | |
1189 | + return ns; | |
1185 | 1190 | } |
1186 | 1191 | |
1187 | 1192 | static const void *net_initial_ns(void) |
1188 | 1193 | |
1189 | 1194 | |
... | ... | @@ -1196,22 +1201,13 @@ |
1196 | 1201 | |
1197 | 1202 | struct kobj_ns_type_operations net_ns_type_operations = { |
1198 | 1203 | .type = KOBJ_NS_TYPE_NET, |
1199 | - .current_ns = net_current_ns, | |
1204 | + .grab_current_ns = net_grab_current_ns, | |
1200 | 1205 | .netlink_ns = net_netlink_ns, |
1201 | 1206 | .initial_ns = net_initial_ns, |
1207 | + .drop_ns = net_drop_ns, | |
1202 | 1208 | }; |
1203 | 1209 | EXPORT_SYMBOL_GPL(net_ns_type_operations); |
1204 | 1210 | |
1205 | -static void net_kobj_ns_exit(struct net *net) | |
1206 | -{ | |
1207 | - kobj_ns_exit(KOBJ_NS_TYPE_NET, net); | |
1208 | -} | |
1209 | - | |
1210 | -static struct pernet_operations kobj_net_ops = { | |
1211 | - .exit = net_kobj_ns_exit, | |
1212 | -}; | |
1213 | - | |
1214 | - | |
1215 | 1211 | #ifdef CONFIG_HOTPLUG |
1216 | 1212 | static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) |
1217 | 1213 | { |
... | ... | @@ -1339,7 +1335,6 @@ |
1339 | 1335 | int netdev_kobject_init(void) |
1340 | 1336 | { |
1341 | 1337 | kobj_ns_type_register(&net_ns_type_operations); |
1342 | - register_pernet_subsys(&kobj_net_ops); | |
1343 | 1338 | return class_register(&net_class); |
1344 | 1339 | } |
net/core/net_namespace.c
... | ... | @@ -128,6 +128,7 @@ |
128 | 128 | LIST_HEAD(net_exit_list); |
129 | 129 | |
130 | 130 | atomic_set(&net->count, 1); |
131 | + atomic_set(&net->passive, 1); | |
131 | 132 | |
132 | 133 | #ifdef NETNS_REFCNT_DEBUG |
133 | 134 | atomic_set(&net->use_count, 0); |
... | ... | @@ -210,6 +211,13 @@ |
210 | 211 | kmem_cache_free(net_cachep, net); |
211 | 212 | } |
212 | 213 | |
214 | +void net_drop_ns(void *p) | |
215 | +{ | |
216 | + struct net *ns = p; | |
217 | + if (ns && atomic_dec_and_test(&ns->passive)) | |
218 | + net_free(ns); | |
219 | +} | |
220 | + | |
213 | 221 | struct net *copy_net_ns(unsigned long flags, struct net *old_net) |
214 | 222 | { |
215 | 223 | struct net *net; |
... | ... | @@ -230,7 +238,7 @@ |
230 | 238 | } |
231 | 239 | mutex_unlock(&net_mutex); |
232 | 240 | if (rv < 0) { |
233 | - net_free(net); | |
241 | + net_drop_ns(net); | |
234 | 242 | return ERR_PTR(rv); |
235 | 243 | } |
236 | 244 | return net; |
... | ... | @@ -286,7 +294,7 @@ |
286 | 294 | /* Finally it is safe to free my network namespace structure */ |
287 | 295 | list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { |
288 | 296 | list_del_init(&net->exit_list); |
289 | - net_free(net); | |
297 | + net_drop_ns(net); | |
290 | 298 | } |
291 | 299 | } |
292 | 300 | static DECLARE_WORK(net_cleanup_work, cleanup_net); |