diff options
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); | ||