diff options
| -rw-r--r-- | fs/afs/dir.c | 8 | ||||
| -rw-r--r-- | fs/afs/fsclient.c | 3 | ||||
| -rw-r--r-- | fs/afs/inode.c | 10 | ||||
| -rw-r--r-- | fs/afs/super.c | 74 | ||||
| -rw-r--r-- | fs/afs/write.c | 21 | ||||
| -rw-r--r-- | fs/buffer.c | 4 | ||||
| -rw-r--r-- | fs/namei.c | 28 | ||||
| -rw-r--r-- | fs/proc/root.c | 11 | ||||
| -rw-r--r-- | fs/sysfs/mount.c | 37 | ||||
| -rw-r--r-- | fs/sysfs/sysfs.h | 2 | ||||
| -rw-r--r-- | fs/ubifs/super.c | 137 | ||||
| -rw-r--r-- | include/linux/kobject_ns.h | 10 | ||||
| -rw-r--r-- | include/linux/sysfs.h | 7 | ||||
| -rw-r--r-- | include/net/net_namespace.h | 10 | ||||
| -rw-r--r-- | lib/kobject.c | 26 | ||||
| -rw-r--r-- | net/core/net-sysfs.c | 23 | ||||
| -rw-r--r-- | net/core/net_namespace.c | 12 |
17 files changed, 210 insertions, 213 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 20c106f24927..1b0b19550015 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
| @@ -584,11 +584,11 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 584 | 584 | ||
| 585 | success: | 585 | success: |
| 586 | d_add(dentry, inode); | 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 | fid.vnode, | 588 | fid.vnode, |
| 589 | fid.unique, | 589 | fid.unique, |
| 590 | dentry->d_inode->i_ino, | 590 | dentry->d_inode->i_ino, |
| 591 | (unsigned long long)dentry->d_inode->i_version); | 591 | dentry->d_inode->i_generation); |
| 592 | 592 | ||
| 593 | return NULL; | 593 | return NULL; |
| 594 | } | 594 | } |
| @@ -671,10 +671,10 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 671 | * been deleted and replaced, and the original vnode ID has | 671 | * been deleted and replaced, and the original vnode ID has |
| 672 | * been reused */ | 672 | * been reused */ |
| 673 | if (fid.unique != vnode->fid.unique) { | 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 | dentry->d_name.name, fid.unique, | 675 | dentry->d_name.name, fid.unique, |
| 676 | vnode->fid.unique, | 676 | vnode->fid.unique, |
| 677 | (unsigned long long)dentry->d_inode->i_version); | 677 | dentry->d_inode->i_generation); |
| 678 | spin_lock(&vnode->lock); | 678 | spin_lock(&vnode->lock); |
| 679 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | 679 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
| 680 | spin_unlock(&vnode->lock); | 680 | spin_unlock(&vnode->lock); |
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 4bd0218473a9..346e3289abd7 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
| @@ -89,7 +89,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | |||
| 89 | i_size_write(&vnode->vfs_inode, size); | 89 | i_size_write(&vnode->vfs_inode, size); |
| 90 | vnode->vfs_inode.i_uid = status->owner; | 90 | vnode->vfs_inode.i_uid = status->owner; |
| 91 | vnode->vfs_inode.i_gid = status->group; | 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 | vnode->vfs_inode.i_nlink = status->nlink; | 93 | vnode->vfs_inode.i_nlink = status->nlink; |
| 94 | 94 | ||
| 95 | mode = vnode->vfs_inode.i_mode; | 95 | mode = vnode->vfs_inode.i_mode; |
| @@ -102,6 +102,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | |||
| 102 | vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server; | 102 | vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server; |
| 103 | vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; | 103 | vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; |
| 104 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; | 104 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; |
| 105 | vnode->vfs_inode.i_version = data_version; | ||
| 105 | } | 106 | } |
| 106 | 107 | ||
| 107 | expected_version = status->data_version; | 108 | expected_version = status->data_version; |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index db66c5201474..0fdab6e03d87 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
| @@ -75,7 +75,8 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) | |||
| 75 | inode->i_ctime.tv_nsec = 0; | 75 | inode->i_ctime.tv_nsec = 0; |
| 76 | inode->i_atime = inode->i_mtime = inode->i_ctime; | 76 | inode->i_atime = inode->i_mtime = inode->i_ctime; |
| 77 | inode->i_blocks = 0; | 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 | inode->i_mapping->a_ops = &afs_fs_aops; | 80 | inode->i_mapping->a_ops = &afs_fs_aops; |
| 80 | 81 | ||
| 81 | /* check to see whether a symbolic link is really a mountpoint */ | 82 | /* check to see whether a symbolic link is really a mountpoint */ |
| @@ -100,7 +101,7 @@ static int afs_iget5_test(struct inode *inode, void *opaque) | |||
| 100 | struct afs_iget_data *data = opaque; | 101 | struct afs_iget_data *data = opaque; |
| 101 | 102 | ||
| 102 | return inode->i_ino == data->fid.vnode && | 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 @@ static int afs_iget5_set(struct inode *inode, void *opaque) | |||
| 122 | struct afs_vnode *vnode = AFS_FS_I(inode); | 123 | struct afs_vnode *vnode = AFS_FS_I(inode); |
| 123 | 124 | ||
| 124 | inode->i_ino = data->fid.vnode; | 125 | inode->i_ino = data->fid.vnode; |
| 125 | inode->i_version = data->fid.unique; | 126 | inode->i_generation = data->fid.unique; |
| 126 | vnode->fid = data->fid; | 127 | vnode->fid = data->fid; |
| 127 | vnode->volume = data->volume; | 128 | vnode->volume = data->volume; |
| 128 | 129 | ||
| @@ -380,8 +381,7 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 380 | 381 | ||
| 381 | inode = dentry->d_inode; | 382 | inode = dentry->d_inode; |
| 382 | 383 | ||
| 383 | _enter("{ ino=%lu v=%llu }", inode->i_ino, | 384 | _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation); |
| 384 | (unsigned long long)inode->i_version); | ||
| 385 | 385 | ||
| 386 | generic_fillattr(inode, stat); | 386 | generic_fillattr(inode, stat); |
| 387 | return 0; | 387 | return 0; |
diff --git a/fs/afs/super.c b/fs/afs/super.c index fb240e8766d6..356dcf0929e8 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
| @@ -31,8 +31,8 @@ | |||
| 31 | static void afs_i_init_once(void *foo); | 31 | static void afs_i_init_once(void *foo); |
| 32 | static struct dentry *afs_mount(struct file_system_type *fs_type, | 32 | static struct dentry *afs_mount(struct file_system_type *fs_type, |
| 33 | int flags, const char *dev_name, void *data); | 33 | int flags, const char *dev_name, void *data); |
| 34 | static void afs_kill_super(struct super_block *sb); | ||
| 34 | static struct inode *afs_alloc_inode(struct super_block *sb); | 35 | static struct inode *afs_alloc_inode(struct super_block *sb); |
| 35 | static void afs_put_super(struct super_block *sb); | ||
| 36 | static void afs_destroy_inode(struct inode *inode); | 36 | static void afs_destroy_inode(struct inode *inode); |
| 37 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); | 37 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); |
| 38 | 38 | ||
| @@ -40,7 +40,7 @@ struct file_system_type afs_fs_type = { | |||
| 40 | .owner = THIS_MODULE, | 40 | .owner = THIS_MODULE, |
| 41 | .name = "afs", | 41 | .name = "afs", |
| 42 | .mount = afs_mount, | 42 | .mount = afs_mount, |
| 43 | .kill_sb = kill_anon_super, | 43 | .kill_sb = afs_kill_super, |
| 44 | .fs_flags = 0, | 44 | .fs_flags = 0, |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| @@ -50,7 +50,6 @@ static const struct super_operations afs_super_ops = { | |||
| 50 | .drop_inode = afs_drop_inode, | 50 | .drop_inode = afs_drop_inode, |
| 51 | .destroy_inode = afs_destroy_inode, | 51 | .destroy_inode = afs_destroy_inode, |
| 52 | .evict_inode = afs_evict_inode, | 52 | .evict_inode = afs_evict_inode, |
| 53 | .put_super = afs_put_super, | ||
| 54 | .show_options = generic_show_options, | 53 | .show_options = generic_show_options, |
| 55 | }; | 54 | }; |
| 56 | 55 | ||
| @@ -282,19 +281,25 @@ static int afs_parse_device_name(struct afs_mount_params *params, | |||
| 282 | */ | 281 | */ |
| 283 | static int afs_test_super(struct super_block *sb, void *data) | 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 | struct afs_super_info *as = sb->s_fs_info; | 285 | struct afs_super_info *as = sb->s_fs_info; |
| 287 | 286 | ||
| 288 | return as->volume == params->volume; | 287 | return as->volume == as1->volume; |
| 288 | } | ||
| 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); | ||
| 289 | } | 294 | } |
| 290 | 295 | ||
| 291 | /* | 296 | /* |
| 292 | * fill in the superblock | 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; | 302 | struct afs_super_info *as = sb->s_fs_info; |
| 297 | struct afs_super_info *as = NULL; | ||
| 298 | struct afs_fid fid; | 303 | struct afs_fid fid; |
| 299 | struct dentry *root = NULL; | 304 | struct dentry *root = NULL; |
| 300 | struct inode *inode = NULL; | 305 | struct inode *inode = NULL; |
| @@ -302,23 +307,13 @@ static int afs_fill_super(struct super_block *sb, void *data) | |||
| 302 | 307 | ||
| 303 | _enter(""); | 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 | /* fill in the superblock */ | 310 | /* fill in the superblock */ |
| 316 | sb->s_blocksize = PAGE_CACHE_SIZE; | 311 | sb->s_blocksize = PAGE_CACHE_SIZE; |
| 317 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 312 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
| 318 | sb->s_magic = AFS_FS_MAGIC; | 313 | sb->s_magic = AFS_FS_MAGIC; |
| 319 | sb->s_op = &afs_super_ops; | 314 | sb->s_op = &afs_super_ops; |
| 320 | sb->s_fs_info = as; | ||
| 321 | sb->s_bdi = &as->volume->bdi; | 315 | sb->s_bdi = &as->volume->bdi; |
| 316 | strlcpy(sb->s_id, as->volume->vlocation->vldb.name, sizeof(sb->s_id)); | ||
| 322 | 317 | ||
| 323 | /* allocate the root inode and dentry */ | 318 | /* allocate the root inode and dentry */ |
| 324 | fid.vid = as->volume->vid; | 319 | fid.vid = as->volume->vid; |
| @@ -326,7 +321,7 @@ static int afs_fill_super(struct super_block *sb, void *data) | |||
| 326 | fid.unique = 1; | 321 | fid.unique = 1; |
| 327 | inode = afs_iget(sb, params->key, &fid, NULL, NULL); | 322 | inode = afs_iget(sb, params->key, &fid, NULL, NULL); |
| 328 | if (IS_ERR(inode)) | 323 | if (IS_ERR(inode)) |
| 329 | goto error_inode; | 324 | return PTR_ERR(inode); |
| 330 | 325 | ||
| 331 | if (params->autocell) | 326 | if (params->autocell) |
| 332 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); | 327 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); |
| @@ -342,16 +337,8 @@ static int afs_fill_super(struct super_block *sb, void *data) | |||
| 342 | _leave(" = 0"); | 337 | _leave(" = 0"); |
| 343 | return 0; | 338 | return 0; |
| 344 | 339 | ||
| 345 | error_inode: | ||
| 346 | ret = PTR_ERR(inode); | ||
| 347 | inode = NULL; | ||
| 348 | error: | 340 | error: |
| 349 | iput(inode); | 341 | iput(inode); |
| 350 | afs_put_volume(as->volume); | ||
| 351 | kfree(as); | ||
| 352 | |||
| 353 | sb->s_fs_info = NULL; | ||
| 354 | |||
| 355 | _leave(" = %d", ret); | 342 | _leave(" = %d", ret); |
| 356 | return ret; | 343 | return ret; |
| 357 | } | 344 | } |
| @@ -367,6 +354,7 @@ static struct dentry *afs_mount(struct file_system_type *fs_type, | |||
| 367 | struct afs_volume *vol; | 354 | struct afs_volume *vol; |
| 368 | struct key *key; | 355 | struct key *key; |
| 369 | char *new_opts = kstrdup(options, GFP_KERNEL); | 356 | char *new_opts = kstrdup(options, GFP_KERNEL); |
| 357 | struct afs_super_info *as; | ||
| 370 | int ret; | 358 | int ret; |
| 371 | 359 | ||
| 372 | _enter(",,%s,%p", dev_name, options); | 360 | _enter(",,%s,%p", dev_name, options); |
| @@ -399,12 +387,22 @@ static struct dentry *afs_mount(struct file_system_type *fs_type, | |||
| 399 | ret = PTR_ERR(vol); | 387 | ret = PTR_ERR(vol); |
| 400 | goto error; | 388 | goto error; |
| 401 | } | 389 | } |
| 402 | params.volume = vol; | 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; | ||
| 403 | 399 | ||
| 404 | /* allocate a deviceless superblock */ | 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 | if (IS_ERR(sb)) { | 402 | if (IS_ERR(sb)) { |
| 407 | ret = PTR_ERR(sb); | 403 | ret = PTR_ERR(sb); |
| 404 | afs_put_volume(vol); | ||
| 405 | kfree(as); | ||
| 408 | goto error; | 406 | goto error; |
| 409 | } | 407 | } |
| 410 | 408 | ||
| @@ -422,16 +420,16 @@ static struct dentry *afs_mount(struct file_system_type *fs_type, | |||
| 422 | } else { | 420 | } else { |
| 423 | _debug("reuse"); | 421 | _debug("reuse"); |
| 424 | ASSERTCMP(sb->s_flags, &, MS_ACTIVE); | 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 | afs_put_cell(params.cell); | 427 | afs_put_cell(params.cell); |
| 429 | kfree(new_opts); | 428 | kfree(new_opts); |
| 430 | _leave(" = 0 [%p]", sb); | 429 | _leave(" = 0 [%p]", sb); |
| 431 | return dget(sb->s_root); | 430 | return dget(sb->s_root); |
| 432 | 431 | ||
| 433 | error: | 432 | error: |
| 434 | afs_put_volume(params.volume); | ||
| 435 | afs_put_cell(params.cell); | 433 | afs_put_cell(params.cell); |
| 436 | key_put(params.key); | 434 | key_put(params.key); |
| 437 | kfree(new_opts); | 435 | kfree(new_opts); |
| @@ -439,18 +437,12 @@ error: | |||
| 439 | return ERR_PTR(ret); | 437 | return ERR_PTR(ret); |
| 440 | } | 438 | } |
| 441 | 439 | ||
| 442 | /* | 440 | static void afs_kill_super(struct super_block *sb) |
| 443 | * finish the unmounting process on the superblock | ||
| 444 | */ | ||
| 445 | static void afs_put_super(struct super_block *sb) | ||
| 446 | { | 441 | { |
| 447 | struct afs_super_info *as = sb->s_fs_info; | 442 | struct afs_super_info *as = sb->s_fs_info; |
| 448 | 443 | kill_anon_super(sb); | |
| 449 | _enter(""); | ||
| 450 | |||
| 451 | afs_put_volume(as->volume); | 444 | afs_put_volume(as->volume); |
| 452 | 445 | kfree(as); | |
| 453 | _leave(""); | ||
| 454 | } | 446 | } |
| 455 | 447 | ||
| 456 | /* | 448 | /* |
diff --git a/fs/afs/write.c b/fs/afs/write.c index 789b3afb3423..b806285ff853 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c | |||
| @@ -84,23 +84,21 @@ void afs_put_writeback(struct afs_writeback *wb) | |||
| 84 | * partly or wholly fill a page that's under preparation for writing | 84 | * partly or wholly fill a page that's under preparation for writing |
| 85 | */ | 85 | */ |
| 86 | static int afs_fill_page(struct afs_vnode *vnode, struct key *key, | 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 | loff_t i_size; | 89 | loff_t i_size; |
| 90 | unsigned eof; | ||
| 91 | int ret; | 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 | |||
| 95 | ASSERTCMP(len, <=, PAGE_CACHE_SIZE); | ||
| 96 | 94 | ||
| 97 | i_size = i_size_read(&vnode->vfs_inode); | 95 | i_size = i_size_read(&vnode->vfs_inode); |
| 98 | if (pos + len > i_size) | 96 | if (pos + PAGE_CACHE_SIZE > i_size) |
| 99 | eof = i_size; | 97 | len = i_size - pos; |
| 100 | else | 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 | if (ret < 0) { | 102 | if (ret < 0) { |
| 105 | if (ret == -ENOENT) { | 103 | if (ret == -ENOENT) { |
| 106 | _debug("got NOENT from server" | 104 | _debug("got NOENT from server" |
| @@ -153,9 +151,8 @@ int afs_write_begin(struct file *file, struct address_space *mapping, | |||
| 153 | *pagep = page; | 151 | *pagep = page; |
| 154 | /* page won't leak in error case: it eventually gets cleaned off LRU */ | 152 | /* page won't leak in error case: it eventually gets cleaned off LRU */ |
| 155 | 153 | ||
| 156 | if (!PageUptodate(page)) { | 154 | if (!PageUptodate(page) && len != PAGE_CACHE_SIZE) { |
| 157 | _debug("not up to date"); | 155 | ret = afs_fill_page(vnode, key, index << PAGE_CACHE_SHIFT, page); |
| 158 | ret = afs_fill_page(vnode, key, pos, len, page); | ||
| 159 | if (ret < 0) { | 156 | if (ret < 0) { |
| 160 | kfree(candidate); | 157 | kfree(candidate); |
| 161 | _leave(" = %d [prep]", ret); | 158 | _leave(" = %d [prep]", ret); |
diff --git a/fs/buffer.c b/fs/buffer.c index 49c9aada0374..1a80b048ade8 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -1902,10 +1902,8 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len, | |||
| 1902 | if (!buffer_uptodate(*wait_bh)) | 1902 | if (!buffer_uptodate(*wait_bh)) |
| 1903 | err = -EIO; | 1903 | err = -EIO; |
| 1904 | } | 1904 | } |
| 1905 | if (unlikely(err)) { | 1905 | if (unlikely(err)) |
| 1906 | page_zero_new_buffers(page, from, to); | 1906 | page_zero_new_buffers(page, from, to); |
| 1907 | ClearPageUptodate(page); | ||
| 1908 | } | ||
| 1909 | return err; | 1907 | return err; |
| 1910 | } | 1908 | } |
| 1911 | EXPORT_SYMBOL(__block_write_begin); | 1909 | EXPORT_SYMBOL(__block_write_begin); |
diff --git a/fs/namei.c b/fs/namei.c index 9802345df5e7..9e425e7e6c8f 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -812,6 +812,11 @@ static int follow_automount(struct path *path, unsigned flags, | |||
| 812 | if (!mnt) /* mount collision */ | 812 | if (!mnt) /* mount collision */ |
| 813 | return 0; | 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 | err = finish_automount(mnt, path); | 820 | err = finish_automount(mnt, path); |
| 816 | 821 | ||
| 817 | switch (err) { | 822 | switch (err) { |
| @@ -819,12 +824,9 @@ static int follow_automount(struct path *path, unsigned flags, | |||
| 819 | /* Someone else made a mount here whilst we were busy */ | 824 | /* Someone else made a mount here whilst we were busy */ |
| 820 | return 0; | 825 | return 0; |
| 821 | case 0: | 826 | case 0: |
| 822 | dput(path->dentry); | 827 | path_put(path); |
| 823 | if (*need_mntput) | ||
| 824 | mntput(path->mnt); | ||
| 825 | path->mnt = mnt; | 828 | path->mnt = mnt; |
| 826 | path->dentry = dget(mnt->mnt_root); | 829 | path->dentry = dget(mnt->mnt_root); |
| 827 | *need_mntput = true; | ||
| 828 | return 0; | 830 | return 0; |
| 829 | default: | 831 | default: |
| 830 | return err; | 832 | return err; |
| @@ -844,9 +846,10 @@ static int follow_automount(struct path *path, unsigned flags, | |||
| 844 | */ | 846 | */ |
| 845 | static int follow_managed(struct path *path, unsigned flags) | 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 | unsigned managed; | 850 | unsigned managed; |
| 848 | bool need_mntput = false; | 851 | bool need_mntput = false; |
| 849 | int ret; | 852 | int ret = 0; |
| 850 | 853 | ||
| 851 | /* Given that we're not holding a lock here, we retain the value in a | 854 | /* Given that we're not holding a lock here, we retain the value in a |
| 852 | * local variable for each dentry as we look at it so that we don't see | 855 | * local variable for each dentry as we look at it so that we don't see |
| @@ -861,7 +864,7 @@ static int follow_managed(struct path *path, unsigned flags) | |||
| 861 | BUG_ON(!path->dentry->d_op->d_manage); | 864 | BUG_ON(!path->dentry->d_op->d_manage); |
| 862 | ret = path->dentry->d_op->d_manage(path->dentry, false); | 865 | ret = path->dentry->d_op->d_manage(path->dentry, false); |
| 863 | if (ret < 0) | 866 | if (ret < 0) |
| 864 | return ret == -EISDIR ? 0 : ret; | 867 | break; |
| 865 | } | 868 | } |
| 866 | 869 | ||
| 867 | /* Transit to a mounted filesystem. */ | 870 | /* Transit to a mounted filesystem. */ |
| @@ -887,14 +890,19 @@ static int follow_managed(struct path *path, unsigned flags) | |||
| 887 | if (managed & DCACHE_NEED_AUTOMOUNT) { | 890 | if (managed & DCACHE_NEED_AUTOMOUNT) { |
| 888 | ret = follow_automount(path, flags, &need_mntput); | 891 | ret = follow_automount(path, flags, &need_mntput); |
| 889 | if (ret < 0) | 892 | if (ret < 0) |
| 890 | return ret == -EISDIR ? 0 : ret; | 893 | break; |
| 891 | continue; | 894 | continue; |
| 892 | } | 895 | } |
| 893 | 896 | ||
| 894 | /* We didn't change the current path point */ | 897 | /* We didn't change the current path point */ |
| 895 | break; | 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 | int follow_down_one(struct path *path) | 908 | int follow_down_one(struct path *path) |
| @@ -2713,8 +2721,10 @@ static long do_unlinkat(int dfd, const char __user *pathname) | |||
| 2713 | error = PTR_ERR(dentry); | 2721 | error = PTR_ERR(dentry); |
| 2714 | if (!IS_ERR(dentry)) { | 2722 | if (!IS_ERR(dentry)) { |
| 2715 | /* Why not before? Because we want correct error value */ | 2723 | /* Why not before? Because we want correct error value */ |
| 2724 | if (nd.last.name[nd.last.len]) | ||
| 2725 | goto slashes; | ||
| 2716 | inode = dentry->d_inode; | 2726 | inode = dentry->d_inode; |
| 2717 | if (nd.last.name[nd.last.len] || !inode) | 2727 | if (!inode) |
| 2718 | goto slashes; | 2728 | goto slashes; |
| 2719 | ihold(inode); | 2729 | ihold(inode); |
| 2720 | error = mnt_want_write(nd.path.mnt); | 2730 | error = mnt_want_write(nd.path.mnt); |
diff --git a/fs/proc/root.c b/fs/proc/root.c index a9000e9cfee5..d6c3b416529b 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
| @@ -28,11 +28,12 @@ static int proc_test_super(struct super_block *sb, void *data) | |||
| 28 | 28 | ||
| 29 | static int proc_set_super(struct super_block *sb, void *data) | 29 | static int proc_set_super(struct super_block *sb, void *data) |
| 30 | { | 30 | { |
| 31 | struct pid_namespace *ns; | 31 | int err = set_anon_super(sb, NULL); |
| 32 | 32 | if (!err) { | |
| 33 | ns = (struct pid_namespace *)data; | 33 | struct pid_namespace *ns = (struct pid_namespace *)data; |
| 34 | sb->s_fs_info = get_pid_ns(ns); | 34 | sb->s_fs_info = get_pid_ns(ns); |
| 35 | return set_anon_super(sb, NULL); | 35 | } |
| 36 | return err; | ||
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | static struct dentry *proc_mount(struct file_system_type *fs_type, | 39 | static struct dentry *proc_mount(struct file_system_type *fs_type, |
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 266895783b47..e34f0d99ea4e 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
| @@ -95,6 +95,14 @@ static int sysfs_set_super(struct super_block *sb, void *data) | |||
| 95 | return error; | 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 | static struct dentry *sysfs_mount(struct file_system_type *fs_type, | 106 | static struct dentry *sysfs_mount(struct file_system_type *fs_type, |
| 99 | int flags, const char *dev_name, void *data) | 107 | int flags, const char *dev_name, void *data) |
| 100 | { | 108 | { |
| @@ -108,11 +116,11 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
| 108 | return ERR_PTR(-ENOMEM); | 116 | return ERR_PTR(-ENOMEM); |
| 109 | 117 | ||
| 110 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) | 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 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info); | 121 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info); |
| 114 | if (IS_ERR(sb) || sb->s_fs_info != info) | 122 | if (IS_ERR(sb) || sb->s_fs_info != info) |
| 115 | kfree(info); | 123 | free_sysfs_super_info(info); |
| 116 | if (IS_ERR(sb)) | 124 | if (IS_ERR(sb)) |
| 117 | return ERR_CAST(sb); | 125 | return ERR_CAST(sb); |
| 118 | if (!sb->s_root) { | 126 | if (!sb->s_root) { |
| @@ -131,12 +139,11 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
| 131 | static void sysfs_kill_sb(struct super_block *sb) | 139 | static void sysfs_kill_sb(struct super_block *sb) |
| 132 | { | 140 | { |
| 133 | struct sysfs_super_info *info = sysfs_info(sb); | 141 | struct sysfs_super_info *info = sysfs_info(sb); |
| 134 | |||
| 135 | /* Remove the superblock from fs_supers/s_instances | 142 | /* Remove the superblock from fs_supers/s_instances |
| 136 | * so we can't find it, before freeing sysfs_super_info. | 143 | * so we can't find it, before freeing sysfs_super_info. |
| 137 | */ | 144 | */ |
| 138 | kill_anon_super(sb); | 145 | kill_anon_super(sb); |
| 139 | kfree(info); | 146 | free_sysfs_super_info(info); |
| 140 | } | 147 | } |
| 141 | 148 | ||
| 142 | static struct file_system_type sysfs_fs_type = { | 149 | static struct file_system_type sysfs_fs_type = { |
| @@ -145,28 +152,6 @@ static struct file_system_type sysfs_fs_type = { | |||
| 145 | .kill_sb = sysfs_kill_sb, | 152 | .kill_sb = sysfs_kill_sb, |
| 146 | }; | 153 | }; |
| 147 | 154 | ||
| 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 | |||
| 170 | int __init sysfs_init(void) | 155 | int __init sysfs_init(void) |
| 171 | { | 156 | { |
| 172 | int err = -ENOMEM; | 157 | int err = -ENOMEM; |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3d28af31d863..2ed2404f3113 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
| @@ -136,7 +136,7 @@ struct sysfs_addrm_cxt { | |||
| 136 | * instance). | 136 | * instance). |
| 137 | */ | 137 | */ |
| 138 | struct sysfs_super_info { | 138 | struct sysfs_super_info { |
| 139 | const void *ns[KOBJ_NS_TYPES]; | 139 | void *ns[KOBJ_NS_TYPES]; |
| 140 | }; | 140 | }; |
| 141 | #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) | 141 | #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) |
| 142 | extern struct sysfs_dirent sysfs_root; | 142 | extern struct sysfs_dirent sysfs_root; |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index b5aeb5a8ebed..8c892c2d5300 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -1848,7 +1848,6 @@ static void ubifs_put_super(struct super_block *sb) | |||
| 1848 | bdi_destroy(&c->bdi); | 1848 | bdi_destroy(&c->bdi); |
| 1849 | ubi_close_volume(c->ubi); | 1849 | ubi_close_volume(c->ubi); |
| 1850 | mutex_unlock(&c->umount_mutex); | 1850 | mutex_unlock(&c->umount_mutex); |
| 1851 | kfree(c); | ||
| 1852 | } | 1851 | } |
| 1853 | 1852 | ||
| 1854 | static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) | 1853 | static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) |
| @@ -1971,61 +1970,65 @@ static struct ubi_volume_desc *open_ubi(const char *name, int mode) | |||
| 1971 | return ERR_PTR(-EINVAL); | 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 | struct ubifs_info *c; | 1975 | struct ubifs_info *c; |
| 1978 | struct inode *root; | ||
| 1979 | int err; | ||
| 1980 | 1976 | ||
| 1981 | c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL); | 1977 | c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL); |
| 1982 | if (!c) | 1978 | if (c) { |
| 1983 | return -ENOMEM; | 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; | ||
| 2010 | |||
| 2011 | c->highest_inum = UBIFS_FIRST_INO; | ||
| 2012 | c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; | ||
| 2013 | |||
| 2014 | ubi_get_volume_info(ubi, &c->vi); | ||
| 2015 | ubi_get_device_info(c->vi.ubi_num, &c->di); | ||
| 2016 | } | ||
| 2017 | return c; | ||
| 2018 | } | ||
| 1984 | 2019 | ||
| 1985 | spin_lock_init(&c->cnt_lock); | 2020 | static int ubifs_fill_super(struct super_block *sb, void *data, int silent) |
| 1986 | spin_lock_init(&c->cs_lock); | 2021 | { |
| 1987 | spin_lock_init(&c->buds_lock); | 2022 | struct ubifs_info *c = sb->s_fs_info; |
| 1988 | spin_lock_init(&c->space_lock); | 2023 | struct inode *root; |
| 1989 | spin_lock_init(&c->orphan_lock); | 2024 | int err; |
| 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; | ||
| 2016 | 2025 | ||
| 2017 | c->vfs_sb = sb; | 2026 | c->vfs_sb = sb; |
| 2018 | c->highest_inum = UBIFS_FIRST_INO; | ||
| 2019 | c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; | ||
| 2020 | |||
| 2021 | ubi_get_volume_info(ubi, &c->vi); | ||
| 2022 | ubi_get_device_info(c->vi.ubi_num, &c->di); | ||
| 2023 | |||
| 2024 | /* Re-open the UBI device in read-write mode */ | 2027 | /* Re-open the UBI device in read-write mode */ |
| 2025 | c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); | 2028 | c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); |
| 2026 | if (IS_ERR(c->ubi)) { | 2029 | if (IS_ERR(c->ubi)) { |
| 2027 | err = PTR_ERR(c->ubi); | 2030 | err = PTR_ERR(c->ubi); |
| 2028 | goto out_free; | 2031 | goto out; |
| 2029 | } | 2032 | } |
| 2030 | 2033 | ||
| 2031 | /* | 2034 | /* |
| @@ -2091,24 +2094,29 @@ out_bdi: | |||
| 2091 | bdi_destroy(&c->bdi); | 2094 | bdi_destroy(&c->bdi); |
| 2092 | out_close: | 2095 | out_close: |
| 2093 | ubi_close_volume(c->ubi); | 2096 | ubi_close_volume(c->ubi); |
| 2094 | out_free: | 2097 | out: |
| 2095 | kfree(c); | ||
| 2096 | return err; | 2098 | return err; |
| 2097 | } | 2099 | } |
| 2098 | 2100 | ||
| 2099 | static int sb_test(struct super_block *sb, void *data) | 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 | struct ubifs_info *c = sb->s_fs_info; | 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; |
| 2107 | } | ||
| 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); | ||
| 2105 | } | 2113 | } |
| 2106 | 2114 | ||
| 2107 | static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, | 2115 | static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, |
| 2108 | const char *name, void *data) | 2116 | const char *name, void *data) |
| 2109 | { | 2117 | { |
| 2110 | struct ubi_volume_desc *ubi; | 2118 | struct ubi_volume_desc *ubi; |
| 2111 | struct ubi_volume_info vi; | 2119 | struct ubifs_info *c; |
| 2112 | struct super_block *sb; | 2120 | struct super_block *sb; |
| 2113 | int err; | 2121 | int err; |
| 2114 | 2122 | ||
| @@ -2125,19 +2133,24 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, | |||
| 2125 | name, (int)PTR_ERR(ubi)); | 2133 | name, (int)PTR_ERR(ubi)); |
| 2126 | return ERR_CAST(ubi); | 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 | } | ||
| 2142 | |||
| 2143 | dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); | ||
| 2131 | 2144 | ||
| 2132 | sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev); | 2145 | sb = sget(fs_type, sb_test, sb_set, c); |
| 2133 | if (IS_ERR(sb)) { | 2146 | if (IS_ERR(sb)) { |
| 2134 | err = PTR_ERR(sb); | 2147 | err = PTR_ERR(sb); |
| 2135 | goto out_close; | 2148 | kfree(c); |
| 2136 | } | 2149 | } |
| 2137 | 2150 | ||
| 2138 | if (sb->s_root) { | 2151 | if (sb->s_root) { |
| 2139 | struct ubifs_info *c1 = sb->s_fs_info; | 2152 | struct ubifs_info *c1 = sb->s_fs_info; |
| 2140 | 2153 | kfree(c); | |
| 2141 | /* A new mount point for already mounted UBIFS */ | 2154 | /* A new mount point for already mounted UBIFS */ |
| 2142 | dbg_gen("this ubi volume is already mounted"); | 2155 | dbg_gen("this ubi volume is already mounted"); |
| 2143 | if (!!(flags & MS_RDONLY) != c1->ro_mount) { | 2156 | if (!!(flags & MS_RDONLY) != c1->ro_mount) { |
| @@ -2146,11 +2159,6 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, | |||
| 2146 | } | 2159 | } |
| 2147 | } else { | 2160 | } else { |
| 2148 | sb->s_flags = flags; | 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 | err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); | 2162 | err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); |
| 2155 | if (err) | 2163 | if (err) |
| 2156 | goto out_deact; | 2164 | goto out_deact; |
| @@ -2170,11 +2178,18 @@ out_close: | |||
| 2170 | return ERR_PTR(err); | 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 | static struct file_system_type ubifs_fs_type = { | 2188 | static struct file_system_type ubifs_fs_type = { |
| 2174 | .name = "ubifs", | 2189 | .name = "ubifs", |
| 2175 | .owner = THIS_MODULE, | 2190 | .owner = THIS_MODULE, |
| 2176 | .mount = ubifs_mount, | 2191 | .mount = ubifs_mount, |
| 2177 | .kill_sb = kill_anon_super, | 2192 | .kill_sb = kill_ubifs_super, |
| 2178 | }; | 2193 | }; |
| 2179 | 2194 | ||
| 2180 | /* | 2195 | /* |
diff --git a/include/linux/kobject_ns.h b/include/linux/kobject_ns.h index 82cb5bf461fb..f66b065a8b5f 100644 --- a/include/linux/kobject_ns.h +++ b/include/linux/kobject_ns.h | |||
| @@ -32,15 +32,17 @@ enum kobj_ns_type { | |||
| 32 | 32 | ||
| 33 | /* | 33 | /* |
| 34 | * Callbacks so sysfs can determine namespaces | 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 | * @netlink_ns: return namespace to which a sock belongs (right?) | 36 | * @netlink_ns: return namespace to which a sock belongs (right?) |
| 37 | * @initial_ns: return the initial namespace (i.e. init_net_ns) | 37 | * @initial_ns: return the initial namespace (i.e. init_net_ns) |
| 38 | * @drop_ns: drops a reference to namespace | ||
| 38 | */ | 39 | */ |
| 39 | struct kobj_ns_type_operations { | 40 | struct kobj_ns_type_operations { |
| 40 | enum kobj_ns_type type; | 41 | enum kobj_ns_type type; |
| 41 | const void *(*current_ns)(void); | 42 | void *(*grab_current_ns)(void); |
| 42 | const void *(*netlink_ns)(struct sock *sk); | 43 | const void *(*netlink_ns)(struct sock *sk); |
| 43 | const void *(*initial_ns)(void); | 44 | const void *(*initial_ns)(void); |
| 45 | void (*drop_ns)(void *); | ||
| 44 | }; | 46 | }; |
| 45 | 47 | ||
| 46 | int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); | 48 | int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); |
| @@ -48,9 +50,9 @@ int kobj_ns_type_registered(enum kobj_ns_type type); | |||
| 48 | const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); | 50 | const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); |
| 49 | const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); | 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 | const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); | 54 | const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); |
| 53 | const void *kobj_ns_initial(enum kobj_ns_type type); | 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 | #endif /* _LINUX_KOBJECT_NS_H */ | 58 | #endif /* _LINUX_KOBJECT_NS_H */ |
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index c3acda60eee0..e2696d76a599 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h | |||
| @@ -177,9 +177,6 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | |||
| 177 | struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); | 177 | struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); |
| 178 | void sysfs_put(struct sysfs_dirent *sd); | 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 | int __must_check sysfs_init(void); | 180 | int __must_check sysfs_init(void); |
| 184 | 181 | ||
| 185 | #else /* CONFIG_SYSFS */ | 182 | #else /* CONFIG_SYSFS */ |
| @@ -338,10 +335,6 @@ static inline void sysfs_put(struct sysfs_dirent *sd) | |||
| 338 | { | 335 | { |
| 339 | } | 336 | } |
| 340 | 337 | ||
| 341 | static inline void sysfs_exit_ns(int type, const void *tag) | ||
| 342 | { | ||
| 343 | } | ||
| 344 | |||
| 345 | static inline int __must_check sysfs_init(void) | 338 | static inline int __must_check sysfs_init(void) |
| 346 | { | 339 | { |
| 347 | return 0; | 340 | return 0; |
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 2bf9ed9ef26b..aef430d779bd 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h | |||
| @@ -35,8 +35,11 @@ struct netns_ipvs; | |||
| 35 | #define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) | 35 | #define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) |
| 36 | 36 | ||
| 37 | struct net { | 37 | struct net { |
| 38 | atomic_t passive; /* To decided when the network | ||
| 39 | * namespace should be freed. | ||
| 40 | */ | ||
| 38 | atomic_t count; /* To decided when the network | 41 | atomic_t count; /* To decided when the network |
| 39 | * namespace should be freed. | 42 | * namespace should be shut down. |
| 40 | */ | 43 | */ |
| 41 | #ifdef NETNS_REFCNT_DEBUG | 44 | #ifdef NETNS_REFCNT_DEBUG |
| 42 | atomic_t use_count; /* To track references we | 45 | atomic_t use_count; /* To track references we |
| @@ -154,6 +157,9 @@ int net_eq(const struct net *net1, const struct net *net2) | |||
| 154 | { | 157 | { |
| 155 | return net1 == net2; | 158 | return net1 == net2; |
| 156 | } | 159 | } |
| 160 | |||
| 161 | extern void net_drop_ns(void *); | ||
| 162 | |||
| 157 | #else | 163 | #else |
| 158 | 164 | ||
| 159 | static inline struct net *get_net(struct net *net) | 165 | static inline struct net *get_net(struct net *net) |
| @@ -175,6 +181,8 @@ int net_eq(const struct net *net1, const struct net *net2) | |||
| 175 | { | 181 | { |
| 176 | return 1; | 182 | return 1; |
| 177 | } | 183 | } |
| 184 | |||
| 185 | #define net_drop_ns NULL | ||
| 178 | #endif | 186 | #endif |
| 179 | 187 | ||
| 180 | 188 | ||
diff --git a/lib/kobject.c b/lib/kobject.c index 82dc34c095c2..640bd98a4c8a 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
| @@ -948,14 +948,14 @@ const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj) | |||
| 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 | spin_lock(&kobj_ns_type_lock); | 955 | spin_lock(&kobj_ns_type_lock); |
| 956 | if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && | 956 | if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && |
| 957 | kobj_ns_ops_tbl[type]) | 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 | spin_unlock(&kobj_ns_type_lock); | 959 | spin_unlock(&kobj_ns_type_lock); |
| 960 | 960 | ||
| 961 | return ns; | 961 | return ns; |
| @@ -987,23 +987,15 @@ const void *kobj_ns_initial(enum kobj_ns_type type) | |||
| 987 | return ns; | 987 | return ns; |
| 988 | } | 988 | } |
| 989 | 989 | ||
| 990 | /* | 990 | void kobj_ns_drop(enum kobj_ns_type type, void *ns) |
| 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) | ||
| 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 | 998 | ||
| 1006 | |||
| 1007 | EXPORT_SYMBOL(kobject_get); | 999 | EXPORT_SYMBOL(kobject_get); |
| 1008 | EXPORT_SYMBOL(kobject_put); | 1000 | EXPORT_SYMBOL(kobject_put); |
| 1009 | EXPORT_SYMBOL(kobject_del); | 1001 | EXPORT_SYMBOL(kobject_del); |
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 11b98bc2aa8f..33d2a1fba131 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
| @@ -1179,9 +1179,14 @@ static void remove_queue_kobjects(struct net_device *net) | |||
| 1179 | #endif | 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 | static const void *net_initial_ns(void) | 1192 | static const void *net_initial_ns(void) |
| @@ -1196,22 +1201,13 @@ static const void *net_netlink_ns(struct sock *sk) | |||
| 1196 | 1201 | ||
| 1197 | struct kobj_ns_type_operations net_ns_type_operations = { | 1202 | struct kobj_ns_type_operations net_ns_type_operations = { |
| 1198 | .type = KOBJ_NS_TYPE_NET, | 1203 | .type = KOBJ_NS_TYPE_NET, |
| 1199 | .current_ns = net_current_ns, | 1204 | .grab_current_ns = net_grab_current_ns, |
| 1200 | .netlink_ns = net_netlink_ns, | 1205 | .netlink_ns = net_netlink_ns, |
| 1201 | .initial_ns = net_initial_ns, | 1206 | .initial_ns = net_initial_ns, |
| 1207 | .drop_ns = net_drop_ns, | ||
| 1202 | }; | 1208 | }; |
| 1203 | EXPORT_SYMBOL_GPL(net_ns_type_operations); | 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 | #ifdef CONFIG_HOTPLUG | 1211 | #ifdef CONFIG_HOTPLUG |
| 1216 | static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) | 1212 | static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) |
| 1217 | { | 1213 | { |
| @@ -1339,6 +1335,5 @@ EXPORT_SYMBOL(netdev_class_remove_file); | |||
| 1339 | int netdev_kobject_init(void) | 1335 | int netdev_kobject_init(void) |
| 1340 | { | 1336 | { |
| 1341 | kobj_ns_type_register(&net_ns_type_operations); | 1337 | kobj_ns_type_register(&net_ns_type_operations); |
| 1342 | register_pernet_subsys(&kobj_net_ops); | ||
| 1343 | return class_register(&net_class); | 1338 | return class_register(&net_class); |
| 1344 | } | 1339 | } |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index e41e5110c65c..ea489db1bc23 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
| @@ -128,6 +128,7 @@ static __net_init int setup_net(struct net *net) | |||
| 128 | LIST_HEAD(net_exit_list); | 128 | LIST_HEAD(net_exit_list); |
| 129 | 129 | ||
| 130 | atomic_set(&net->count, 1); | 130 | atomic_set(&net->count, 1); |
| 131 | atomic_set(&net->passive, 1); | ||
| 131 | 132 | ||
| 132 | #ifdef NETNS_REFCNT_DEBUG | 133 | #ifdef NETNS_REFCNT_DEBUG |
| 133 | atomic_set(&net->use_count, 0); | 134 | atomic_set(&net->use_count, 0); |
| @@ -210,6 +211,13 @@ static void net_free(struct net *net) | |||
| 210 | kmem_cache_free(net_cachep, net); | 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 | struct net *copy_net_ns(unsigned long flags, struct net *old_net) | 221 | struct net *copy_net_ns(unsigned long flags, struct net *old_net) |
| 214 | { | 222 | { |
| 215 | struct net *net; | 223 | struct net *net; |
| @@ -230,7 +238,7 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) | |||
| 230 | } | 238 | } |
| 231 | mutex_unlock(&net_mutex); | 239 | mutex_unlock(&net_mutex); |
| 232 | if (rv < 0) { | 240 | if (rv < 0) { |
| 233 | net_free(net); | 241 | net_drop_ns(net); |
| 234 | return ERR_PTR(rv); | 242 | return ERR_PTR(rv); |
| 235 | } | 243 | } |
| 236 | return net; | 244 | return net; |
| @@ -286,7 +294,7 @@ static void cleanup_net(struct work_struct *work) | |||
| 286 | /* Finally it is safe to free my network namespace structure */ | 294 | /* Finally it is safe to free my network namespace structure */ |
| 287 | list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { | 295 | list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { |
| 288 | list_del_init(&net->exit_list); | 296 | list_del_init(&net->exit_list); |
| 289 | net_free(net); | 297 | net_drop_ns(net); |
| 290 | } | 298 | } |
| 291 | } | 299 | } |
| 292 | static DECLARE_WORK(net_cleanup_work, cleanup_net); | 300 | static DECLARE_WORK(net_cleanup_work, cleanup_net); |
