diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/shmem.c | 23 | ||||
-rw-r--r-- | mm/truncate.c | 38 |
2 files changed, 41 insertions, 20 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 566f9a481e64..dfaa0f4e9789 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -766,6 +766,10 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | |||
766 | loff_t newsize = attr->ia_size; | 766 | loff_t newsize = attr->ia_size; |
767 | int error; | 767 | int error; |
768 | 768 | ||
769 | error = inode_change_ok(inode, attr); | ||
770 | if (error) | ||
771 | return error; | ||
772 | |||
769 | if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE) | 773 | if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE) |
770 | && newsize != inode->i_size) { | 774 | && newsize != inode->i_size) { |
771 | struct page *page = NULL; | 775 | struct page *page = NULL; |
@@ -800,25 +804,22 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | |||
800 | } | 804 | } |
801 | } | 805 | } |
802 | 806 | ||
803 | error = simple_setsize(inode, newsize); | 807 | /* XXX(truncate): truncate_setsize should be called last */ |
808 | truncate_setsize(inode, newsize); | ||
804 | if (page) | 809 | if (page) |
805 | page_cache_release(page); | 810 | page_cache_release(page); |
806 | if (error) | ||
807 | return error; | ||
808 | shmem_truncate_range(inode, newsize, (loff_t)-1); | 811 | shmem_truncate_range(inode, newsize, (loff_t)-1); |
809 | } | 812 | } |
810 | 813 | ||
811 | error = inode_change_ok(inode, attr); | 814 | setattr_copy(inode, attr); |
812 | if (!error) | ||
813 | generic_setattr(inode, attr); | ||
814 | #ifdef CONFIG_TMPFS_POSIX_ACL | 815 | #ifdef CONFIG_TMPFS_POSIX_ACL |
815 | if (!error && (attr->ia_valid & ATTR_MODE)) | 816 | if (attr->ia_valid & ATTR_MODE) |
816 | error = generic_acl_chmod(inode); | 817 | error = generic_acl_chmod(inode); |
817 | #endif | 818 | #endif |
818 | return error; | 819 | return error; |
819 | } | 820 | } |
820 | 821 | ||
821 | static void shmem_delete_inode(struct inode *inode) | 822 | static void shmem_evict_inode(struct inode *inode) |
822 | { | 823 | { |
823 | struct shmem_inode_info *info = SHMEM_I(inode); | 824 | struct shmem_inode_info *info = SHMEM_I(inode); |
824 | 825 | ||
@@ -835,7 +836,7 @@ static void shmem_delete_inode(struct inode *inode) | |||
835 | } | 836 | } |
836 | BUG_ON(inode->i_blocks); | 837 | BUG_ON(inode->i_blocks); |
837 | shmem_free_inode(inode->i_sb); | 838 | shmem_free_inode(inode->i_sb); |
838 | clear_inode(inode); | 839 | end_writeback(inode); |
839 | } | 840 | } |
840 | 841 | ||
841 | static inline int shmem_find_swp(swp_entry_t entry, swp_entry_t *dir, swp_entry_t *edir) | 842 | static inline int shmem_find_swp(swp_entry_t entry, swp_entry_t *dir, swp_entry_t *edir) |
@@ -932,7 +933,7 @@ found: | |||
932 | 933 | ||
933 | /* | 934 | /* |
934 | * Move _head_ to start search for next from here. | 935 | * Move _head_ to start search for next from here. |
935 | * But be careful: shmem_delete_inode checks list_empty without taking | 936 | * But be careful: shmem_evict_inode checks list_empty without taking |
936 | * mutex, and there's an instant in list_move_tail when info->swaplist | 937 | * mutex, and there's an instant in list_move_tail when info->swaplist |
937 | * would appear empty, if it were the only one on shmem_swaplist. We | 938 | * would appear empty, if it were the only one on shmem_swaplist. We |
938 | * could avoid doing it if inode NULL; or use this minor optimization. | 939 | * could avoid doing it if inode NULL; or use this minor optimization. |
@@ -2518,7 +2519,7 @@ static const struct super_operations shmem_ops = { | |||
2518 | .remount_fs = shmem_remount_fs, | 2519 | .remount_fs = shmem_remount_fs, |
2519 | .show_options = shmem_show_options, | 2520 | .show_options = shmem_show_options, |
2520 | #endif | 2521 | #endif |
2521 | .delete_inode = shmem_delete_inode, | 2522 | .evict_inode = shmem_evict_inode, |
2522 | .drop_inode = generic_delete_inode, | 2523 | .drop_inode = generic_delete_inode, |
2523 | .put_super = shmem_put_super, | 2524 | .put_super = shmem_put_super, |
2524 | }; | 2525 | }; |
diff --git a/mm/truncate.c b/mm/truncate.c index 937571b8b233..ba887bff48c5 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
@@ -541,28 +541,48 @@ void truncate_pagecache(struct inode *inode, loff_t old, loff_t new) | |||
541 | EXPORT_SYMBOL(truncate_pagecache); | 541 | EXPORT_SYMBOL(truncate_pagecache); |
542 | 542 | ||
543 | /** | 543 | /** |
544 | * truncate_setsize - update inode and pagecache for a new file size | ||
545 | * @inode: inode | ||
546 | * @newsize: new file size | ||
547 | * | ||
548 | * truncate_setsize updastes i_size update and performs pagecache | ||
549 | * truncation (if necessary) for a file size updates. It will be | ||
550 | * typically be called from the filesystem's setattr function when | ||
551 | * ATTR_SIZE is passed in. | ||
552 | * | ||
553 | * Must be called with inode_mutex held and after all filesystem | ||
554 | * specific block truncation has been performed. | ||
555 | */ | ||
556 | void truncate_setsize(struct inode *inode, loff_t newsize) | ||
557 | { | ||
558 | loff_t oldsize; | ||
559 | |||
560 | oldsize = inode->i_size; | ||
561 | i_size_write(inode, newsize); | ||
562 | |||
563 | truncate_pagecache(inode, oldsize, newsize); | ||
564 | } | ||
565 | EXPORT_SYMBOL(truncate_setsize); | ||
566 | |||
567 | /** | ||
544 | * vmtruncate - unmap mappings "freed" by truncate() syscall | 568 | * vmtruncate - unmap mappings "freed" by truncate() syscall |
545 | * @inode: inode of the file used | 569 | * @inode: inode of the file used |
546 | * @offset: file offset to start truncating | 570 | * @offset: file offset to start truncating |
547 | * | 571 | * |
548 | * NOTE! We have to be ready to update the memory sharing | 572 | * This function is deprecated and truncate_setsize or truncate_pagecache |
549 | * between the file and the memory map for a potential last | 573 | * should be used instead, together with filesystem specific block truncation. |
550 | * incomplete page. Ugly, but necessary. | ||
551 | * | ||
552 | * This function is deprecated and simple_setsize or truncate_pagecache | ||
553 | * should be used instead. | ||
554 | */ | 574 | */ |
555 | int vmtruncate(struct inode *inode, loff_t offset) | 575 | int vmtruncate(struct inode *inode, loff_t offset) |
556 | { | 576 | { |
557 | int error; | 577 | int error; |
558 | 578 | ||
559 | error = simple_setsize(inode, offset); | 579 | error = inode_newsize_ok(inode, offset); |
560 | if (error) | 580 | if (error) |
561 | return error; | 581 | return error; |
562 | 582 | ||
583 | truncate_setsize(inode, offset); | ||
563 | if (inode->i_op->truncate) | 584 | if (inode->i_op->truncate) |
564 | inode->i_op->truncate(inode); | 585 | inode->i_op->truncate(inode); |
565 | 586 | return 0; | |
566 | return error; | ||
567 | } | 587 | } |
568 | EXPORT_SYMBOL(vmtruncate); | 588 | EXPORT_SYMBOL(vmtruncate); |