diff options
Diffstat (limited to 'fs/ext2/inode.c')
-rw-r--r-- | fs/ext2/inode.c | 209 |
1 files changed, 145 insertions, 64 deletions
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index fc13cc119aad..940c96168868 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000 | 22 | * Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000 |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/smp_lock.h> | ||
26 | #include <linux/time.h> | 25 | #include <linux/time.h> |
27 | #include <linux/highuid.h> | 26 | #include <linux/highuid.h> |
28 | #include <linux/pagemap.h> | 27 | #include <linux/pagemap.h> |
@@ -55,29 +54,57 @@ static inline int ext2_inode_is_fast_symlink(struct inode *inode) | |||
55 | inode->i_blocks - ea_blocks == 0); | 54 | inode->i_blocks - ea_blocks == 0); |
56 | } | 55 | } |
57 | 56 | ||
57 | static void ext2_truncate_blocks(struct inode *inode, loff_t offset); | ||
58 | |||
59 | static void ext2_write_failed(struct address_space *mapping, loff_t to) | ||
60 | { | ||
61 | struct inode *inode = mapping->host; | ||
62 | |||
63 | if (to > inode->i_size) { | ||
64 | truncate_pagecache(inode, to, inode->i_size); | ||
65 | ext2_truncate_blocks(inode, inode->i_size); | ||
66 | } | ||
67 | } | ||
68 | |||
58 | /* | 69 | /* |
59 | * Called at the last iput() if i_nlink is zero. | 70 | * Called at the last iput() if i_nlink is zero. |
60 | */ | 71 | */ |
61 | void ext2_delete_inode (struct inode * inode) | 72 | void ext2_evict_inode(struct inode * inode) |
62 | { | 73 | { |
63 | if (!is_bad_inode(inode)) | 74 | struct ext2_block_alloc_info *rsv; |
75 | int want_delete = 0; | ||
76 | |||
77 | if (!inode->i_nlink && !is_bad_inode(inode)) { | ||
78 | want_delete = 1; | ||
64 | dquot_initialize(inode); | 79 | dquot_initialize(inode); |
80 | } else { | ||
81 | dquot_drop(inode); | ||
82 | } | ||
83 | |||
65 | truncate_inode_pages(&inode->i_data, 0); | 84 | truncate_inode_pages(&inode->i_data, 0); |
66 | 85 | ||
67 | if (is_bad_inode(inode)) | 86 | if (want_delete) { |
68 | goto no_delete; | 87 | /* set dtime */ |
69 | EXT2_I(inode)->i_dtime = get_seconds(); | 88 | EXT2_I(inode)->i_dtime = get_seconds(); |
70 | mark_inode_dirty(inode); | 89 | mark_inode_dirty(inode); |
71 | __ext2_write_inode(inode, inode_needs_sync(inode)); | 90 | __ext2_write_inode(inode, inode_needs_sync(inode)); |
91 | /* truncate to 0 */ | ||
92 | inode->i_size = 0; | ||
93 | if (inode->i_blocks) | ||
94 | ext2_truncate_blocks(inode, 0); | ||
95 | } | ||
96 | |||
97 | invalidate_inode_buffers(inode); | ||
98 | end_writeback(inode); | ||
72 | 99 | ||
73 | inode->i_size = 0; | 100 | ext2_discard_reservation(inode); |
74 | if (inode->i_blocks) | 101 | rsv = EXT2_I(inode)->i_block_alloc_info; |
75 | ext2_truncate (inode); | 102 | EXT2_I(inode)->i_block_alloc_info = NULL; |
76 | ext2_free_inode (inode); | 103 | if (unlikely(rsv)) |
104 | kfree(rsv); | ||
77 | 105 | ||
78 | return; | 106 | if (want_delete) |
79 | no_delete: | 107 | ext2_free_inode(inode); |
80 | clear_inode(inode); /* We must guarantee clearing of inode... */ | ||
81 | } | 108 | } |
82 | 109 | ||
83 | typedef struct { | 110 | typedef struct { |
@@ -412,6 +439,8 @@ static int ext2_alloc_blocks(struct inode *inode, | |||
412 | failed_out: | 439 | failed_out: |
413 | for (i = 0; i <index; i++) | 440 | for (i = 0; i <index; i++) |
414 | ext2_free_blocks(inode, new_blocks[i], 1); | 441 | ext2_free_blocks(inode, new_blocks[i], 1); |
442 | if (index) | ||
443 | mark_inode_dirty(inode); | ||
415 | return ret; | 444 | return ret; |
416 | } | 445 | } |
417 | 446 | ||
@@ -754,21 +783,30 @@ ext2_readpages(struct file *file, struct address_space *mapping, | |||
754 | return mpage_readpages(mapping, pages, nr_pages, ext2_get_block); | 783 | return mpage_readpages(mapping, pages, nr_pages, ext2_get_block); |
755 | } | 784 | } |
756 | 785 | ||
757 | int __ext2_write_begin(struct file *file, struct address_space *mapping, | 786 | static int |
787 | ext2_write_begin(struct file *file, struct address_space *mapping, | ||
758 | loff_t pos, unsigned len, unsigned flags, | 788 | loff_t pos, unsigned len, unsigned flags, |
759 | struct page **pagep, void **fsdata) | 789 | struct page **pagep, void **fsdata) |
760 | { | 790 | { |
761 | return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 791 | int ret; |
762 | ext2_get_block); | 792 | |
793 | ret = block_write_begin(mapping, pos, len, flags, pagep, | ||
794 | ext2_get_block); | ||
795 | if (ret < 0) | ||
796 | ext2_write_failed(mapping, pos + len); | ||
797 | return ret; | ||
763 | } | 798 | } |
764 | 799 | ||
765 | static int | 800 | static int ext2_write_end(struct file *file, struct address_space *mapping, |
766 | ext2_write_begin(struct file *file, struct address_space *mapping, | 801 | loff_t pos, unsigned len, unsigned copied, |
767 | loff_t pos, unsigned len, unsigned flags, | 802 | struct page *page, void *fsdata) |
768 | struct page **pagep, void **fsdata) | ||
769 | { | 803 | { |
770 | *pagep = NULL; | 804 | int ret; |
771 | return __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata); | 805 | |
806 | ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); | ||
807 | if (ret < len) | ||
808 | ext2_write_failed(mapping, pos + len); | ||
809 | return ret; | ||
772 | } | 810 | } |
773 | 811 | ||
774 | static int | 812 | static int |
@@ -776,13 +814,13 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping, | |||
776 | loff_t pos, unsigned len, unsigned flags, | 814 | loff_t pos, unsigned len, unsigned flags, |
777 | struct page **pagep, void **fsdata) | 815 | struct page **pagep, void **fsdata) |
778 | { | 816 | { |
779 | /* | 817 | int ret; |
780 | * Dir-in-pagecache still uses ext2_write_begin. Would have to rework | 818 | |
781 | * directory handling code to pass around offsets rather than struct | 819 | ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata, |
782 | * pages in order to make this work easily. | 820 | ext2_get_block); |
783 | */ | 821 | if (ret < 0) |
784 | return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 822 | ext2_write_failed(mapping, pos + len); |
785 | ext2_get_block); | 823 | return ret; |
786 | } | 824 | } |
787 | 825 | ||
788 | static int ext2_nobh_writepage(struct page *page, | 826 | static int ext2_nobh_writepage(struct page *page, |
@@ -801,10 +839,15 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
801 | loff_t offset, unsigned long nr_segs) | 839 | loff_t offset, unsigned long nr_segs) |
802 | { | 840 | { |
803 | struct file *file = iocb->ki_filp; | 841 | struct file *file = iocb->ki_filp; |
804 | struct inode *inode = file->f_mapping->host; | 842 | struct address_space *mapping = file->f_mapping; |
805 | 843 | struct inode *inode = mapping->host; | |
806 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 844 | ssize_t ret; |
807 | offset, nr_segs, ext2_get_block, NULL); | 845 | |
846 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, | ||
847 | iov, offset, nr_segs, ext2_get_block, NULL); | ||
848 | if (ret < 0 && (rw & WRITE)) | ||
849 | ext2_write_failed(mapping, offset + iov_length(iov, nr_segs)); | ||
850 | return ret; | ||
808 | } | 851 | } |
809 | 852 | ||
810 | static int | 853 | static int |
@@ -819,7 +862,7 @@ const struct address_space_operations ext2_aops = { | |||
819 | .writepage = ext2_writepage, | 862 | .writepage = ext2_writepage, |
820 | .sync_page = block_sync_page, | 863 | .sync_page = block_sync_page, |
821 | .write_begin = ext2_write_begin, | 864 | .write_begin = ext2_write_begin, |
822 | .write_end = generic_write_end, | 865 | .write_end = ext2_write_end, |
823 | .bmap = ext2_bmap, | 866 | .bmap = ext2_bmap, |
824 | .direct_IO = ext2_direct_IO, | 867 | .direct_IO = ext2_direct_IO, |
825 | .writepages = ext2_writepages, | 868 | .writepages = ext2_writepages, |
@@ -968,8 +1011,8 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q) | |||
968 | else if (block_to_free == nr - count) | 1011 | else if (block_to_free == nr - count) |
969 | count++; | 1012 | count++; |
970 | else { | 1013 | else { |
971 | mark_inode_dirty(inode); | ||
972 | ext2_free_blocks (inode, block_to_free, count); | 1014 | ext2_free_blocks (inode, block_to_free, count); |
1015 | mark_inode_dirty(inode); | ||
973 | free_this: | 1016 | free_this: |
974 | block_to_free = nr; | 1017 | block_to_free = nr; |
975 | count = 1; | 1018 | count = 1; |
@@ -977,8 +1020,8 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q) | |||
977 | } | 1020 | } |
978 | } | 1021 | } |
979 | if (count > 0) { | 1022 | if (count > 0) { |
980 | mark_inode_dirty(inode); | ||
981 | ext2_free_blocks (inode, block_to_free, count); | 1023 | ext2_free_blocks (inode, block_to_free, count); |
1024 | mark_inode_dirty(inode); | ||
982 | } | 1025 | } |
983 | } | 1026 | } |
984 | 1027 | ||
@@ -1028,7 +1071,7 @@ static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int de | |||
1028 | ext2_free_data(inode, p, q); | 1071 | ext2_free_data(inode, p, q); |
1029 | } | 1072 | } |
1030 | 1073 | ||
1031 | void ext2_truncate(struct inode *inode) | 1074 | static void __ext2_truncate_blocks(struct inode *inode, loff_t offset) |
1032 | { | 1075 | { |
1033 | __le32 *i_data = EXT2_I(inode)->i_data; | 1076 | __le32 *i_data = EXT2_I(inode)->i_data; |
1034 | struct ext2_inode_info *ei = EXT2_I(inode); | 1077 | struct ext2_inode_info *ei = EXT2_I(inode); |
@@ -1040,27 +1083,8 @@ void ext2_truncate(struct inode *inode) | |||
1040 | int n; | 1083 | int n; |
1041 | long iblock; | 1084 | long iblock; |
1042 | unsigned blocksize; | 1085 | unsigned blocksize; |
1043 | |||
1044 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | ||
1045 | S_ISLNK(inode->i_mode))) | ||
1046 | return; | ||
1047 | if (ext2_inode_is_fast_symlink(inode)) | ||
1048 | return; | ||
1049 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
1050 | return; | ||
1051 | |||
1052 | blocksize = inode->i_sb->s_blocksize; | 1086 | blocksize = inode->i_sb->s_blocksize; |
1053 | iblock = (inode->i_size + blocksize-1) | 1087 | iblock = (offset + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); |
1054 | >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); | ||
1055 | |||
1056 | if (mapping_is_xip(inode->i_mapping)) | ||
1057 | xip_truncate_page(inode->i_mapping, inode->i_size); | ||
1058 | else if (test_opt(inode->i_sb, NOBH)) | ||
1059 | nobh_truncate_page(inode->i_mapping, | ||
1060 | inode->i_size, ext2_get_block); | ||
1061 | else | ||
1062 | block_truncate_page(inode->i_mapping, | ||
1063 | inode->i_size, ext2_get_block); | ||
1064 | 1088 | ||
1065 | n = ext2_block_to_path(inode, iblock, offsets, NULL); | 1089 | n = ext2_block_to_path(inode, iblock, offsets, NULL); |
1066 | if (n == 0) | 1090 | if (n == 0) |
@@ -1128,6 +1152,54 @@ do_indirects: | |||
1128 | ext2_discard_reservation(inode); | 1152 | ext2_discard_reservation(inode); |
1129 | 1153 | ||
1130 | mutex_unlock(&ei->truncate_mutex); | 1154 | mutex_unlock(&ei->truncate_mutex); |
1155 | } | ||
1156 | |||
1157 | static void ext2_truncate_blocks(struct inode *inode, loff_t offset) | ||
1158 | { | ||
1159 | /* | ||
1160 | * XXX: it seems like a bug here that we don't allow | ||
1161 | * IS_APPEND inode to have blocks-past-i_size trimmed off. | ||
1162 | * review and fix this. | ||
1163 | * | ||
1164 | * Also would be nice to be able to handle IO errors and such, | ||
1165 | * but that's probably too much to ask. | ||
1166 | */ | ||
1167 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | ||
1168 | S_ISLNK(inode->i_mode))) | ||
1169 | return; | ||
1170 | if (ext2_inode_is_fast_symlink(inode)) | ||
1171 | return; | ||
1172 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
1173 | return; | ||
1174 | __ext2_truncate_blocks(inode, offset); | ||
1175 | } | ||
1176 | |||
1177 | static int ext2_setsize(struct inode *inode, loff_t newsize) | ||
1178 | { | ||
1179 | int error; | ||
1180 | |||
1181 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | ||
1182 | S_ISLNK(inode->i_mode))) | ||
1183 | return -EINVAL; | ||
1184 | if (ext2_inode_is_fast_symlink(inode)) | ||
1185 | return -EINVAL; | ||
1186 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
1187 | return -EPERM; | ||
1188 | |||
1189 | if (mapping_is_xip(inode->i_mapping)) | ||
1190 | error = xip_truncate_page(inode->i_mapping, newsize); | ||
1191 | else if (test_opt(inode->i_sb, NOBH)) | ||
1192 | error = nobh_truncate_page(inode->i_mapping, | ||
1193 | newsize, ext2_get_block); | ||
1194 | else | ||
1195 | error = block_truncate_page(inode->i_mapping, | ||
1196 | newsize, ext2_get_block); | ||
1197 | if (error) | ||
1198 | return error; | ||
1199 | |||
1200 | truncate_setsize(inode, newsize); | ||
1201 | __ext2_truncate_blocks(inode, newsize); | ||
1202 | |||
1131 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | 1203 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; |
1132 | if (inode_needs_sync(inode)) { | 1204 | if (inode_needs_sync(inode)) { |
1133 | sync_mapping_buffers(inode->i_mapping); | 1205 | sync_mapping_buffers(inode->i_mapping); |
@@ -1135,6 +1207,8 @@ do_indirects: | |||
1135 | } else { | 1207 | } else { |
1136 | mark_inode_dirty(inode); | 1208 | mark_inode_dirty(inode); |
1137 | } | 1209 | } |
1210 | |||
1211 | return 0; | ||
1138 | } | 1212 | } |
1139 | 1213 | ||
1140 | static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino, | 1214 | static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino, |
@@ -1406,11 +1480,11 @@ static int __ext2_write_inode(struct inode *inode, int do_sync) | |||
1406 | /* If this is the first large file | 1480 | /* If this is the first large file |
1407 | * created, add a flag to the superblock. | 1481 | * created, add a flag to the superblock. |
1408 | */ | 1482 | */ |
1409 | lock_kernel(); | 1483 | spin_lock(&EXT2_SB(sb)->s_lock); |
1410 | ext2_update_dynamic_rev(sb); | 1484 | ext2_update_dynamic_rev(sb); |
1411 | EXT2_SET_RO_COMPAT_FEATURE(sb, | 1485 | EXT2_SET_RO_COMPAT_FEATURE(sb, |
1412 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE); | 1486 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE); |
1413 | unlock_kernel(); | 1487 | spin_unlock(&EXT2_SB(sb)->s_lock); |
1414 | ext2_write_super(sb); | 1488 | ext2_write_super(sb); |
1415 | } | 1489 | } |
1416 | } | 1490 | } |
@@ -1467,7 +1541,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) | |||
1467 | if (error) | 1541 | if (error) |
1468 | return error; | 1542 | return error; |
1469 | 1543 | ||
1470 | if (iattr->ia_valid & ATTR_SIZE) | 1544 | if (is_quota_modification(inode, iattr)) |
1471 | dquot_initialize(inode); | 1545 | dquot_initialize(inode); |
1472 | if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || | 1546 | if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || |
1473 | (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { | 1547 | (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { |
@@ -1475,8 +1549,15 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) | |||
1475 | if (error) | 1549 | if (error) |
1476 | return error; | 1550 | return error; |
1477 | } | 1551 | } |
1478 | error = inode_setattr(inode, iattr); | 1552 | if (iattr->ia_valid & ATTR_SIZE && iattr->ia_size != inode->i_size) { |
1479 | if (!error && (iattr->ia_valid & ATTR_MODE)) | 1553 | error = ext2_setsize(inode, iattr->ia_size); |
1554 | if (error) | ||
1555 | return error; | ||
1556 | } | ||
1557 | setattr_copy(inode, iattr); | ||
1558 | if (iattr->ia_valid & ATTR_MODE) | ||
1480 | error = ext2_acl_chmod(inode); | 1559 | error = ext2_acl_chmod(inode); |
1560 | mark_inode_dirty(inode); | ||
1561 | |||
1481 | return error; | 1562 | return error; |
1482 | } | 1563 | } |