Commit b522412aeabadbb302fd4338eaabf09d10e2d29c
1 parent
964f536966
Exists in
master
and in
4 other branches
Sanitize ->fsync() for FAT
* mark directory data blocks as assoc. metadata * add new inode to deal with FAT, mark FAT blocks as assoc. metadata of that * now ->fsync() is trivial both for files and directories Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 7 changed files with 49 additions and 19 deletions Side-by-side Diff
fs/fat/dir.c
... | ... | @@ -840,7 +840,7 @@ |
840 | 840 | #ifdef CONFIG_COMPAT |
841 | 841 | .compat_ioctl = fat_compat_dir_ioctl, |
842 | 842 | #endif |
843 | - .fsync = file_fsync, | |
843 | + .fsync = fat_file_fsync, | |
844 | 844 | }; |
845 | 845 | |
846 | 846 | static int fat_get_short_entry(struct inode *dir, loff_t *pos, |
... | ... | @@ -967,7 +967,7 @@ |
967 | 967 | de++; |
968 | 968 | nr_slots--; |
969 | 969 | } |
970 | - mark_buffer_dirty(bh); | |
970 | + mark_buffer_dirty_inode(bh, dir); | |
971 | 971 | if (IS_DIRSYNC(dir)) |
972 | 972 | err = sync_dirty_buffer(bh); |
973 | 973 | brelse(bh); |
... | ... | @@ -1001,7 +1001,7 @@ |
1001 | 1001 | de--; |
1002 | 1002 | nr_slots--; |
1003 | 1003 | } |
1004 | - mark_buffer_dirty(bh); | |
1004 | + mark_buffer_dirty_inode(bh, dir); | |
1005 | 1005 | if (IS_DIRSYNC(dir)) |
1006 | 1006 | err = sync_dirty_buffer(bh); |
1007 | 1007 | brelse(bh); |
... | ... | @@ -1051,7 +1051,7 @@ |
1051 | 1051 | } |
1052 | 1052 | memset(bhs[n]->b_data, 0, sb->s_blocksize); |
1053 | 1053 | set_buffer_uptodate(bhs[n]); |
1054 | - mark_buffer_dirty(bhs[n]); | |
1054 | + mark_buffer_dirty_inode(bhs[n], dir); | |
1055 | 1055 | |
1056 | 1056 | n++; |
1057 | 1057 | blknr++; |
... | ... | @@ -1131,7 +1131,7 @@ |
1131 | 1131 | de[0].size = de[1].size = 0; |
1132 | 1132 | memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); |
1133 | 1133 | set_buffer_uptodate(bhs[0]); |
1134 | - mark_buffer_dirty(bhs[0]); | |
1134 | + mark_buffer_dirty_inode(bhs[0], dir); | |
1135 | 1135 | |
1136 | 1136 | err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE); |
1137 | 1137 | if (err) |
... | ... | @@ -1193,7 +1193,7 @@ |
1193 | 1193 | slots += copy; |
1194 | 1194 | size -= copy; |
1195 | 1195 | set_buffer_uptodate(bhs[n]); |
1196 | - mark_buffer_dirty(bhs[n]); | |
1196 | + mark_buffer_dirty_inode(bhs[n], dir); | |
1197 | 1197 | if (!size) |
1198 | 1198 | break; |
1199 | 1199 | n++; |
... | ... | @@ -1293,7 +1293,7 @@ |
1293 | 1293 | for (i = 0; i < long_bhs; i++) { |
1294 | 1294 | int copy = min_t(int, sb->s_blocksize - offset, size); |
1295 | 1295 | memcpy(bhs[i]->b_data + offset, slots, copy); |
1296 | - mark_buffer_dirty(bhs[i]); | |
1296 | + mark_buffer_dirty_inode(bhs[i], dir); | |
1297 | 1297 | offset = 0; |
1298 | 1298 | slots += copy; |
1299 | 1299 | size -= copy; |
... | ... | @@ -1304,7 +1304,7 @@ |
1304 | 1304 | /* Fill the short name slot. */ |
1305 | 1305 | int copy = min_t(int, sb->s_blocksize - offset, size); |
1306 | 1306 | memcpy(bhs[i]->b_data + offset, slots, copy); |
1307 | - mark_buffer_dirty(bhs[i]); | |
1307 | + mark_buffer_dirty_inode(bhs[i], dir); | |
1308 | 1308 | if (IS_DIRSYNC(dir)) |
1309 | 1309 | err = sync_dirty_buffer(bhs[i]); |
1310 | 1310 | } |
fs/fat/fat.h
... | ... | @@ -74,6 +74,7 @@ |
74 | 74 | |
75 | 75 | int fatent_shift; |
76 | 76 | struct fatent_operations *fatent_ops; |
77 | + struct inode *fat_inode; | |
77 | 78 | |
78 | 79 | spinlock_t inode_hash_lock; |
79 | 80 | struct hlist_head inode_hashtable[FAT_HASH_SIZE]; |
... | ... | @@ -251,6 +252,7 @@ |
251 | 252 | } u; |
252 | 253 | int nr_bhs; |
253 | 254 | struct buffer_head *bhs[2]; |
255 | + struct inode *fat_inode; | |
254 | 256 | }; |
255 | 257 | |
256 | 258 | static inline void fatent_init(struct fat_entry *fatent) |
... | ... | @@ -259,6 +261,7 @@ |
259 | 261 | fatent->entry = 0; |
260 | 262 | fatent->u.ent32_p = NULL; |
261 | 263 | fatent->bhs[0] = fatent->bhs[1] = NULL; |
264 | + fatent->fat_inode = NULL; | |
262 | 265 | } |
263 | 266 | |
264 | 267 | static inline void fatent_set_entry(struct fat_entry *fatent, int entry) |
... | ... | @@ -275,6 +278,7 @@ |
275 | 278 | brelse(fatent->bhs[i]); |
276 | 279 | fatent->nr_bhs = 0; |
277 | 280 | fatent->bhs[0] = fatent->bhs[1] = NULL; |
281 | + fatent->fat_inode = NULL; | |
278 | 282 | } |
279 | 283 | |
280 | 284 | extern void fat_ent_access_init(struct super_block *sb); |
... | ... | @@ -296,6 +300,8 @@ |
296 | 300 | extern void fat_truncate(struct inode *inode); |
297 | 301 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, |
298 | 302 | struct kstat *stat); |
303 | +extern int fat_file_fsync(struct file *file, struct dentry *dentry, | |
304 | + int datasync); | |
299 | 305 | |
300 | 306 | /* fat/inode.c */ |
301 | 307 | extern void fat_attach(struct inode *inode, loff_t i_pos); |
fs/fat/fatent.c
... | ... | @@ -73,6 +73,8 @@ |
73 | 73 | struct buffer_head **bhs = fatent->bhs; |
74 | 74 | |
75 | 75 | WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); |
76 | + fatent->fat_inode = MSDOS_SB(sb)->fat_inode; | |
77 | + | |
76 | 78 | bhs[0] = sb_bread(sb, blocknr); |
77 | 79 | if (!bhs[0]) |
78 | 80 | goto err; |
... | ... | @@ -103,6 +105,7 @@ |
103 | 105 | struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; |
104 | 106 | |
105 | 107 | WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); |
108 | + fatent->fat_inode = MSDOS_SB(sb)->fat_inode; | |
106 | 109 | fatent->bhs[0] = sb_bread(sb, blocknr); |
107 | 110 | if (!fatent->bhs[0]) { |
108 | 111 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", |
109 | 112 | |
... | ... | @@ -167,9 +170,9 @@ |
167 | 170 | } |
168 | 171 | spin_unlock(&fat12_entry_lock); |
169 | 172 | |
170 | - mark_buffer_dirty(fatent->bhs[0]); | |
173 | + mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); | |
171 | 174 | if (fatent->nr_bhs == 2) |
172 | - mark_buffer_dirty(fatent->bhs[1]); | |
175 | + mark_buffer_dirty_inode(fatent->bhs[1], fatent->fat_inode); | |
173 | 176 | } |
174 | 177 | |
175 | 178 | static void fat16_ent_put(struct fat_entry *fatent, int new) |
... | ... | @@ -178,7 +181,7 @@ |
178 | 181 | new = EOF_FAT16; |
179 | 182 | |
180 | 183 | *fatent->u.ent16_p = cpu_to_le16(new); |
181 | - mark_buffer_dirty(fatent->bhs[0]); | |
184 | + mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); | |
182 | 185 | } |
183 | 186 | |
184 | 187 | static void fat32_ent_put(struct fat_entry *fatent, int new) |
... | ... | @@ -189,7 +192,7 @@ |
189 | 192 | WARN_ON(new & 0xf0000000); |
190 | 193 | new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; |
191 | 194 | *fatent->u.ent32_p = cpu_to_le32(new); |
192 | - mark_buffer_dirty(fatent->bhs[0]); | |
195 | + mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); | |
193 | 196 | } |
194 | 197 | |
195 | 198 | static int fat12_ent_next(struct fat_entry *fatent) |
... | ... | @@ -381,7 +384,7 @@ |
381 | 384 | } |
382 | 385 | memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize); |
383 | 386 | set_buffer_uptodate(c_bh); |
384 | - mark_buffer_dirty(c_bh); | |
387 | + mark_buffer_dirty_inode(c_bh, sbi->fat_inode); | |
385 | 388 | if (sb->s_flags & MS_SYNCHRONOUS) |
386 | 389 | err = sync_dirty_buffer(c_bh); |
387 | 390 | brelse(c_bh); |
fs/fat/file.c
... | ... | @@ -133,6 +133,18 @@ |
133 | 133 | return 0; |
134 | 134 | } |
135 | 135 | |
136 | +int fat_file_fsync(struct file *filp, struct dentry *dentry, int datasync) | |
137 | +{ | |
138 | + struct inode *inode = dentry->d_inode; | |
139 | + int res, err; | |
140 | + | |
141 | + res = simple_fsync(filp, dentry, datasync); | |
142 | + err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); | |
143 | + | |
144 | + return res ? res : err; | |
145 | +} | |
146 | + | |
147 | + | |
136 | 148 | const struct file_operations fat_file_operations = { |
137 | 149 | .llseek = generic_file_llseek, |
138 | 150 | .read = do_sync_read, |
... | ... | @@ -142,7 +154,7 @@ |
142 | 154 | .mmap = generic_file_mmap, |
143 | 155 | .release = fat_file_release, |
144 | 156 | .ioctl = fat_generic_ioctl, |
145 | - .fsync = file_fsync, | |
157 | + .fsync = fat_file_fsync, | |
146 | 158 | .splice_read = generic_file_splice_read, |
147 | 159 | }; |
148 | 160 |
fs/fat/inode.c
... | ... | @@ -458,6 +458,8 @@ |
458 | 458 | if (sb->s_dirt) |
459 | 459 | fat_write_super(sb); |
460 | 460 | |
461 | + iput(sbi->fat_inode); | |
462 | + | |
461 | 463 | if (sbi->nls_disk) { |
462 | 464 | unload_nls(sbi->nls_disk); |
463 | 465 | sbi->nls_disk = NULL; |
... | ... | @@ -1183,7 +1185,7 @@ |
1183 | 1185 | int fat_fill_super(struct super_block *sb, void *data, int silent, |
1184 | 1186 | const struct inode_operations *fs_dir_inode_ops, int isvfat) |
1185 | 1187 | { |
1186 | - struct inode *root_inode = NULL; | |
1188 | + struct inode *root_inode = NULL, *fat_inode = NULL; | |
1187 | 1189 | struct buffer_head *bh; |
1188 | 1190 | struct fat_boot_sector *b; |
1189 | 1191 | struct msdos_sb_info *sbi; |
... | ... | @@ -1423,6 +1425,11 @@ |
1423 | 1425 | } |
1424 | 1426 | |
1425 | 1427 | error = -ENOMEM; |
1428 | + fat_inode = new_inode(sb); | |
1429 | + if (!fat_inode) | |
1430 | + goto out_fail; | |
1431 | + MSDOS_I(fat_inode)->i_pos = 0; | |
1432 | + sbi->fat_inode = fat_inode; | |
1426 | 1433 | root_inode = new_inode(sb); |
1427 | 1434 | if (!root_inode) |
1428 | 1435 | goto out_fail; |
... | ... | @@ -1448,6 +1455,8 @@ |
1448 | 1455 | " on dev %s.\n", sb->s_id); |
1449 | 1456 | |
1450 | 1457 | out_fail: |
1458 | + if (fat_inode) | |
1459 | + iput(fat_inode); | |
1451 | 1460 | if (root_inode) |
1452 | 1461 | iput(root_inode); |
1453 | 1462 | if (sbi->nls_io) |
fs/fat/namei_msdos.c
... | ... | @@ -544,7 +544,7 @@ |
544 | 544 | int start = MSDOS_I(new_dir)->i_logstart; |
545 | 545 | dotdot_de->start = cpu_to_le16(start); |
546 | 546 | dotdot_de->starthi = cpu_to_le16(start >> 16); |
547 | - mark_buffer_dirty(dotdot_bh); | |
547 | + mark_buffer_dirty_inode(dotdot_bh, old_inode); | |
548 | 548 | if (IS_DIRSYNC(new_dir)) { |
549 | 549 | err = sync_dirty_buffer(dotdot_bh); |
550 | 550 | if (err) |
... | ... | @@ -586,7 +586,7 @@ |
586 | 586 | int start = MSDOS_I(old_dir)->i_logstart; |
587 | 587 | dotdot_de->start = cpu_to_le16(start); |
588 | 588 | dotdot_de->starthi = cpu_to_le16(start >> 16); |
589 | - mark_buffer_dirty(dotdot_bh); | |
589 | + mark_buffer_dirty_inode(dotdot_bh, old_inode); | |
590 | 590 | corrupt |= sync_dirty_buffer(dotdot_bh); |
591 | 591 | } |
592 | 592 | error_inode: |
fs/fat/namei_vfat.c
... | ... | @@ -965,7 +965,7 @@ |
965 | 965 | int start = MSDOS_I(new_dir)->i_logstart; |
966 | 966 | dotdot_de->start = cpu_to_le16(start); |
967 | 967 | dotdot_de->starthi = cpu_to_le16(start >> 16); |
968 | - mark_buffer_dirty(dotdot_bh); | |
968 | + mark_buffer_dirty_inode(dotdot_bh, old_inode); | |
969 | 969 | if (IS_DIRSYNC(new_dir)) { |
970 | 970 | err = sync_dirty_buffer(dotdot_bh); |
971 | 971 | if (err) |
... | ... | @@ -1009,7 +1009,7 @@ |
1009 | 1009 | int start = MSDOS_I(old_dir)->i_logstart; |
1010 | 1010 | dotdot_de->start = cpu_to_le16(start); |
1011 | 1011 | dotdot_de->starthi = cpu_to_le16(start >> 16); |
1012 | - mark_buffer_dirty(dotdot_bh); | |
1012 | + mark_buffer_dirty_inode(dotdot_bh, old_inode); | |
1013 | 1013 | corrupt |= sync_dirty_buffer(dotdot_bh); |
1014 | 1014 | } |
1015 | 1015 | error_inode: |