diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-24 11:32:11 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-24 11:32:11 -0400 |
| commit | 6c5daf012c9155aafd2c7973e4278766c30dfad0 (patch) | |
| tree | 33959d7b36d03e1610615641a2940cb2de5e8603 | |
| parent | 6d39b27f0ac7e805ae3bd9efa51d7da04bec0360 (diff) | |
| parent | c08d3b0e33edce28e9cfa7b64f7fe5bdeeb29248 (diff) | |
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:
truncate: use new helpers
truncate: new helpers
fs: fix overflow in sys_mount() for in-kernel calls
fs: Make unload_nls() NULL pointer safe
freeze_bdev: grab active reference to frozen superblocks
freeze_bdev: kill bd_mount_sem
exofs: remove BKL from super operations
fs/romfs: correct error-handling code
vfs: seq_file: add helpers for data filling
vfs: remove redundant position check in do_sendfile
vfs: change sb->s_maxbytes to a loff_t
vfs: explicitly cast s_maxbytes in fiemap_check_ranges
libfs: return error code on failed attr set
seq_file: return a negative error code when seq_path_root() fails.
vfs: optimize touch_time() too
vfs: optimization for touch_atime()
vfs: split generic_forget_inode() so that hugetlbfs does not have to copy it
fs/inode.c: add dev-id and inode number for debugging in init_special_inode()
libfs: make simple_read_from_buffer conventional
41 files changed, 532 insertions, 533 deletions
diff --git a/Documentation/vm/locking b/Documentation/vm/locking index f366fa956179..25fadb448760 100644 --- a/Documentation/vm/locking +++ b/Documentation/vm/locking | |||
| @@ -80,7 +80,7 @@ Note: PTL can also be used to guarantee that no new clones using the | |||
| 80 | mm start up ... this is a loose form of stability on mm_users. For | 80 | mm start up ... this is a loose form of stability on mm_users. For |
| 81 | example, it is used in copy_mm to protect against a racing tlb_gather_mmu | 81 | example, it is used in copy_mm to protect against a racing tlb_gather_mmu |
| 82 | single address space optimization, so that the zap_page_range (from | 82 | single address space optimization, so that the zap_page_range (from |
| 83 | vmtruncate) does not lose sending ipi's to cloned threads that might | 83 | truncate) does not lose sending ipi's to cloned threads that might |
| 84 | be spawned underneath it and go to user mode to drag in pte's into tlbs. | 84 | be spawned underneath it and go to user mode to drag in pte's into tlbs. |
| 85 | 85 | ||
| 86 | swap_lock | 86 | swap_lock |
| @@ -18,7 +18,7 @@ | |||
| 18 | /* Taken over from the old code... */ | 18 | /* Taken over from the old code... */ |
| 19 | 19 | ||
| 20 | /* POSIX UID/GID verification for setting inode attributes. */ | 20 | /* POSIX UID/GID verification for setting inode attributes. */ |
| 21 | int inode_change_ok(struct inode *inode, struct iattr *attr) | 21 | int inode_change_ok(const struct inode *inode, struct iattr *attr) |
| 22 | { | 22 | { |
| 23 | int retval = -EPERM; | 23 | int retval = -EPERM; |
| 24 | unsigned int ia_valid = attr->ia_valid; | 24 | unsigned int ia_valid = attr->ia_valid; |
| @@ -60,9 +60,51 @@ fine: | |||
| 60 | error: | 60 | error: |
| 61 | return retval; | 61 | return retval; |
| 62 | } | 62 | } |
| 63 | |||
| 64 | EXPORT_SYMBOL(inode_change_ok); | 63 | EXPORT_SYMBOL(inode_change_ok); |
| 65 | 64 | ||
| 65 | /** | ||
| 66 | * inode_newsize_ok - may this inode be truncated to a given size | ||
| 67 | * @inode: the inode to be truncated | ||
| 68 | * @offset: the new size to assign to the inode | ||
| 69 | * @Returns: 0 on success, -ve errno on failure | ||
| 70 | * | ||
| 71 | * inode_newsize_ok will check filesystem limits and ulimits to check that the | ||
| 72 | * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ | ||
| 73 | * when necessary. Caller must not proceed with inode size change if failure is | ||
| 74 | * returned. @inode must be a file (not directory), with appropriate | ||
| 75 | * permissions to allow truncate (inode_newsize_ok does NOT check these | ||
| 76 | * conditions). | ||
| 77 | * | ||
| 78 | * inode_newsize_ok must be called with i_mutex held. | ||
| 79 | */ | ||
| 80 | int inode_newsize_ok(const struct inode *inode, loff_t offset) | ||
| 81 | { | ||
| 82 | if (inode->i_size < offset) { | ||
| 83 | unsigned long limit; | ||
| 84 | |||
| 85 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
| 86 | if (limit != RLIM_INFINITY && offset > limit) | ||
| 87 | goto out_sig; | ||
| 88 | if (offset > inode->i_sb->s_maxbytes) | ||
| 89 | goto out_big; | ||
| 90 | } else { | ||
| 91 | /* | ||
| 92 | * truncation of in-use swapfiles is disallowed - it would | ||
| 93 | * cause subsequent swapout to scribble on the now-freed | ||
| 94 | * blocks. | ||
| 95 | */ | ||
| 96 | if (IS_SWAPFILE(inode)) | ||
| 97 | return -ETXTBSY; | ||
| 98 | } | ||
| 99 | |||
| 100 | return 0; | ||
| 101 | out_sig: | ||
| 102 | send_sig(SIGXFSZ, current, 0); | ||
| 103 | out_big: | ||
| 104 | return -EFBIG; | ||
| 105 | } | ||
| 106 | EXPORT_SYMBOL(inode_newsize_ok); | ||
| 107 | |||
| 66 | int inode_setattr(struct inode * inode, struct iattr * attr) | 108 | int inode_setattr(struct inode * inode, struct iattr * attr) |
| 67 | { | 109 | { |
| 68 | unsigned int ia_valid = attr->ia_valid; | 110 | unsigned int ia_valid = attr->ia_valid; |
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index dd376c124e71..33baf27fac78 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
| @@ -737,12 +737,7 @@ befs_put_super(struct super_block *sb) | |||
| 737 | { | 737 | { |
| 738 | kfree(BEFS_SB(sb)->mount_opts.iocharset); | 738 | kfree(BEFS_SB(sb)->mount_opts.iocharset); |
| 739 | BEFS_SB(sb)->mount_opts.iocharset = NULL; | 739 | BEFS_SB(sb)->mount_opts.iocharset = NULL; |
| 740 | 740 | unload_nls(BEFS_SB(sb)->nls); | |
| 741 | if (BEFS_SB(sb)->nls) { | ||
| 742 | unload_nls(BEFS_SB(sb)->nls); | ||
| 743 | BEFS_SB(sb)->nls = NULL; | ||
| 744 | } | ||
| 745 | |||
| 746 | kfree(sb->s_fs_info); | 741 | kfree(sb->s_fs_info); |
| 747 | sb->s_fs_info = NULL; | 742 | sb->s_fs_info = NULL; |
| 748 | } | 743 | } |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 5d1ed50bd46c..9cf4b926f8e4 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -216,8 +216,6 @@ EXPORT_SYMBOL(fsync_bdev); | |||
| 216 | * freeze_bdev -- lock a filesystem and force it into a consistent state | 216 | * freeze_bdev -- lock a filesystem and force it into a consistent state |
| 217 | * @bdev: blockdevice to lock | 217 | * @bdev: blockdevice to lock |
| 218 | * | 218 | * |
| 219 | * This takes the block device bd_mount_sem to make sure no new mounts | ||
| 220 | * happen on bdev until thaw_bdev() is called. | ||
| 221 | * If a superblock is found on this device, we take the s_umount semaphore | 219 | * If a superblock is found on this device, we take the s_umount semaphore |
| 222 | * on it to make sure nobody unmounts until the snapshot creation is done. | 220 | * on it to make sure nobody unmounts until the snapshot creation is done. |
| 223 | * The reference counter (bd_fsfreeze_count) guarantees that only the last | 221 | * The reference counter (bd_fsfreeze_count) guarantees that only the last |
| @@ -232,46 +230,55 @@ struct super_block *freeze_bdev(struct block_device *bdev) | |||
| 232 | int error = 0; | 230 | int error = 0; |
| 233 | 231 | ||
| 234 | mutex_lock(&bdev->bd_fsfreeze_mutex); | 232 | mutex_lock(&bdev->bd_fsfreeze_mutex); |
| 235 | if (bdev->bd_fsfreeze_count > 0) { | 233 | if (++bdev->bd_fsfreeze_count > 1) { |
| 236 | bdev->bd_fsfreeze_count++; | 234 | /* |
| 235 | * We don't even need to grab a reference - the first call | ||
| 236 | * to freeze_bdev grab an active reference and only the last | ||
| 237 | * thaw_bdev drops it. | ||
| 238 | */ | ||
| 237 | sb = get_super(bdev); | 239 | sb = get_super(bdev); |
| 240 | drop_super(sb); | ||
| 238 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 241 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
| 239 | return sb; | 242 | return sb; |
| 240 | } | 243 | } |
| 241 | bdev->bd_fsfreeze_count++; | 244 | |
| 242 | 245 | sb = get_active_super(bdev); | |
| 243 | down(&bdev->bd_mount_sem); | 246 | if (!sb) |
| 244 | sb = get_super(bdev); | 247 | goto out; |
| 245 | if (sb && !(sb->s_flags & MS_RDONLY)) { | 248 | if (sb->s_flags & MS_RDONLY) { |
| 246 | sb->s_frozen = SB_FREEZE_WRITE; | 249 | deactivate_locked_super(sb); |
| 247 | smp_wmb(); | 250 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
| 248 | 251 | return sb; | |
| 249 | sync_filesystem(sb); | 252 | } |
| 250 | 253 | ||
| 251 | sb->s_frozen = SB_FREEZE_TRANS; | 254 | sb->s_frozen = SB_FREEZE_WRITE; |
| 252 | smp_wmb(); | 255 | smp_wmb(); |
| 253 | 256 | ||
| 254 | sync_blockdev(sb->s_bdev); | 257 | sync_filesystem(sb); |
| 255 | 258 | ||
| 256 | if (sb->s_op->freeze_fs) { | 259 | sb->s_frozen = SB_FREEZE_TRANS; |
| 257 | error = sb->s_op->freeze_fs(sb); | 260 | smp_wmb(); |
| 258 | if (error) { | 261 | |
| 259 | printk(KERN_ERR | 262 | sync_blockdev(sb->s_bdev); |
| 260 | "VFS:Filesystem freeze failed\n"); | 263 | |
| 261 | sb->s_frozen = SB_UNFROZEN; | 264 | if (sb->s_op->freeze_fs) { |
| 262 | drop_super(sb); | 265 | error = sb->s_op->freeze_fs(sb); |
| 263 | up(&bdev->bd_mount_sem); | 266 | if (error) { |
| 264 | bdev->bd_fsfreeze_count--; | 267 | printk(KERN_ERR |
| 265 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 268 | "VFS:Filesystem freeze failed\n"); |
| 266 | return ERR_PTR(error); | 269 | sb->s_frozen = SB_UNFROZEN; |
| 267 | } | 270 | deactivate_locked_super(sb); |
| 271 | bdev->bd_fsfreeze_count--; | ||
| 272 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
| 273 | return ERR_PTR(error); | ||
| 268 | } | 274 | } |
| 269 | } | 275 | } |
| 276 | up_write(&sb->s_umount); | ||
| 270 | 277 | ||
| 278 | out: | ||
| 271 | sync_blockdev(bdev); | 279 | sync_blockdev(bdev); |
| 272 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 280 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
| 273 | 281 | return sb; /* thaw_bdev releases s->s_umount */ | |
| 274 | return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */ | ||
| 275 | } | 282 | } |
| 276 | EXPORT_SYMBOL(freeze_bdev); | 283 | EXPORT_SYMBOL(freeze_bdev); |
| 277 | 284 | ||
| @@ -284,44 +291,44 @@ EXPORT_SYMBOL(freeze_bdev); | |||
| 284 | */ | 291 | */ |
| 285 | int thaw_bdev(struct block_device *bdev, struct super_block *sb) | 292 | int thaw_bdev(struct block_device *bdev, struct super_block *sb) |
| 286 | { | 293 | { |
| 287 | int error = 0; | 294 | int error = -EINVAL; |
| 288 | 295 | ||
| 289 | mutex_lock(&bdev->bd_fsfreeze_mutex); | 296 | mutex_lock(&bdev->bd_fsfreeze_mutex); |
| 290 | if (!bdev->bd_fsfreeze_count) { | 297 | if (!bdev->bd_fsfreeze_count) |
| 291 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 298 | goto out_unlock; |
| 292 | return -EINVAL; | 299 | |
| 293 | } | 300 | error = 0; |
| 294 | 301 | if (--bdev->bd_fsfreeze_count > 0) | |
| 295 | bdev->bd_fsfreeze_count--; | 302 | goto out_unlock; |
| 296 | if (bdev->bd_fsfreeze_count > 0) { | 303 | |
| 297 | if (sb) | 304 | if (!sb) |
| 298 | drop_super(sb); | 305 | goto out_unlock; |
| 299 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 306 | |
| 300 | return 0; | 307 | BUG_ON(sb->s_bdev != bdev); |
| 301 | } | 308 | down_write(&sb->s_umount); |
| 302 | 309 | if (sb->s_flags & MS_RDONLY) | |
| 303 | if (sb) { | 310 | goto out_deactivate; |
| 304 | BUG_ON(sb->s_bdev != bdev); | 311 | |
| 305 | if (!(sb->s_flags & MS_RDONLY)) { | 312 | if (sb->s_op->unfreeze_fs) { |
| 306 | if (sb->s_op->unfreeze_fs) { | 313 | error = sb->s_op->unfreeze_fs(sb); |
| 307 | error = sb->s_op->unfreeze_fs(sb); | 314 | if (error) { |
| 308 | if (error) { | 315 | printk(KERN_ERR |
| 309 | printk(KERN_ERR | 316 | "VFS:Filesystem thaw failed\n"); |
| 310 | "VFS:Filesystem thaw failed\n"); | 317 | sb->s_frozen = SB_FREEZE_TRANS; |
| 311 | sb->s_frozen = SB_FREEZE_TRANS; | 318 | bdev->bd_fsfreeze_count++; |
| 312 | bdev->bd_fsfreeze_count++; | 319 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
| 313 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 320 | return error; |
| 314 | return error; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | sb->s_frozen = SB_UNFROZEN; | ||
| 318 | smp_wmb(); | ||
| 319 | wake_up(&sb->s_wait_unfrozen); | ||
| 320 | } | 321 | } |
| 321 | drop_super(sb); | ||
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | up(&bdev->bd_mount_sem); | 324 | sb->s_frozen = SB_UNFROZEN; |
| 325 | smp_wmb(); | ||
| 326 | wake_up(&sb->s_wait_unfrozen); | ||
| 327 | |||
| 328 | out_deactivate: | ||
| 329 | if (sb) | ||
| 330 | deactivate_locked_super(sb); | ||
| 331 | out_unlock: | ||
| 325 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | 332 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
| 326 | return 0; | 333 | return 0; |
| 327 | } | 334 | } |
| @@ -430,7 +437,6 @@ static void init_once(void *foo) | |||
| 430 | 437 | ||
| 431 | memset(bdev, 0, sizeof(*bdev)); | 438 | memset(bdev, 0, sizeof(*bdev)); |
| 432 | mutex_init(&bdev->bd_mutex); | 439 | mutex_init(&bdev->bd_mutex); |
| 433 | sema_init(&bdev->bd_mount_sem, 1); | ||
| 434 | INIT_LIST_HEAD(&bdev->bd_inodes); | 440 | INIT_LIST_HEAD(&bdev->bd_inodes); |
| 435 | INIT_LIST_HEAD(&bdev->bd_list); | 441 | INIT_LIST_HEAD(&bdev->bd_list); |
| 436 | #ifdef CONFIG_SYSFS | 442 | #ifdef CONFIG_SYSFS |
diff --git a/fs/buffer.c b/fs/buffer.c index 209f7f15f5f8..24afd7422ae8 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -2239,16 +2239,10 @@ int generic_cont_expand_simple(struct inode *inode, loff_t size) | |||
| 2239 | struct address_space *mapping = inode->i_mapping; | 2239 | struct address_space *mapping = inode->i_mapping; |
| 2240 | struct page *page; | 2240 | struct page *page; |
| 2241 | void *fsdata; | 2241 | void *fsdata; |
| 2242 | unsigned long limit; | ||
| 2243 | int err; | 2242 | int err; |
| 2244 | 2243 | ||
| 2245 | err = -EFBIG; | 2244 | err = inode_newsize_ok(inode, size); |
| 2246 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | 2245 | if (err) |
| 2247 | if (limit != RLIM_INFINITY && size > (loff_t)limit) { | ||
| 2248 | send_sig(SIGXFSZ, current, 0); | ||
| 2249 | goto out; | ||
| 2250 | } | ||
| 2251 | if (size > inode->i_sb->s_maxbytes) | ||
| 2252 | goto out; | 2246 | goto out; |
| 2253 | 2247 | ||
| 2254 | err = pagecache_write_begin(NULL, mapping, size, 0, | 2248 | err = pagecache_write_begin(NULL, mapping, size, 0, |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d79ce2e95c23..90c5b39f0313 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -185,8 +185,7 @@ out_mount_failed: | |||
| 185 | cifs_sb->mountdata = NULL; | 185 | cifs_sb->mountdata = NULL; |
| 186 | } | 186 | } |
| 187 | #endif | 187 | #endif |
| 188 | if (cifs_sb->local_nls) | 188 | unload_nls(cifs_sb->local_nls); |
| 189 | unload_nls(cifs_sb->local_nls); | ||
| 190 | kfree(cifs_sb); | 189 | kfree(cifs_sb); |
| 191 | } | 190 | } |
| 192 | return rc; | 191 | return rc; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 1f09c7619319..5e2492535daa 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -1557,57 +1557,24 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) | |||
| 1557 | 1557 | ||
| 1558 | static int cifs_vmtruncate(struct inode *inode, loff_t offset) | 1558 | static int cifs_vmtruncate(struct inode *inode, loff_t offset) |
| 1559 | { | 1559 | { |
| 1560 | struct address_space *mapping = inode->i_mapping; | 1560 | loff_t oldsize; |
| 1561 | unsigned long limit; | 1561 | int err; |
| 1562 | 1562 | ||
| 1563 | spin_lock(&inode->i_lock); | 1563 | spin_lock(&inode->i_lock); |
| 1564 | if (inode->i_size < offset) | 1564 | err = inode_newsize_ok(inode, offset); |
| 1565 | goto do_expand; | 1565 | if (err) { |
| 1566 | /* | ||
| 1567 | * truncation of in-use swapfiles is disallowed - it would cause | ||
| 1568 | * subsequent swapout to scribble on the now-freed blocks. | ||
| 1569 | */ | ||
| 1570 | if (IS_SWAPFILE(inode)) { | ||
| 1571 | spin_unlock(&inode->i_lock); | ||
| 1572 | goto out_busy; | ||
| 1573 | } | ||
| 1574 | i_size_write(inode, offset); | ||
| 1575 | spin_unlock(&inode->i_lock); | ||
| 1576 | /* | ||
| 1577 | * unmap_mapping_range is called twice, first simply for efficiency | ||
| 1578 | * so that truncate_inode_pages does fewer single-page unmaps. However | ||
| 1579 | * after this first call, and before truncate_inode_pages finishes, | ||
| 1580 | * it is possible for private pages to be COWed, which remain after | ||
| 1581 | * truncate_inode_pages finishes, hence the second unmap_mapping_range | ||
| 1582 | * call must be made for correctness. | ||
| 1583 | */ | ||
| 1584 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
| 1585 | truncate_inode_pages(mapping, offset); | ||
| 1586 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
| 1587 | goto out_truncate; | ||
| 1588 | |||
| 1589 | do_expand: | ||
| 1590 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
| 1591 | if (limit != RLIM_INFINITY && offset > limit) { | ||
| 1592 | spin_unlock(&inode->i_lock); | 1566 | spin_unlock(&inode->i_lock); |
| 1593 | goto out_sig; | 1567 | goto out; |
| 1594 | } | ||
| 1595 | if (offset > inode->i_sb->s_maxbytes) { | ||
| 1596 | spin_unlock(&inode->i_lock); | ||
| 1597 | goto out_big; | ||
| 1598 | } | 1568 | } |
| 1569 | |||
| 1570 | oldsize = inode->i_size; | ||
| 1599 | i_size_write(inode, offset); | 1571 | i_size_write(inode, offset); |
| 1600 | spin_unlock(&inode->i_lock); | 1572 | spin_unlock(&inode->i_lock); |
| 1601 | out_truncate: | 1573 | truncate_pagecache(inode, oldsize, offset); |
| 1602 | if (inode->i_op->truncate) | 1574 | if (inode->i_op->truncate) |
| 1603 | inode->i_op->truncate(inode); | 1575 | inode->i_op->truncate(inode); |
| 1604 | return 0; | 1576 | out: |
| 1605 | out_sig: | 1577 | return err; |
| 1606 | send_sig(SIGXFSZ, current, 0); | ||
| 1607 | out_big: | ||
| 1608 | return -EFBIG; | ||
| 1609 | out_busy: | ||
| 1610 | return -ETXTBSY; | ||
| 1611 | } | 1578 | } |
| 1612 | 1579 | ||
| 1613 | static int | 1580 | static int |
diff --git a/fs/compat.c b/fs/compat.c index 3aa48834a222..d576b552e8e2 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -768,13 +768,13 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, | |||
| 768 | char __user * type, unsigned long flags, | 768 | char __user * type, unsigned long flags, |
| 769 | void __user * data) | 769 | void __user * data) |
| 770 | { | 770 | { |
| 771 | unsigned long type_page; | 771 | char *kernel_type; |
| 772 | unsigned long data_page; | 772 | unsigned long data_page; |
| 773 | unsigned long dev_page; | 773 | char *kernel_dev; |
| 774 | char *dir_page; | 774 | char *dir_page; |
| 775 | int retval; | 775 | int retval; |
| 776 | 776 | ||
| 777 | retval = copy_mount_options (type, &type_page); | 777 | retval = copy_mount_string(type, &kernel_type); |
| 778 | if (retval < 0) | 778 | if (retval < 0) |
| 779 | goto out; | 779 | goto out; |
| 780 | 780 | ||
| @@ -783,38 +783,38 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, | |||
| 783 | if (IS_ERR(dir_page)) | 783 | if (IS_ERR(dir_page)) |
| 784 | goto out1; | 784 | goto out1; |
| 785 | 785 | ||
| 786 | retval = copy_mount_options (dev_name, &dev_page); | 786 | retval = copy_mount_string(dev_name, &kernel_dev); |
| 787 | if (retval < 0) | 787 | if (retval < 0) |
| 788 | goto out2; | 788 | goto out2; |
| 789 | 789 | ||
| 790 | retval = copy_mount_options (data, &data_page); | 790 | retval = copy_mount_options(data, &data_page); |
| 791 | if (retval < 0) | 791 | if (retval < 0) |
| 792 | goto out3; | 792 | goto out3; |
| 793 | 793 | ||
| 794 | retval = -EINVAL; | 794 | retval = -EINVAL; |
| 795 | 795 | ||
| 796 | if (type_page && data_page) { | 796 | if (kernel_type && data_page) { |
| 797 | if (!strcmp((char *)type_page, SMBFS_NAME)) { | 797 | if (!strcmp(kernel_type, SMBFS_NAME)) { |
| 798 | do_smb_super_data_conv((void *)data_page); | 798 | do_smb_super_data_conv((void *)data_page); |
| 799 | } else if (!strcmp((char *)type_page, NCPFS_NAME)) { | 799 | } else if (!strcmp(kernel_type, NCPFS_NAME)) { |
| 800 | do_ncp_super_data_conv((void *)data_page); | 800 | do_ncp_super_data_conv((void *)data_page); |
| 801 | } else if (!strcmp((char *)type_page, NFS4_NAME)) { | 801 | } else if (!strcmp(kernel_type, NFS4_NAME)) { |
| 802 | if (do_nfs4_super_data_conv((void *) data_page)) | 802 | if (do_nfs4_super_data_conv((void *) data_page)) |
| 803 | goto out4; | 803 | goto out4; |
| 804 | } | 804 | } |
| 805 | } | 805 | } |
| 806 | 806 | ||
| 807 | retval = do_mount((char*)dev_page, dir_page, (char*)type_page, | 807 | retval = do_mount(kernel_dev, dir_page, kernel_type, |
| 808 | flags, (void*)data_page); | 808 | flags, (void*)data_page); |
| 809 | 809 | ||
| 810 | out4: | 810 | out4: |
| 811 | free_page(data_page); | 811 | free_page(data_page); |
| 812 | out3: | 812 | out3: |
| 813 | free_page(dev_page); | 813 | kfree(kernel_dev); |
| 814 | out2: | 814 | out2: |
| 815 | putname(dir_page); | 815 | putname(dir_page); |
| 816 | out1: | 816 | out1: |
| 817 | free_page(type_page); | 817 | kfree(kernel_type); |
| 818 | out: | 818 | out: |
| 819 | return retval; | 819 | return retval; |
| 820 | } | 820 | } |
diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 5ab10c3bbebe..9f500dec3b59 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c | |||
| @@ -214,7 +214,6 @@ int exofs_sync_fs(struct super_block *sb, int wait) | |||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | lock_super(sb); | 216 | lock_super(sb); |
| 217 | lock_kernel(); | ||
| 218 | sbi = sb->s_fs_info; | 217 | sbi = sb->s_fs_info; |
| 219 | fscb->s_nextid = cpu_to_le64(sbi->s_nextid); | 218 | fscb->s_nextid = cpu_to_le64(sbi->s_nextid); |
| 220 | fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles); | 219 | fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles); |
| @@ -245,7 +244,6 @@ int exofs_sync_fs(struct super_block *sb, int wait) | |||
| 245 | out: | 244 | out: |
| 246 | if (or) | 245 | if (or) |
| 247 | osd_end_request(or); | 246 | osd_end_request(or); |
| 248 | unlock_kernel(); | ||
| 249 | unlock_super(sb); | 247 | unlock_super(sb); |
| 250 | kfree(fscb); | 248 | kfree(fscb); |
| 251 | return ret; | 249 | return ret; |
| @@ -268,8 +266,6 @@ static void exofs_put_super(struct super_block *sb) | |||
| 268 | int num_pend; | 266 | int num_pend; |
| 269 | struct exofs_sb_info *sbi = sb->s_fs_info; | 267 | struct exofs_sb_info *sbi = sb->s_fs_info; |
| 270 | 268 | ||
| 271 | lock_kernel(); | ||
| 272 | |||
| 273 | if (sb->s_dirt) | 269 | if (sb->s_dirt) |
| 274 | exofs_write_super(sb); | 270 | exofs_write_super(sb); |
| 275 | 271 | ||
| @@ -286,8 +282,6 @@ static void exofs_put_super(struct super_block *sb) | |||
| 286 | osduld_put_device(sbi->s_dev); | 282 | osduld_put_device(sbi->s_dev); |
| 287 | kfree(sb->s_fs_info); | 283 | kfree(sb->s_fs_info); |
| 288 | sb->s_fs_info = NULL; | 284 | sb->s_fs_info = NULL; |
| 289 | |||
| 290 | unlock_kernel(); | ||
| 291 | } | 285 | } |
| 292 | 286 | ||
| 293 | /* | 287 | /* |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 8970d8c49bb0..04629d1302fc 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
| @@ -470,19 +470,11 @@ static void fat_put_super(struct super_block *sb) | |||
| 470 | 470 | ||
| 471 | iput(sbi->fat_inode); | 471 | iput(sbi->fat_inode); |
| 472 | 472 | ||
| 473 | if (sbi->nls_disk) { | 473 | unload_nls(sbi->nls_disk); |
| 474 | unload_nls(sbi->nls_disk); | 474 | unload_nls(sbi->nls_io); |
| 475 | sbi->nls_disk = NULL; | 475 | |
| 476 | sbi->options.codepage = fat_default_codepage; | 476 | if (sbi->options.iocharset != fat_default_iocharset) |
| 477 | } | ||
| 478 | if (sbi->nls_io) { | ||
| 479 | unload_nls(sbi->nls_io); | ||
| 480 | sbi->nls_io = NULL; | ||
| 481 | } | ||
| 482 | if (sbi->options.iocharset != fat_default_iocharset) { | ||
| 483 | kfree(sbi->options.iocharset); | 477 | kfree(sbi->options.iocharset); |
| 484 | sbi->options.iocharset = fat_default_iocharset; | ||
| 485 | } | ||
| 486 | 478 | ||
| 487 | sb->s_fs_info = NULL; | 479 | sb->s_fs_info = NULL; |
| 488 | kfree(sbi); | 480 | kfree(sbi); |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index e703654e7f40..992f6c9410bb 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
| @@ -1276,14 +1276,9 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, | |||
| 1276 | return 0; | 1276 | return 0; |
| 1277 | 1277 | ||
| 1278 | if (attr->ia_valid & ATTR_SIZE) { | 1278 | if (attr->ia_valid & ATTR_SIZE) { |
| 1279 | unsigned long limit; | 1279 | err = inode_newsize_ok(inode, attr->ia_size); |
| 1280 | if (IS_SWAPFILE(inode)) | 1280 | if (err) |
| 1281 | return -ETXTBSY; | 1281 | return err; |
| 1282 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
| 1283 | if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { | ||
| 1284 | send_sig(SIGXFSZ, current, 0); | ||
| 1285 | return -EFBIG; | ||
| 1286 | } | ||
| 1287 | is_truncate = true; | 1282 | is_truncate = true; |
| 1288 | } | 1283 | } |
| 1289 | 1284 | ||
| @@ -1350,8 +1345,7 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, | |||
| 1350 | * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. | 1345 | * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. |
| 1351 | */ | 1346 | */ |
| 1352 | if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { | 1347 | if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { |
| 1353 | if (outarg.attr.size < oldsize) | 1348 | truncate_pagecache(inode, oldsize, outarg.attr.size); |
| 1354 | fuse_truncate(inode->i_mapping, outarg.attr.size); | ||
| 1355 | invalidate_inode_pages2(inode->i_mapping); | 1349 | invalidate_inode_pages2(inode->i_mapping); |
| 1356 | } | 1350 | } |
| 1357 | 1351 | ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index fc9c79feb5f7..01cc462ff45d 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -606,8 +606,6 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
| 606 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | 606 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, |
| 607 | u64 attr_valid); | 607 | u64 attr_valid); |
| 608 | 608 | ||
| 609 | void fuse_truncate(struct address_space *mapping, loff_t offset); | ||
| 610 | |||
| 611 | /** | 609 | /** |
| 612 | * Initialize the client device | 610 | * Initialize the client device |
| 613 | */ | 611 | */ |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 6da947daabda..1a822ce2b24b 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -140,14 +140,6 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 140 | return 0; | 140 | return 0; |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | void fuse_truncate(struct address_space *mapping, loff_t offset) | ||
| 144 | { | ||
| 145 | /* See vmtruncate() */ | ||
| 146 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
| 147 | truncate_inode_pages(mapping, offset); | ||
| 148 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
| 149 | } | ||
| 150 | |||
| 151 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | 143 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, |
| 152 | u64 attr_valid) | 144 | u64 attr_valid) |
| 153 | { | 145 | { |
| @@ -205,8 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
| 205 | spin_unlock(&fc->lock); | 197 | spin_unlock(&fc->lock); |
| 206 | 198 | ||
| 207 | if (S_ISREG(inode->i_mode) && oldsize != attr->size) { | 199 | if (S_ISREG(inode->i_mode) && oldsize != attr->size) { |
| 208 | if (attr->size < oldsize) | 200 | truncate_pagecache(inode, oldsize, attr->size); |
| 209 | fuse_truncate(inode->i_mapping, attr->size); | ||
| 210 | invalidate_inode_pages2(inode->i_mapping); | 201 | invalidate_inode_pages2(inode->i_mapping); |
| 211 | } | 202 | } |
| 212 | } | 203 | } |
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c index 7b6165f25fbe..8bbe03c3f6d5 100644 --- a/fs/hfs/mdb.c +++ b/fs/hfs/mdb.c | |||
| @@ -344,10 +344,8 @@ void hfs_mdb_put(struct super_block *sb) | |||
| 344 | brelse(HFS_SB(sb)->mdb_bh); | 344 | brelse(HFS_SB(sb)->mdb_bh); |
| 345 | brelse(HFS_SB(sb)->alt_mdb_bh); | 345 | brelse(HFS_SB(sb)->alt_mdb_bh); |
| 346 | 346 | ||
| 347 | if (HFS_SB(sb)->nls_io) | 347 | unload_nls(HFS_SB(sb)->nls_io); |
| 348 | unload_nls(HFS_SB(sb)->nls_io); | 348 | unload_nls(HFS_SB(sb)->nls_disk); |
| 349 | if (HFS_SB(sb)->nls_disk) | ||
| 350 | unload_nls(HFS_SB(sb)->nls_disk); | ||
| 351 | 349 | ||
| 352 | free_pages((unsigned long)HFS_SB(sb)->bitmap, PAGE_SIZE < 8192 ? 1 : 0); | 350 | free_pages((unsigned long)HFS_SB(sb)->bitmap, PAGE_SIZE < 8192 ? 1 : 0); |
| 353 | kfree(HFS_SB(sb)); | 351 | kfree(HFS_SB(sb)); |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index c0759fe0855b..43022f3d5148 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
| @@ -229,8 +229,7 @@ static void hfsplus_put_super(struct super_block *sb) | |||
| 229 | iput(HFSPLUS_SB(sb).alloc_file); | 229 | iput(HFSPLUS_SB(sb).alloc_file); |
| 230 | iput(HFSPLUS_SB(sb).hidden_dir); | 230 | iput(HFSPLUS_SB(sb).hidden_dir); |
| 231 | brelse(HFSPLUS_SB(sb).s_vhbh); | 231 | brelse(HFSPLUS_SB(sb).s_vhbh); |
| 232 | if (HFSPLUS_SB(sb).nls) | 232 | unload_nls(HFSPLUS_SB(sb).nls); |
| 233 | unload_nls(HFSPLUS_SB(sb).nls); | ||
| 234 | kfree(sb->s_fs_info); | 233 | kfree(sb->s_fs_info); |
| 235 | sb->s_fs_info = NULL; | 234 | sb->s_fs_info = NULL; |
| 236 | 235 | ||
| @@ -464,8 +463,7 @@ out: | |||
| 464 | 463 | ||
| 465 | cleanup: | 464 | cleanup: |
| 466 | hfsplus_put_super(sb); | 465 | hfsplus_put_super(sb); |
| 467 | if (nls) | 466 | unload_nls(nls); |
| 468 | unload_nls(nls); | ||
| 469 | return err; | 467 | return err; |
| 470 | } | 468 | } |
| 471 | 469 | ||
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 133335479c24..87a1258953b8 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
| @@ -380,36 +380,11 @@ static void hugetlbfs_delete_inode(struct inode *inode) | |||
| 380 | 380 | ||
| 381 | static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock) | 381 | static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock) |
| 382 | { | 382 | { |
| 383 | struct super_block *sb = inode->i_sb; | 383 | if (generic_detach_inode(inode)) { |
| 384 | 384 | truncate_hugepages(inode, 0); | |
| 385 | if (!hlist_unhashed(&inode->i_hash)) { | 385 | clear_inode(inode); |
| 386 | if (!(inode->i_state & (I_DIRTY|I_SYNC))) | 386 | destroy_inode(inode); |
| 387 | list_move(&inode->i_list, &inode_unused); | ||
| 388 | inodes_stat.nr_unused++; | ||
| 389 | if (!sb || (sb->s_flags & MS_ACTIVE)) { | ||
| 390 | spin_unlock(&inode_lock); | ||
| 391 | return; | ||
| 392 | } | ||
| 393 | inode->i_state |= I_WILL_FREE; | ||
| 394 | spin_unlock(&inode_lock); | ||
| 395 | /* | ||
| 396 | * write_inode_now is a noop as we set BDI_CAP_NO_WRITEBACK | ||
| 397 | * in our backing_dev_info. | ||
| 398 | */ | ||
| 399 | write_inode_now(inode, 1); | ||
| 400 | spin_lock(&inode_lock); | ||
| 401 | inode->i_state &= ~I_WILL_FREE; | ||
| 402 | inodes_stat.nr_unused--; | ||
| 403 | hlist_del_init(&inode->i_hash); | ||
| 404 | } | 387 | } |
| 405 | list_del_init(&inode->i_list); | ||
| 406 | list_del_init(&inode->i_sb_list); | ||
| 407 | inode->i_state |= I_FREEING; | ||
| 408 | inodes_stat.nr_inodes--; | ||
| 409 | spin_unlock(&inode_lock); | ||
| 410 | truncate_hugepages(inode, 0); | ||
| 411 | clear_inode(inode); | ||
| 412 | destroy_inode(inode); | ||
| 413 | } | 388 | } |
| 414 | 389 | ||
| 415 | static void hugetlbfs_drop_inode(struct inode *inode) | 390 | static void hugetlbfs_drop_inode(struct inode *inode) |
diff --git a/fs/inode.c b/fs/inode.c index 76582b06ab97..4d8e3be55976 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -1241,7 +1241,16 @@ void generic_delete_inode(struct inode *inode) | |||
| 1241 | } | 1241 | } |
| 1242 | EXPORT_SYMBOL(generic_delete_inode); | 1242 | EXPORT_SYMBOL(generic_delete_inode); |
| 1243 | 1243 | ||
| 1244 | static void generic_forget_inode(struct inode *inode) | 1244 | /** |
| 1245 | * generic_detach_inode - remove inode from inode lists | ||
| 1246 | * @inode: inode to remove | ||
| 1247 | * | ||
| 1248 | * Remove inode from inode lists, write it if it's dirty. This is just an | ||
| 1249 | * internal VFS helper exported for hugetlbfs. Do not use! | ||
| 1250 | * | ||
| 1251 | * Returns 1 if inode should be completely destroyed. | ||
| 1252 | */ | ||
| 1253 | int generic_detach_inode(struct inode *inode) | ||
| 1245 | { | 1254 | { |
| 1246 | struct super_block *sb = inode->i_sb; | 1255 | struct super_block *sb = inode->i_sb; |
| 1247 | 1256 | ||
| @@ -1251,7 +1260,7 @@ static void generic_forget_inode(struct inode *inode) | |||
| 1251 | inodes_stat.nr_unused++; | 1260 | inodes_stat.nr_unused++; |
| 1252 | if (sb->s_flags & MS_ACTIVE) { | 1261 | if (sb->s_flags & MS_ACTIVE) { |
| 1253 | spin_unlock(&inode_lock); | 1262 | spin_unlock(&inode_lock); |
| 1254 | return; | 1263 | return 0; |
| 1255 | } | 1264 | } |
| 1256 | WARN_ON(inode->i_state & I_NEW); | 1265 | WARN_ON(inode->i_state & I_NEW); |
| 1257 | inode->i_state |= I_WILL_FREE; | 1266 | inode->i_state |= I_WILL_FREE; |
| @@ -1269,6 +1278,14 @@ static void generic_forget_inode(struct inode *inode) | |||
| 1269 | inode->i_state |= I_FREEING; | 1278 | inode->i_state |= I_FREEING; |
| 1270 | inodes_stat.nr_inodes--; | 1279 | inodes_stat.nr_inodes--; |
| 1271 | spin_unlock(&inode_lock); | 1280 | spin_unlock(&inode_lock); |
| 1281 | return 1; | ||
| 1282 | } | ||
| 1283 | EXPORT_SYMBOL_GPL(generic_detach_inode); | ||
| 1284 | |||
| 1285 | static void generic_forget_inode(struct inode *inode) | ||
| 1286 | { | ||
| 1287 | if (!generic_detach_inode(inode)) | ||
| 1288 | return; | ||
| 1272 | if (inode->i_data.nrpages) | 1289 | if (inode->i_data.nrpages) |
| 1273 | truncate_inode_pages(&inode->i_data, 0); | 1290 | truncate_inode_pages(&inode->i_data, 0); |
| 1274 | clear_inode(inode); | 1291 | clear_inode(inode); |
| @@ -1399,31 +1416,31 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry) | |||
| 1399 | struct inode *inode = dentry->d_inode; | 1416 | struct inode *inode = dentry->d_inode; |
| 1400 | struct timespec now; | 1417 | struct timespec now; |
| 1401 | 1418 | ||
| 1402 | if (mnt_want_write(mnt)) | ||
| 1403 | return; | ||
| 1404 | if (inode->i_flags & S_NOATIME) | 1419 | if (inode->i_flags & S_NOATIME) |
| 1405 | goto out; | 1420 | return; |
| 1406 | if (IS_NOATIME(inode)) | 1421 | if (IS_NOATIME(inode)) |
| 1407 | goto out; | 1422 | return; |
| 1408 | if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) | 1423 | if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) |
| 1409 | goto out; | 1424 | return; |
| 1410 | 1425 | ||
| 1411 | if (mnt->mnt_flags & MNT_NOATIME) | 1426 | if (mnt->mnt_flags & MNT_NOATIME) |
| 1412 | goto out; | 1427 | return; |
| 1413 | if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) | 1428 | if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) |
| 1414 | goto out; | 1429 | return; |
| 1415 | 1430 | ||
| 1416 | now = current_fs_time(inode->i_sb); | 1431 | now = current_fs_time(inode->i_sb); |
| 1417 | 1432 | ||
| 1418 | if (!relatime_need_update(mnt, inode, now)) | 1433 | if (!relatime_need_update(mnt, inode, now)) |
| 1419 | goto out; | 1434 | return; |
| 1420 | 1435 | ||
| 1421 | if (timespec_equal(&inode->i_atime, &now)) | 1436 | if (timespec_equal(&inode->i_atime, &now)) |
| 1422 | goto out; | 1437 | return; |
| 1438 | |||
| 1439 | if (mnt_want_write(mnt)) | ||
| 1440 | return; | ||
| 1423 | 1441 | ||
| 1424 | inode->i_atime = now; | 1442 | inode->i_atime = now; |
| 1425 | mark_inode_dirty_sync(inode); | 1443 | mark_inode_dirty_sync(inode); |
| 1426 | out: | ||
| 1427 | mnt_drop_write(mnt); | 1444 | mnt_drop_write(mnt); |
| 1428 | } | 1445 | } |
| 1429 | EXPORT_SYMBOL(touch_atime); | 1446 | EXPORT_SYMBOL(touch_atime); |
| @@ -1444,34 +1461,37 @@ void file_update_time(struct file *file) | |||
| 1444 | { | 1461 | { |
| 1445 | struct inode *inode = file->f_path.dentry->d_inode; | 1462 | struct inode *inode = file->f_path.dentry->d_inode; |
| 1446 | struct timespec now; | 1463 | struct timespec now; |
| 1447 | int sync_it = 0; | 1464 | enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0; |
| 1448 | int err; | ||
| 1449 | 1465 | ||
| 1466 | /* First try to exhaust all avenues to not sync */ | ||
| 1450 | if (IS_NOCMTIME(inode)) | 1467 | if (IS_NOCMTIME(inode)) |
| 1451 | return; | 1468 | return; |
| 1452 | 1469 | ||
| 1453 | err = mnt_want_write_file(file); | ||
| 1454 | if (err) | ||
| 1455 | return; | ||
| 1456 | |||
| 1457 | now = current_fs_time(inode->i_sb); | 1470 | now = current_fs_time(inode->i_sb); |
| 1458 | if (!timespec_equal(&inode->i_mtime, &now)) { | 1471 | if (!timespec_equal(&inode->i_mtime, &now)) |
| 1459 | inode->i_mtime = now; | 1472 | sync_it = S_MTIME; |
| 1460 | sync_it = 1; | ||
| 1461 | } | ||
| 1462 | 1473 | ||
| 1463 | if (!timespec_equal(&inode->i_ctime, &now)) { | 1474 | if (!timespec_equal(&inode->i_ctime, &now)) |
| 1464 | inode->i_ctime = now; | 1475 | sync_it |= S_CTIME; |
| 1465 | sync_it = 1; | ||
| 1466 | } | ||
| 1467 | 1476 | ||
| 1468 | if (IS_I_VERSION(inode)) { | 1477 | if (IS_I_VERSION(inode)) |
| 1469 | inode_inc_iversion(inode); | 1478 | sync_it |= S_VERSION; |
| 1470 | sync_it = 1; | 1479 | |
| 1471 | } | 1480 | if (!sync_it) |
| 1481 | return; | ||
| 1472 | 1482 | ||
| 1473 | if (sync_it) | 1483 | /* Finally allowed to write? Takes lock. */ |
| 1474 | mark_inode_dirty_sync(inode); | 1484 | if (mnt_want_write_file(file)) |
| 1485 | return; | ||
| 1486 | |||
| 1487 | /* Only change inode inside the lock region */ | ||
| 1488 | if (sync_it & S_VERSION) | ||
| 1489 | inode_inc_iversion(inode); | ||
| 1490 | if (sync_it & S_CTIME) | ||
| 1491 | inode->i_ctime = now; | ||
| 1492 | if (sync_it & S_MTIME) | ||
| 1493 | inode->i_mtime = now; | ||
| 1494 | mark_inode_dirty_sync(inode); | ||
| 1475 | mnt_drop_write(file->f_path.mnt); | 1495 | mnt_drop_write(file->f_path.mnt); |
| 1476 | } | 1496 | } |
| 1477 | EXPORT_SYMBOL(file_update_time); | 1497 | EXPORT_SYMBOL(file_update_time); |
| @@ -1599,7 +1619,8 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) | |||
| 1599 | else if (S_ISSOCK(mode)) | 1619 | else if (S_ISSOCK(mode)) |
| 1600 | inode->i_fop = &bad_sock_fops; | 1620 | inode->i_fop = &bad_sock_fops; |
| 1601 | else | 1621 | else |
| 1602 | printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n", | 1622 | printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" |
| 1603 | mode); | 1623 | " inode %s:%lu\n", mode, inode->i_sb->s_id, |
| 1624 | inode->i_ino); | ||
| 1604 | } | 1625 | } |
| 1605 | EXPORT_SYMBOL(init_special_inode); | 1626 | EXPORT_SYMBOL(init_special_inode); |
diff --git a/fs/internal.h b/fs/internal.h index d55ef562f0bb..515175b8b72e 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
| @@ -57,6 +57,7 @@ extern int check_unsafe_exec(struct linux_binprm *); | |||
| 57 | * namespace.c | 57 | * namespace.c |
| 58 | */ | 58 | */ |
| 59 | extern int copy_mount_options(const void __user *, unsigned long *); | 59 | extern int copy_mount_options(const void __user *, unsigned long *); |
| 60 | extern int copy_mount_string(const void __user *, char **); | ||
| 60 | 61 | ||
| 61 | extern void free_vfsmnt(struct vfsmount *); | 62 | extern void free_vfsmnt(struct vfsmount *); |
| 62 | extern struct vfsmount *alloc_vfsmnt(const char *); | 63 | extern struct vfsmount *alloc_vfsmnt(const char *); |
diff --git a/fs/ioctl.c b/fs/ioctl.c index 5612880fcbe7..7b17a14396ff 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
| @@ -162,20 +162,21 @@ EXPORT_SYMBOL(fiemap_check_flags); | |||
| 162 | static int fiemap_check_ranges(struct super_block *sb, | 162 | static int fiemap_check_ranges(struct super_block *sb, |
| 163 | u64 start, u64 len, u64 *new_len) | 163 | u64 start, u64 len, u64 *new_len) |
| 164 | { | 164 | { |
| 165 | u64 maxbytes = (u64) sb->s_maxbytes; | ||
| 166 | |||
| 165 | *new_len = len; | 167 | *new_len = len; |
| 166 | 168 | ||
| 167 | if (len == 0) | 169 | if (len == 0) |
| 168 | return -EINVAL; | 170 | return -EINVAL; |
| 169 | 171 | ||
| 170 | if (start > sb->s_maxbytes) | 172 | if (start > maxbytes) |
| 171 | return -EFBIG; | 173 | return -EFBIG; |
| 172 | 174 | ||
| 173 | /* | 175 | /* |
| 174 | * Shrink request scope to what the fs can actually handle. | 176 | * Shrink request scope to what the fs can actually handle. |
| 175 | */ | 177 | */ |
| 176 | if ((len > sb->s_maxbytes) || | 178 | if (len > maxbytes || (maxbytes - len) < start) |
| 177 | (sb->s_maxbytes - len) < start) | 179 | *new_len = maxbytes - start; |
| 178 | *new_len = sb->s_maxbytes - start; | ||
| 179 | 180 | ||
| 180 | return 0; | 181 | return 0; |
| 181 | } | 182 | } |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 85f96bc651c7..6b4dcd4f2943 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -46,10 +46,7 @@ static void isofs_put_super(struct super_block *sb) | |||
| 46 | #ifdef CONFIG_JOLIET | 46 | #ifdef CONFIG_JOLIET |
| 47 | lock_kernel(); | 47 | lock_kernel(); |
| 48 | 48 | ||
| 49 | if (sbi->s_nls_iocharset) { | 49 | unload_nls(sbi->s_nls_iocharset); |
| 50 | unload_nls(sbi->s_nls_iocharset); | ||
| 51 | sbi->s_nls_iocharset = NULL; | ||
| 52 | } | ||
| 53 | 50 | ||
| 54 | unlock_kernel(); | 51 | unlock_kernel(); |
| 55 | #endif | 52 | #endif |
| @@ -912,8 +909,7 @@ out_no_root: | |||
| 912 | printk(KERN_WARNING "%s: get root inode failed\n", __func__); | 909 | printk(KERN_WARNING "%s: get root inode failed\n", __func__); |
| 913 | out_no_inode: | 910 | out_no_inode: |
| 914 | #ifdef CONFIG_JOLIET | 911 | #ifdef CONFIG_JOLIET |
| 915 | if (sbi->s_nls_iocharset) | 912 | unload_nls(sbi->s_nls_iocharset); |
| 916 | unload_nls(sbi->s_nls_iocharset); | ||
| 917 | #endif | 913 | #endif |
| 918 | goto out_freesbi; | 914 | goto out_freesbi; |
| 919 | out_no_read: | 915 | out_no_read: |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 37e6dcda8fc8..2234c73fc577 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
| @@ -178,13 +178,11 @@ static void jfs_put_super(struct super_block *sb) | |||
| 178 | rc = jfs_umount(sb); | 178 | rc = jfs_umount(sb); |
| 179 | if (rc) | 179 | if (rc) |
| 180 | jfs_err("jfs_umount failed with return code %d", rc); | 180 | jfs_err("jfs_umount failed with return code %d", rc); |
| 181 | if (sbi->nls_tab) | 181 | |
| 182 | unload_nls(sbi->nls_tab); | 182 | unload_nls(sbi->nls_tab); |
| 183 | sbi->nls_tab = NULL; | ||
| 184 | 183 | ||
| 185 | truncate_inode_pages(sbi->direct_inode->i_mapping, 0); | 184 | truncate_inode_pages(sbi->direct_inode->i_mapping, 0); |
| 186 | iput(sbi->direct_inode); | 185 | iput(sbi->direct_inode); |
| 187 | sbi->direct_inode = NULL; | ||
| 188 | 186 | ||
| 189 | kfree(sbi); | 187 | kfree(sbi); |
| 190 | 188 | ||
| @@ -347,8 +345,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, | |||
| 347 | 345 | ||
| 348 | if (nls_map != (void *) -1) { | 346 | if (nls_map != (void *) -1) { |
| 349 | /* Discard old (if remount) */ | 347 | /* Discard old (if remount) */ |
| 350 | if (sbi->nls_tab) | 348 | unload_nls(sbi->nls_tab); |
| 351 | unload_nls(sbi->nls_tab); | ||
| 352 | sbi->nls_tab = nls_map; | 349 | sbi->nls_tab = nls_map; |
| 353 | } | 350 | } |
| 354 | return 1; | 351 | return 1; |
diff --git a/fs/libfs.c b/fs/libfs.c index dcec3d3ea64f..219576c52d80 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
| @@ -527,14 +527,18 @@ ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos, | |||
| 527 | const void *from, size_t available) | 527 | const void *from, size_t available) |
| 528 | { | 528 | { |
| 529 | loff_t pos = *ppos; | 529 | loff_t pos = *ppos; |
| 530 | size_t ret; | ||
| 531 | |||
| 530 | if (pos < 0) | 532 | if (pos < 0) |
| 531 | return -EINVAL; | 533 | return -EINVAL; |
| 532 | if (pos >= available) | 534 | if (pos >= available || !count) |
| 533 | return 0; | 535 | return 0; |
| 534 | if (count > available - pos) | 536 | if (count > available - pos) |
| 535 | count = available - pos; | 537 | count = available - pos; |
| 536 | if (copy_to_user(to, from + pos, count)) | 538 | ret = copy_to_user(to, from + pos, count); |
| 539 | if (ret == count) | ||
| 537 | return -EFAULT; | 540 | return -EFAULT; |
| 541 | count -= ret; | ||
| 538 | *ppos = pos + count; | 542 | *ppos = pos + count; |
| 539 | return count; | 543 | return count; |
| 540 | } | 544 | } |
| @@ -735,10 +739,11 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf, | |||
| 735 | if (copy_from_user(attr->set_buf, buf, size)) | 739 | if (copy_from_user(attr->set_buf, buf, size)) |
| 736 | goto out; | 740 | goto out; |
| 737 | 741 | ||
| 738 | ret = len; /* claim we got the whole input */ | ||
| 739 | attr->set_buf[size] = '\0'; | 742 | attr->set_buf[size] = '\0'; |
| 740 | val = simple_strtol(attr->set_buf, NULL, 0); | 743 | val = simple_strtol(attr->set_buf, NULL, 0); |
| 741 | attr->set(attr->data, val); | 744 | ret = attr->set(attr->data, val); |
| 745 | if (ret == 0) | ||
| 746 | ret = len; /* on success, claim we got the whole input */ | ||
| 742 | out: | 747 | out: |
| 743 | mutex_unlock(&attr->mutex); | 748 | mutex_unlock(&attr->mutex); |
| 744 | return ret; | 749 | return ret; |
diff --git a/fs/namespace.c b/fs/namespace.c index 7230787d18b0..bdc3cb4fd222 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -1640,7 +1640,7 @@ static int do_new_mount(struct path *path, char *type, int flags, | |||
| 1640 | { | 1640 | { |
| 1641 | struct vfsmount *mnt; | 1641 | struct vfsmount *mnt; |
| 1642 | 1642 | ||
| 1643 | if (!type || !memchr(type, 0, PAGE_SIZE)) | 1643 | if (!type) |
| 1644 | return -EINVAL; | 1644 | return -EINVAL; |
| 1645 | 1645 | ||
| 1646 | /* we need capabilities... */ | 1646 | /* we need capabilities... */ |
| @@ -1871,6 +1871,23 @@ int copy_mount_options(const void __user * data, unsigned long *where) | |||
| 1871 | return 0; | 1871 | return 0; |
| 1872 | } | 1872 | } |
| 1873 | 1873 | ||
| 1874 | int copy_mount_string(const void __user *data, char **where) | ||
| 1875 | { | ||
| 1876 | char *tmp; | ||
| 1877 | |||
| 1878 | if (!data) { | ||
| 1879 | *where = NULL; | ||
| 1880 | return 0; | ||
| 1881 | } | ||
| 1882 | |||
| 1883 | tmp = strndup_user(data, PAGE_SIZE); | ||
| 1884 | if (IS_ERR(tmp)) | ||
| 1885 | return PTR_ERR(tmp); | ||
| 1886 | |||
| 1887 | *where = tmp; | ||
| 1888 | return 0; | ||
| 1889 | } | ||
| 1890 | |||
| 1874 | /* | 1891 | /* |
| 1875 | * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to | 1892 | * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to |
| 1876 | * be given to the mount() call (ie: read-only, no-dev, no-suid etc). | 1893 | * be given to the mount() call (ie: read-only, no-dev, no-suid etc). |
| @@ -1900,8 +1917,6 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
| 1900 | 1917 | ||
| 1901 | if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) | 1918 | if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) |
| 1902 | return -EINVAL; | 1919 | return -EINVAL; |
| 1903 | if (dev_name && !memchr(dev_name, 0, PAGE_SIZE)) | ||
| 1904 | return -EINVAL; | ||
| 1905 | 1920 | ||
| 1906 | if (data_page) | 1921 | if (data_page) |
| 1907 | ((char *)data_page)[PAGE_SIZE - 1] = 0; | 1922 | ((char *)data_page)[PAGE_SIZE - 1] = 0; |
| @@ -2070,40 +2085,42 @@ EXPORT_SYMBOL(create_mnt_ns); | |||
| 2070 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, | 2085 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, |
| 2071 | char __user *, type, unsigned long, flags, void __user *, data) | 2086 | char __user *, type, unsigned long, flags, void __user *, data) |
| 2072 | { | 2087 | { |
| 2073 | int retval; | 2088 | int ret; |
| 2089 | char *kernel_type; | ||
| 2090 | char *kernel_dir; | ||
| 2091 | char *kernel_dev; | ||
| 2074 | unsigned long data_page; | 2092 | unsigned long data_page; |
| 2075 | unsigned long type_page; | ||
| 2076 | unsigned long dev_page; | ||
| 2077 | char *dir_page; | ||
| 2078 | 2093 | ||
| 2079 | retval = copy_mount_options(type, &type_page); | 2094 | ret = copy_mount_string(type, &kernel_type); |
| 2080 | if (retval < 0) | 2095 | if (ret < 0) |
| 2081 | return retval; | 2096 | goto out_type; |
| 2082 | 2097 | ||
| 2083 | dir_page = getname(dir_name); | 2098 | kernel_dir = getname(dir_name); |
| 2084 | retval = PTR_ERR(dir_page); | 2099 | if (IS_ERR(kernel_dir)) { |
| 2085 | if (IS_ERR(dir_page)) | 2100 | ret = PTR_ERR(kernel_dir); |
| 2086 | goto out1; | 2101 | goto out_dir; |
| 2102 | } | ||
| 2087 | 2103 | ||
| 2088 | retval = copy_mount_options(dev_name, &dev_page); | 2104 | ret = copy_mount_string(dev_name, &kernel_dev); |
| 2089 | if (retval < 0) | 2105 | if (ret < 0) |
| 2090 | goto out2; | 2106 | goto out_dev; |
| 2091 | 2107 | ||
| 2092 | retval = copy_mount_options(data, &data_page); | 2108 | ret = copy_mount_options(data, &data_page); |
| 2093 | if (retval < 0) | 2109 | if (ret < 0) |
| 2094 | goto out3; | 2110 | goto out_data; |
| 2095 | 2111 | ||
| 2096 | retval = do_mount((char *)dev_page, dir_page, (char *)type_page, | 2112 | ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags, |
| 2097 | flags, (void *)data_page); | 2113 | (void *) data_page); |
| 2098 | free_page(data_page); | ||
| 2099 | 2114 | ||
| 2100 | out3: | 2115 | free_page(data_page); |
| 2101 | free_page(dev_page); | 2116 | out_data: |
| 2102 | out2: | 2117 | kfree(kernel_dev); |
| 2103 | putname(dir_page); | 2118 | out_dev: |
| 2104 | out1: | 2119 | putname(kernel_dir); |
| 2105 | free_page(type_page); | 2120 | out_dir: |
| 2106 | return retval; | 2121 | kfree(kernel_type); |
| 2122 | out_type: | ||
| 2123 | return ret; | ||
| 2107 | } | 2124 | } |
| 2108 | 2125 | ||
| 2109 | /* | 2126 | /* |
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index b99ce205b1bd..cf98da1be23e 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c | |||
| @@ -746,16 +746,8 @@ static void ncp_put_super(struct super_block *sb) | |||
| 746 | 746 | ||
| 747 | #ifdef CONFIG_NCPFS_NLS | 747 | #ifdef CONFIG_NCPFS_NLS |
| 748 | /* unload the NLS charsets */ | 748 | /* unload the NLS charsets */ |
| 749 | if (server->nls_vol) | 749 | unload_nls(server->nls_vol); |
| 750 | { | 750 | unload_nls(server->nls_io); |
| 751 | unload_nls(server->nls_vol); | ||
| 752 | server->nls_vol = NULL; | ||
| 753 | } | ||
| 754 | if (server->nls_io) | ||
| 755 | { | ||
| 756 | unload_nls(server->nls_io); | ||
| 757 | server->nls_io = NULL; | ||
| 758 | } | ||
| 759 | #endif /* CONFIG_NCPFS_NLS */ | 751 | #endif /* CONFIG_NCPFS_NLS */ |
| 760 | 752 | ||
| 761 | if (server->info_filp) | 753 | if (server->info_filp) |
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 53a7ed7eb9c6..0d58caf4a6e1 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c | |||
| @@ -223,10 +223,8 @@ ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) | |||
| 223 | oldset_io = server->nls_io; | 223 | oldset_io = server->nls_io; |
| 224 | server->nls_io = iocharset; | 224 | server->nls_io = iocharset; |
| 225 | 225 | ||
| 226 | if (oldset_cp) | 226 | unload_nls(oldset_cp); |
| 227 | unload_nls(oldset_cp); | 227 | unload_nls(oldset_io); |
| 228 | if (oldset_io) | ||
| 229 | unload_nls(oldset_io); | ||
| 230 | 228 | ||
| 231 | return 0; | 229 | return 0; |
| 232 | } | 230 | } |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 060022b4651c..faa091865ad0 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -458,49 +458,21 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 458 | */ | 458 | */ |
| 459 | static int nfs_vmtruncate(struct inode * inode, loff_t offset) | 459 | static int nfs_vmtruncate(struct inode * inode, loff_t offset) |
| 460 | { | 460 | { |
| 461 | if (i_size_read(inode) < offset) { | 461 | loff_t oldsize; |
| 462 | unsigned long limit; | 462 | int err; |
| 463 | |||
| 464 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
| 465 | if (limit != RLIM_INFINITY && offset > limit) | ||
| 466 | goto out_sig; | ||
| 467 | if (offset > inode->i_sb->s_maxbytes) | ||
| 468 | goto out_big; | ||
| 469 | spin_lock(&inode->i_lock); | ||
| 470 | i_size_write(inode, offset); | ||
| 471 | spin_unlock(&inode->i_lock); | ||
| 472 | } else { | ||
| 473 | struct address_space *mapping = inode->i_mapping; | ||
| 474 | 463 | ||
| 475 | /* | 464 | err = inode_newsize_ok(inode, offset); |
| 476 | * truncation of in-use swapfiles is disallowed - it would | 465 | if (err) |
| 477 | * cause subsequent swapout to scribble on the now-freed | 466 | goto out; |
| 478 | * blocks. | ||
| 479 | */ | ||
| 480 | if (IS_SWAPFILE(inode)) | ||
| 481 | return -ETXTBSY; | ||
| 482 | spin_lock(&inode->i_lock); | ||
| 483 | i_size_write(inode, offset); | ||
| 484 | spin_unlock(&inode->i_lock); | ||
| 485 | 467 | ||
| 486 | /* | 468 | spin_lock(&inode->i_lock); |
| 487 | * unmap_mapping_range is called twice, first simply for | 469 | oldsize = inode->i_size; |
| 488 | * efficiency so that truncate_inode_pages does fewer | 470 | i_size_write(inode, offset); |
| 489 | * single-page unmaps. However after this first call, and | 471 | spin_unlock(&inode->i_lock); |
| 490 | * before truncate_inode_pages finishes, it is possible for | 472 | |
| 491 | * private pages to be COWed, which remain after | 473 | truncate_pagecache(inode, oldsize, offset); |
| 492 | * truncate_inode_pages finishes, hence the second | 474 | out: |
| 493 | * unmap_mapping_range call must be made for correctness. | 475 | return err; |
| 494 | */ | ||
| 495 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
| 496 | truncate_inode_pages(mapping, offset); | ||
| 497 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
| 498 | } | ||
| 499 | return 0; | ||
| 500 | out_sig: | ||
| 501 | send_sig(SIGXFSZ, current, 0); | ||
| 502 | out_big: | ||
| 503 | return -EFBIG; | ||
| 504 | } | 476 | } |
| 505 | 477 | ||
| 506 | /** | 478 | /** |
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 477d37d83b31..2224b4d07bf0 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c | |||
| @@ -270,7 +270,8 @@ struct nls_table *load_nls(char *charset) | |||
| 270 | 270 | ||
| 271 | void unload_nls(struct nls_table *nls) | 271 | void unload_nls(struct nls_table *nls) |
| 272 | { | 272 | { |
| 273 | module_put(nls->owner); | 273 | if (nls) |
| 274 | module_put(nls->owner); | ||
| 274 | } | 275 | } |
| 275 | 276 | ||
| 276 | static const wchar_t charset2uni[256] = { | 277 | static const wchar_t charset2uni[256] = { |
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index abaaa1cbf8de..80b04770e8e9 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
| @@ -201,8 +201,7 @@ use_utf8: | |||
| 201 | v, old_nls->charset); | 201 | v, old_nls->charset); |
| 202 | nls_map = old_nls; | 202 | nls_map = old_nls; |
| 203 | } else /* nls_map */ { | 203 | } else /* nls_map */ { |
| 204 | if (old_nls) | 204 | unload_nls(old_nls); |
| 205 | unload_nls(old_nls); | ||
| 206 | } | 205 | } |
| 207 | } else if (!strcmp(p, "utf8")) { | 206 | } else if (!strcmp(p, "utf8")) { |
| 208 | bool val = false; | 207 | bool val = false; |
| @@ -2427,10 +2426,9 @@ static void ntfs_put_super(struct super_block *sb) | |||
| 2427 | ntfs_free(vol->upcase); | 2426 | ntfs_free(vol->upcase); |
| 2428 | vol->upcase = NULL; | 2427 | vol->upcase = NULL; |
| 2429 | } | 2428 | } |
| 2430 | if (vol->nls_map) { | 2429 | |
| 2431 | unload_nls(vol->nls_map); | 2430 | unload_nls(vol->nls_map); |
| 2432 | vol->nls_map = NULL; | 2431 | |
| 2433 | } | ||
| 2434 | sb->s_fs_info = NULL; | 2432 | sb->s_fs_info = NULL; |
| 2435 | kfree(vol); | 2433 | kfree(vol); |
| 2436 | 2434 | ||
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index 11f0c06316de..32fae4040ebf 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c | |||
| @@ -69,14 +69,11 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) | |||
| 69 | /* make various checks */ | 69 | /* make various checks */ |
| 70 | order = get_order(newsize); | 70 | order = get_order(newsize); |
| 71 | if (unlikely(order >= MAX_ORDER)) | 71 | if (unlikely(order >= MAX_ORDER)) |
| 72 | goto too_big; | 72 | return -EFBIG; |
| 73 | 73 | ||
| 74 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | 74 | ret = inode_newsize_ok(inode, newsize); |
| 75 | if (limit != RLIM_INFINITY && newsize > limit) | 75 | if (ret) |
| 76 | goto fsize_exceeded; | 76 | return ret; |
| 77 | |||
| 78 | if (newsize > inode->i_sb->s_maxbytes) | ||
| 79 | goto too_big; | ||
| 80 | 77 | ||
| 81 | i_size_write(inode, newsize); | 78 | i_size_write(inode, newsize); |
| 82 | 79 | ||
| @@ -118,12 +115,7 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) | |||
| 118 | 115 | ||
| 119 | return 0; | 116 | return 0; |
| 120 | 117 | ||
| 121 | fsize_exceeded: | 118 | add_error: |
| 122 | send_sig(SIGXFSZ, current, 0); | ||
| 123 | too_big: | ||
| 124 | return -EFBIG; | ||
| 125 | |||
| 126 | add_error: | ||
| 127 | while (loop < npages) | 119 | while (loop < npages) |
| 128 | __free_page(pages + loop++); | 120 | __free_page(pages + loop++); |
| 129 | return ret; | 121 | return ret; |
diff --git a/fs/read_write.c b/fs/read_write.c index 6c8c55dec2bc..3ac28987f22a 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
| @@ -839,9 +839,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
| 839 | max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); | 839 | max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); |
| 840 | 840 | ||
| 841 | pos = *ppos; | 841 | pos = *ppos; |
| 842 | retval = -EINVAL; | ||
| 843 | if (unlikely(pos < 0)) | ||
| 844 | goto fput_out; | ||
| 845 | if (unlikely(pos + count > max)) { | 842 | if (unlikely(pos + count > max)) { |
| 846 | retval = -EOVERFLOW; | 843 | retval = -EOVERFLOW; |
| 847 | if (pos >= max) | 844 | if (pos >= max) |
diff --git a/fs/seq_file.c b/fs/seq_file.c index 6c959275f2d0..eae7d9dbf3ff 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
| @@ -429,20 +429,21 @@ EXPORT_SYMBOL(mangle_path); | |||
| 429 | */ | 429 | */ |
| 430 | int seq_path(struct seq_file *m, struct path *path, char *esc) | 430 | int seq_path(struct seq_file *m, struct path *path, char *esc) |
| 431 | { | 431 | { |
| 432 | if (m->count < m->size) { | 432 | char *buf; |
| 433 | char *s = m->buf + m->count; | 433 | size_t size = seq_get_buf(m, &buf); |
| 434 | char *p = d_path(path, s, m->size - m->count); | 434 | int res = -1; |
| 435 | |||
| 436 | if (size) { | ||
| 437 | char *p = d_path(path, buf, size); | ||
| 435 | if (!IS_ERR(p)) { | 438 | if (!IS_ERR(p)) { |
| 436 | s = mangle_path(s, p, esc); | 439 | char *end = mangle_path(buf, p, esc); |
| 437 | if (s) { | 440 | if (end) |
| 438 | p = m->buf + m->count; | 441 | res = end - buf; |
| 439 | m->count = s - m->buf; | ||
| 440 | return s - p; | ||
| 441 | } | ||
| 442 | } | 442 | } |
| 443 | } | 443 | } |
| 444 | m->count = m->size; | 444 | seq_commit(m, res); |
| 445 | return -1; | 445 | |
| 446 | return res; | ||
| 446 | } | 447 | } |
| 447 | EXPORT_SYMBOL(seq_path); | 448 | EXPORT_SYMBOL(seq_path); |
| 448 | 449 | ||
| @@ -454,26 +455,28 @@ EXPORT_SYMBOL(seq_path); | |||
| 454 | int seq_path_root(struct seq_file *m, struct path *path, struct path *root, | 455 | int seq_path_root(struct seq_file *m, struct path *path, struct path *root, |
| 455 | char *esc) | 456 | char *esc) |
| 456 | { | 457 | { |
| 457 | int err = -ENAMETOOLONG; | 458 | char *buf; |
| 458 | if (m->count < m->size) { | 459 | size_t size = seq_get_buf(m, &buf); |
| 459 | char *s = m->buf + m->count; | 460 | int res = -ENAMETOOLONG; |
| 461 | |||
| 462 | if (size) { | ||
| 460 | char *p; | 463 | char *p; |
| 461 | 464 | ||
| 462 | spin_lock(&dcache_lock); | 465 | spin_lock(&dcache_lock); |
| 463 | p = __d_path(path, root, s, m->size - m->count); | 466 | p = __d_path(path, root, buf, size); |
| 464 | spin_unlock(&dcache_lock); | 467 | spin_unlock(&dcache_lock); |
| 465 | err = PTR_ERR(p); | 468 | res = PTR_ERR(p); |
| 466 | if (!IS_ERR(p)) { | 469 | if (!IS_ERR(p)) { |
| 467 | s = mangle_path(s, p, esc); | 470 | char *end = mangle_path(buf, p, esc); |
| 468 | if (s) { | 471 | if (end) |
| 469 | p = m->buf + m->count; | 472 | res = end - buf; |
| 470 | m->count = s - m->buf; | 473 | else |
| 471 | return 0; | 474 | res = -ENAMETOOLONG; |
| 472 | } | ||
| 473 | } | 475 | } |
| 474 | } | 476 | } |
| 475 | m->count = m->size; | 477 | seq_commit(m, res); |
| 476 | return err; | 478 | |
| 479 | return res < 0 ? res : 0; | ||
| 477 | } | 480 | } |
| 478 | 481 | ||
| 479 | /* | 482 | /* |
| @@ -481,20 +484,21 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, | |||
| 481 | */ | 484 | */ |
| 482 | int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc) | 485 | int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc) |
| 483 | { | 486 | { |
| 484 | if (m->count < m->size) { | 487 | char *buf; |
| 485 | char *s = m->buf + m->count; | 488 | size_t size = seq_get_buf(m, &buf); |
| 486 | char *p = dentry_path(dentry, s, m->size - m->count); | 489 | int res = -1; |
| 490 | |||
| 491 | if (size) { | ||
| 492 | char *p = dentry_path(dentry, buf, size); | ||
| 487 | if (!IS_ERR(p)) { | 493 | if (!IS_ERR(p)) { |
| 488 | s = mangle_path(s, p, esc); | 494 | char *end = mangle_path(buf, p, esc); |
| 489 | if (s) { | 495 | if (end) |
| 490 | p = m->buf + m->count; | 496 | res = end - buf; |
| 491 | m->count = s - m->buf; | ||
| 492 | return s - p; | ||
| 493 | } | ||
| 494 | } | 497 | } |
| 495 | } | 498 | } |
| 496 | m->count = m->size; | 499 | seq_commit(m, res); |
| 497 | return -1; | 500 | |
| 501 | return res; | ||
| 498 | } | 502 | } |
| 499 | 503 | ||
| 500 | int seq_bitmap(struct seq_file *m, const unsigned long *bits, | 504 | int seq_bitmap(struct seq_file *m, const unsigned long *bits, |
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 1402d2d54f52..1c4c8f089970 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c | |||
| @@ -459,14 +459,8 @@ smb_show_options(struct seq_file *s, struct vfsmount *m) | |||
| 459 | static void | 459 | static void |
| 460 | smb_unload_nls(struct smb_sb_info *server) | 460 | smb_unload_nls(struct smb_sb_info *server) |
| 461 | { | 461 | { |
| 462 | if (server->remote_nls) { | 462 | unload_nls(server->remote_nls); |
| 463 | unload_nls(server->remote_nls); | 463 | unload_nls(server->local_nls); |
| 464 | server->remote_nls = NULL; | ||
| 465 | } | ||
| 466 | if (server->local_nls) { | ||
| 467 | unload_nls(server->local_nls); | ||
| 468 | server->local_nls = NULL; | ||
| 469 | } | ||
| 470 | } | 464 | } |
| 471 | 465 | ||
| 472 | static void | 466 | static void |
diff --git a/fs/super.c b/fs/super.c index 0e7207b9815c..19eb70b374bc 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -465,6 +465,48 @@ rescan: | |||
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | EXPORT_SYMBOL(get_super); | 467 | EXPORT_SYMBOL(get_super); |
| 468 | |||
| 469 | /** | ||
| 470 | * get_active_super - get an active reference to the superblock of a device | ||
| 471 | * @bdev: device to get the superblock for | ||
| 472 | * | ||
| 473 | * Scans the superblock list and finds the superblock of the file system | ||
| 474 | * mounted on the device given. Returns the superblock with an active | ||
| 475 | * reference and s_umount held exclusively or %NULL if none was found. | ||
| 476 | */ | ||
| 477 | struct super_block *get_active_super(struct block_device *bdev) | ||
| 478 | { | ||
| 479 | struct super_block *sb; | ||
| 480 | |||
| 481 | if (!bdev) | ||
| 482 | return NULL; | ||
| 483 | |||
| 484 | spin_lock(&sb_lock); | ||
| 485 | list_for_each_entry(sb, &super_blocks, s_list) { | ||
| 486 | if (sb->s_bdev != bdev) | ||
| 487 | continue; | ||
| 488 | |||
| 489 | sb->s_count++; | ||
| 490 | spin_unlock(&sb_lock); | ||
| 491 | down_write(&sb->s_umount); | ||
| 492 | if (sb->s_root) { | ||
| 493 | spin_lock(&sb_lock); | ||
| 494 | if (sb->s_count > S_BIAS) { | ||
| 495 | atomic_inc(&sb->s_active); | ||
| 496 | sb->s_count--; | ||
| 497 | spin_unlock(&sb_lock); | ||
| 498 | return sb; | ||
| 499 | } | ||
| 500 | spin_unlock(&sb_lock); | ||
| 501 | } | ||
| 502 | up_write(&sb->s_umount); | ||
| 503 | put_super(sb); | ||
| 504 | yield(); | ||
| 505 | spin_lock(&sb_lock); | ||
| 506 | } | ||
| 507 | spin_unlock(&sb_lock); | ||
| 508 | return NULL; | ||
| 509 | } | ||
| 468 | 510 | ||
| 469 | struct super_block * user_get_super(dev_t dev) | 511 | struct super_block * user_get_super(dev_t dev) |
| 470 | { | 512 | { |
| @@ -527,11 +569,15 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
| 527 | { | 569 | { |
| 528 | int retval; | 570 | int retval; |
| 529 | int remount_rw; | 571 | int remount_rw; |
| 530 | 572 | ||
| 573 | if (sb->s_frozen != SB_UNFROZEN) | ||
| 574 | return -EBUSY; | ||
| 575 | |||
| 531 | #ifdef CONFIG_BLOCK | 576 | #ifdef CONFIG_BLOCK |
| 532 | if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) | 577 | if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) |
| 533 | return -EACCES; | 578 | return -EACCES; |
| 534 | #endif | 579 | #endif |
| 580 | |||
| 535 | if (flags & MS_RDONLY) | 581 | if (flags & MS_RDONLY) |
| 536 | acct_auto_close(sb); | 582 | acct_auto_close(sb); |
| 537 | shrink_dcache_sb(sb); | 583 | shrink_dcache_sb(sb); |
| @@ -743,9 +789,14 @@ int get_sb_bdev(struct file_system_type *fs_type, | |||
| 743 | * will protect the lockfs code from trying to start a snapshot | 789 | * will protect the lockfs code from trying to start a snapshot |
| 744 | * while we are mounting | 790 | * while we are mounting |
| 745 | */ | 791 | */ |
| 746 | down(&bdev->bd_mount_sem); | 792 | mutex_lock(&bdev->bd_fsfreeze_mutex); |
| 793 | if (bdev->bd_fsfreeze_count > 0) { | ||
| 794 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
| 795 | error = -EBUSY; | ||
| 796 | goto error_bdev; | ||
| 797 | } | ||
| 747 | s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); | 798 | s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); |
| 748 | up(&bdev->bd_mount_sem); | 799 | mutex_unlock(&bdev->bd_fsfreeze_mutex); |
| 749 | if (IS_ERR(s)) | 800 | if (IS_ERR(s)) |
| 750 | goto error_s; | 801 | goto error_s; |
| 751 | 802 | ||
| @@ -892,6 +943,16 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void | |||
| 892 | if (error) | 943 | if (error) |
| 893 | goto out_sb; | 944 | goto out_sb; |
| 894 | 945 | ||
| 946 | /* | ||
| 947 | * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE | ||
| 948 | * but s_maxbytes was an unsigned long long for many releases. Throw | ||
| 949 | * this warning for a little while to try and catch filesystems that | ||
| 950 | * violate this rule. This warning should be either removed or | ||
| 951 | * converted to a BUG() in 2.6.34. | ||
| 952 | */ | ||
| 953 | WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " | ||
| 954 | "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes); | ||
| 955 | |||
| 895 | mnt->mnt_mountpoint = mnt->mnt_root; | 956 | mnt->mnt_mountpoint = mnt->mnt_root; |
| 896 | mnt->mnt_parent = mnt; | 957 | mnt->mnt_parent = mnt; |
| 897 | up_write(&mnt->mnt_sb->s_umount); | 958 | up_write(&mnt->mnt_sb->s_umount); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 78e95b8b66d4..2adaa2529f18 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -641,7 +641,6 @@ struct block_device { | |||
| 641 | struct super_block * bd_super; | 641 | struct super_block * bd_super; |
| 642 | int bd_openers; | 642 | int bd_openers; |
| 643 | struct mutex bd_mutex; /* open/close mutex */ | 643 | struct mutex bd_mutex; /* open/close mutex */ |
| 644 | struct semaphore bd_mount_sem; | ||
| 645 | struct list_head bd_inodes; | 644 | struct list_head bd_inodes; |
| 646 | void * bd_holder; | 645 | void * bd_holder; |
| 647 | int bd_holders; | 646 | int bd_holders; |
| @@ -1316,7 +1315,7 @@ struct super_block { | |||
| 1316 | unsigned long s_blocksize; | 1315 | unsigned long s_blocksize; |
| 1317 | unsigned char s_blocksize_bits; | 1316 | unsigned char s_blocksize_bits; |
| 1318 | unsigned char s_dirt; | 1317 | unsigned char s_dirt; |
| 1319 | unsigned long long s_maxbytes; /* Max file size */ | 1318 | loff_t s_maxbytes; /* Max file size */ |
| 1320 | struct file_system_type *s_type; | 1319 | struct file_system_type *s_type; |
| 1321 | const struct super_operations *s_op; | 1320 | const struct super_operations *s_op; |
| 1322 | const struct dquot_operations *dq_op; | 1321 | const struct dquot_operations *dq_op; |
| @@ -2157,6 +2156,7 @@ extern ino_t iunique(struct super_block *, ino_t); | |||
| 2157 | extern int inode_needs_sync(struct inode *inode); | 2156 | extern int inode_needs_sync(struct inode *inode); |
| 2158 | extern void generic_delete_inode(struct inode *inode); | 2157 | extern void generic_delete_inode(struct inode *inode); |
| 2159 | extern void generic_drop_inode(struct inode *inode); | 2158 | extern void generic_drop_inode(struct inode *inode); |
| 2159 | extern int generic_detach_inode(struct inode *inode); | ||
| 2160 | 2160 | ||
| 2161 | extern struct inode *ilookup5_nowait(struct super_block *sb, | 2161 | extern struct inode *ilookup5_nowait(struct super_block *sb, |
| 2162 | unsigned long hashval, int (*test)(struct inode *, void *), | 2162 | unsigned long hashval, int (*test)(struct inode *, void *), |
| @@ -2335,6 +2335,7 @@ extern void get_filesystem(struct file_system_type *fs); | |||
| 2335 | extern void put_filesystem(struct file_system_type *fs); | 2335 | extern void put_filesystem(struct file_system_type *fs); |
| 2336 | extern struct file_system_type *get_fs_type(const char *name); | 2336 | extern struct file_system_type *get_fs_type(const char *name); |
| 2337 | extern struct super_block *get_super(struct block_device *); | 2337 | extern struct super_block *get_super(struct block_device *); |
| 2338 | extern struct super_block *get_active_super(struct block_device *bdev); | ||
| 2338 | extern struct super_block *user_get_super(dev_t); | 2339 | extern struct super_block *user_get_super(dev_t); |
| 2339 | extern void drop_super(struct super_block *sb); | 2340 | extern void drop_super(struct super_block *sb); |
| 2340 | 2341 | ||
| @@ -2382,7 +2383,8 @@ extern int buffer_migrate_page(struct address_space *, | |||
| 2382 | #define buffer_migrate_page NULL | 2383 | #define buffer_migrate_page NULL |
| 2383 | #endif | 2384 | #endif |
| 2384 | 2385 | ||
| 2385 | extern int inode_change_ok(struct inode *, struct iattr *); | 2386 | extern int inode_change_ok(const struct inode *, struct iattr *); |
| 2387 | extern int inode_newsize_ok(const struct inode *, loff_t offset); | ||
| 2386 | extern int __must_check inode_setattr(struct inode *, struct iattr *); | 2388 | extern int __must_check inode_setattr(struct inode *, struct iattr *); |
| 2387 | 2389 | ||
| 2388 | extern void file_update_time(struct file *file); | 2390 | extern void file_update_time(struct file *file); |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 6953a5a53e44..df08551cb0ad 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
| @@ -792,8 +792,9 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, | |||
| 792 | unmap_mapping_range(mapping, holebegin, holelen, 0); | 792 | unmap_mapping_range(mapping, holebegin, holelen, 0); |
| 793 | } | 793 | } |
| 794 | 794 | ||
| 795 | extern int vmtruncate(struct inode * inode, loff_t offset); | 795 | extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new); |
| 796 | extern int vmtruncate_range(struct inode * inode, loff_t offset, loff_t end); | 796 | extern int vmtruncate(struct inode *inode, loff_t offset); |
| 797 | extern int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end); | ||
| 797 | 798 | ||
| 798 | int truncate_inode_page(struct address_space *mapping, struct page *page); | 799 | int truncate_inode_page(struct address_space *mapping, struct page *page); |
| 799 | int generic_error_remove_page(struct address_space *mapping, struct page *page); | 800 | int generic_error_remove_page(struct address_space *mapping, struct page *page); |
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 0c6a86b79596..8366d8f12e53 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h | |||
| @@ -35,6 +35,44 @@ struct seq_operations { | |||
| 35 | 35 | ||
| 36 | #define SEQ_SKIP 1 | 36 | #define SEQ_SKIP 1 |
| 37 | 37 | ||
| 38 | /** | ||
| 39 | * seq_get_buf - get buffer to write arbitrary data to | ||
| 40 | * @m: the seq_file handle | ||
| 41 | * @bufp: the beginning of the buffer is stored here | ||
| 42 | * | ||
| 43 | * Return the number of bytes available in the buffer, or zero if | ||
| 44 | * there's no space. | ||
| 45 | */ | ||
| 46 | static inline size_t seq_get_buf(struct seq_file *m, char **bufp) | ||
| 47 | { | ||
| 48 | BUG_ON(m->count > m->size); | ||
| 49 | if (m->count < m->size) | ||
| 50 | *bufp = m->buf + m->count; | ||
| 51 | else | ||
| 52 | *bufp = NULL; | ||
| 53 | |||
| 54 | return m->size - m->count; | ||
| 55 | } | ||
| 56 | |||
| 57 | /** | ||
| 58 | * seq_commit - commit data to the buffer | ||
| 59 | * @m: the seq_file handle | ||
| 60 | * @num: the number of bytes to commit | ||
| 61 | * | ||
| 62 | * Commit @num bytes of data written to a buffer previously acquired | ||
| 63 | * by seq_buf_get. To signal an error condition, or that the data | ||
| 64 | * didn't fit in the available space, pass a negative @num value. | ||
| 65 | */ | ||
| 66 | static inline void seq_commit(struct seq_file *m, int num) | ||
| 67 | { | ||
| 68 | if (num < 0) { | ||
| 69 | m->count = m->size; | ||
| 70 | } else { | ||
| 71 | BUG_ON(m->count + num > m->size); | ||
| 72 | m->count += num; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 38 | char *mangle_path(char *s, char *p, char *esc); | 76 | char *mangle_path(char *s, char *p, char *esc); |
| 39 | int seq_open(struct file *, const struct seq_operations *); | 77 | int seq_open(struct file *, const struct seq_operations *); |
| 40 | ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); | 78 | ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); |
diff --git a/mm/filemap.c b/mm/filemap.c index c1fc205a92c6..6c84e598b4a9 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
| @@ -58,7 +58,7 @@ | |||
| 58 | /* | 58 | /* |
| 59 | * Lock ordering: | 59 | * Lock ordering: |
| 60 | * | 60 | * |
| 61 | * ->i_mmap_lock (vmtruncate) | 61 | * ->i_mmap_lock (truncate_pagecache) |
| 62 | * ->private_lock (__free_pte->__set_page_dirty_buffers) | 62 | * ->private_lock (__free_pte->__set_page_dirty_buffers) |
| 63 | * ->swap_lock (exclusive_swap_page, others) | 63 | * ->swap_lock (exclusive_swap_page, others) |
| 64 | * ->mapping->tree_lock | 64 | * ->mapping->tree_lock |
diff --git a/mm/memory.c b/mm/memory.c index 987389a809e7..7e91b5f9f690 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
| @@ -297,7 +297,8 @@ void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *vma, | |||
| 297 | unsigned long addr = vma->vm_start; | 297 | unsigned long addr = vma->vm_start; |
| 298 | 298 | ||
| 299 | /* | 299 | /* |
| 300 | * Hide vma from rmap and vmtruncate before freeing pgtables | 300 | * Hide vma from rmap and truncate_pagecache before freeing |
| 301 | * pgtables | ||
| 301 | */ | 302 | */ |
| 302 | anon_vma_unlink(vma); | 303 | anon_vma_unlink(vma); |
| 303 | unlink_file_vma(vma); | 304 | unlink_file_vma(vma); |
| @@ -2408,7 +2409,7 @@ restart: | |||
| 2408 | * @mapping: the address space containing mmaps to be unmapped. | 2409 | * @mapping: the address space containing mmaps to be unmapped. |
| 2409 | * @holebegin: byte in first page to unmap, relative to the start of | 2410 | * @holebegin: byte in first page to unmap, relative to the start of |
| 2410 | * the underlying file. This will be rounded down to a PAGE_SIZE | 2411 | * the underlying file. This will be rounded down to a PAGE_SIZE |
| 2411 | * boundary. Note that this is different from vmtruncate(), which | 2412 | * boundary. Note that this is different from truncate_pagecache(), which |
| 2412 | * must keep the partial page. In contrast, we must get rid of | 2413 | * must keep the partial page. In contrast, we must get rid of |
| 2413 | * partial pages. | 2414 | * partial pages. |
| 2414 | * @holelen: size of prospective hole in bytes. This will be rounded | 2415 | * @holelen: size of prospective hole in bytes. This will be rounded |
| @@ -2459,63 +2460,6 @@ void unmap_mapping_range(struct address_space *mapping, | |||
| 2459 | } | 2460 | } |
| 2460 | EXPORT_SYMBOL(unmap_mapping_range); | 2461 | EXPORT_SYMBOL(unmap_mapping_range); |
| 2461 | 2462 | ||
| 2462 | /** | ||
| 2463 | * vmtruncate - unmap mappings "freed" by truncate() syscall | ||
| 2464 | * @inode: inode of the file used | ||
| 2465 | * @offset: file offset to start truncating | ||
| 2466 | * | ||
| 2467 | * NOTE! We have to be ready to update the memory sharing | ||
| 2468 | * between the file and the memory map for a potential last | ||
| 2469 | * incomplete page. Ugly, but necessary. | ||
| 2470 | */ | ||
| 2471 | int vmtruncate(struct inode * inode, loff_t offset) | ||
| 2472 | { | ||
| 2473 | if (inode->i_size < offset) { | ||
| 2474 | unsigned long limit; | ||
| 2475 | |||
| 2476 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
| 2477 | if (limit != RLIM_INFINITY && offset > limit) | ||
| 2478 | goto out_sig; | ||
| 2479 | if (offset > inode->i_sb->s_maxbytes) | ||
| 2480 | goto out_big; | ||
| 2481 | i_size_write(inode, offset); | ||
| 2482 | } else { | ||
| 2483 | struct address_space *mapping = inode->i_mapping; | ||
| 2484 | |||
| 2485 | /* | ||
| 2486 | * truncation of in-use swapfiles is disallowed - it would | ||
| 2487 | * cause subsequent swapout to scribble on the now-freed | ||
| 2488 | * blocks. | ||
| 2489 | */ | ||
| 2490 | if (IS_SWAPFILE(inode)) | ||
| 2491 | return -ETXTBSY; | ||
| 2492 | i_size_write(inode, offset); | ||
| 2493 | |||
| 2494 | /* | ||
| 2495 | * unmap_mapping_range is called twice, first simply for | ||
| 2496 | * efficiency so that truncate_inode_pages does fewer | ||
| 2497 | * single-page unmaps. However after this first call, and | ||
| 2498 | * before truncate_inode_pages finishes, it is possible for | ||
| 2499 | * private pages to be COWed, which remain after | ||
| 2500 | * truncate_inode_pages finishes, hence the second | ||
| 2501 | * unmap_mapping_range call must be made for correctness. | ||
| 2502 | */ | ||
| 2503 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
| 2504 | truncate_inode_pages(mapping, offset); | ||
| 2505 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
| 2506 | } | ||
| 2507 | |||
| 2508 | if (inode->i_op->truncate) | ||
| 2509 | inode->i_op->truncate(inode); | ||
| 2510 | return 0; | ||
| 2511 | |||
| 2512 | out_sig: | ||
| 2513 | send_sig(SIGXFSZ, current, 0); | ||
| 2514 | out_big: | ||
| 2515 | return -EFBIG; | ||
| 2516 | } | ||
| 2517 | EXPORT_SYMBOL(vmtruncate); | ||
| 2518 | |||
| 2519 | int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end) | 2463 | int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end) |
| 2520 | { | 2464 | { |
| 2521 | struct address_space *mapping = inode->i_mapping; | 2465 | struct address_space *mapping = inode->i_mapping; |
diff --git a/mm/mremap.c b/mm/mremap.c index 20a07dba6be0..97bff2547719 100644 --- a/mm/mremap.c +++ b/mm/mremap.c | |||
| @@ -86,8 +86,8 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, | |||
| 86 | if (vma->vm_file) { | 86 | if (vma->vm_file) { |
| 87 | /* | 87 | /* |
| 88 | * Subtle point from Rajesh Venkatasubramanian: before | 88 | * Subtle point from Rajesh Venkatasubramanian: before |
| 89 | * moving file-based ptes, we must lock vmtruncate out, | 89 | * moving file-based ptes, we must lock truncate_pagecache |
| 90 | * since it might clean the dst vma before the src vma, | 90 | * out, since it might clean the dst vma before the src vma, |
| 91 | * and we propagate stale pages into the dst afterward. | 91 | * and we propagate stale pages into the dst afterward. |
| 92 | */ | 92 | */ |
| 93 | mapping = vma->vm_file->f_mapping; | 93 | mapping = vma->vm_file->f_mapping; |
diff --git a/mm/nommu.c b/mm/nommu.c index 8d484241d034..56a446f05971 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
| @@ -83,46 +83,6 @@ struct vm_operations_struct generic_file_vm_ops = { | |||
| 83 | }; | 83 | }; |
| 84 | 84 | ||
| 85 | /* | 85 | /* |
| 86 | * Handle all mappings that got truncated by a "truncate()" | ||
| 87 | * system call. | ||
| 88 | * | ||
| 89 | * NOTE! We have to be ready to update the memory sharing | ||
| 90 | * between the file and the memory map for a potential last | ||
| 91 | * incomplete page. Ugly, but necessary. | ||
| 92 | */ | ||
| 93 | int vmtruncate(struct inode *inode, loff_t offset) | ||
| 94 | { | ||
| 95 | struct address_space *mapping = inode->i_mapping; | ||
| 96 | unsigned long limit; | ||
| 97 | |||
| 98 | if (inode->i_size < offset) | ||
| 99 | goto do_expand; | ||
| 100 | i_size_write(inode, offset); | ||
| 101 | |||
| 102 | truncate_inode_pages(mapping, offset); | ||
| 103 | goto out_truncate; | ||
| 104 | |||
| 105 | do_expand: | ||
| 106 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
| 107 | if (limit != RLIM_INFINITY && offset > limit) | ||
| 108 | goto out_sig; | ||
| 109 | if (offset > inode->i_sb->s_maxbytes) | ||
| 110 | goto out; | ||
| 111 | i_size_write(inode, offset); | ||
| 112 | |||
| 113 | out_truncate: | ||
| 114 | if (inode->i_op->truncate) | ||
| 115 | inode->i_op->truncate(inode); | ||
| 116 | return 0; | ||
| 117 | out_sig: | ||
| 118 | send_sig(SIGXFSZ, current, 0); | ||
| 119 | out: | ||
| 120 | return -EFBIG; | ||
| 121 | } | ||
| 122 | |||
| 123 | EXPORT_SYMBOL(vmtruncate); | ||
| 124 | |||
| 125 | /* | ||
| 126 | * Return the total memory allocated for this pointer, not | 86 | * Return the total memory allocated for this pointer, not |
| 127 | * just what the caller asked for. | 87 | * just what the caller asked for. |
| 128 | * | 88 | * |
diff --git a/mm/truncate.c b/mm/truncate.c index a17b3977cfdf..450cebdabfc0 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
| @@ -497,3 +497,67 @@ int invalidate_inode_pages2(struct address_space *mapping) | |||
| 497 | return invalidate_inode_pages2_range(mapping, 0, -1); | 497 | return invalidate_inode_pages2_range(mapping, 0, -1); |
| 498 | } | 498 | } |
| 499 | EXPORT_SYMBOL_GPL(invalidate_inode_pages2); | 499 | EXPORT_SYMBOL_GPL(invalidate_inode_pages2); |
| 500 | |||
| 501 | /** | ||
| 502 | * truncate_pagecache - unmap and remove pagecache that has been truncated | ||
| 503 | * @inode: inode | ||
| 504 | * @old: old file offset | ||
| 505 | * @new: new file offset | ||
| 506 | * | ||
| 507 | * inode's new i_size must already be written before truncate_pagecache | ||
| 508 | * is called. | ||
| 509 | * | ||
| 510 | * This function should typically be called before the filesystem | ||
| 511 | * releases resources associated with the freed range (eg. deallocates | ||
| 512 | * blocks). This way, pagecache will always stay logically coherent | ||
| 513 | * with on-disk format, and the filesystem would not have to deal with | ||
| 514 | * situations such as writepage being called for a page that has already | ||
| 515 | * had its underlying blocks deallocated. | ||
| 516 | */ | ||
| 517 | void truncate_pagecache(struct inode *inode, loff_t old, loff_t new) | ||
| 518 | { | ||
| 519 | if (new < old) { | ||
| 520 | struct address_space *mapping = inode->i_mapping; | ||
| 521 | |||
| 522 | /* | ||
| 523 | * unmap_mapping_range is called twice, first simply for | ||
| 524 | * efficiency so that truncate_inode_pages does fewer | ||
| 525 | * single-page unmaps. However after this first call, and | ||
| 526 | * before truncate_inode_pages finishes, it is possible for | ||
| 527 | * private pages to be COWed, which remain after | ||
| 528 | * truncate_inode_pages finishes, hence the second | ||
| 529 | * unmap_mapping_range call must be made for correctness. | ||
| 530 | */ | ||
| 531 | unmap_mapping_range(mapping, new + PAGE_SIZE - 1, 0, 1); | ||
| 532 | truncate_inode_pages(mapping, new); | ||
| 533 | unmap_mapping_range(mapping, new + PAGE_SIZE - 1, 0, 1); | ||
| 534 | } | ||
| 535 | } | ||
| 536 | EXPORT_SYMBOL(truncate_pagecache); | ||
| 537 | |||
| 538 | /** | ||
| 539 | * vmtruncate - unmap mappings "freed" by truncate() syscall | ||
| 540 | * @inode: inode of the file used | ||
| 541 | * @offset: file offset to start truncating | ||
| 542 | * | ||
| 543 | * NOTE! We have to be ready to update the memory sharing | ||
| 544 | * between the file and the memory map for a potential last | ||
| 545 | * incomplete page. Ugly, but necessary. | ||
| 546 | */ | ||
| 547 | int vmtruncate(struct inode *inode, loff_t offset) | ||
| 548 | { | ||
| 549 | loff_t oldsize; | ||
| 550 | int error; | ||
| 551 | |||
| 552 | error = inode_newsize_ok(inode, offset); | ||
| 553 | if (error) | ||
| 554 | return error; | ||
| 555 | oldsize = inode->i_size; | ||
| 556 | i_size_write(inode, offset); | ||
| 557 | truncate_pagecache(inode, oldsize, offset); | ||
| 558 | if (inode->i_op->truncate) | ||
| 559 | inode->i_op->truncate(inode); | ||
| 560 | |||
| 561 | return error; | ||
| 562 | } | ||
| 563 | EXPORT_SYMBOL(vmtruncate); | ||
