diff options
Diffstat (limited to 'fs/fat/inode.c')
-rw-r--r-- | fs/fat/inode.c | 119 |
1 files changed, 102 insertions, 17 deletions
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index a0f9b9fe1307..e7f4aa7fc686 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -18,10 +18,12 @@ | |||
18 | #include <linux/seq_file.h> | 18 | #include <linux/seq_file.h> |
19 | #include <linux/msdos_fs.h> | 19 | #include <linux/msdos_fs.h> |
20 | #include <linux/pagemap.h> | 20 | #include <linux/pagemap.h> |
21 | #include <linux/mpage.h> | ||
21 | #include <linux/buffer_head.h> | 22 | #include <linux/buffer_head.h> |
22 | #include <linux/mount.h> | 23 | #include <linux/mount.h> |
23 | #include <linux/vfs.h> | 24 | #include <linux/vfs.h> |
24 | #include <linux/parser.h> | 25 | #include <linux/parser.h> |
26 | #include <linux/uio.h> | ||
25 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
26 | 28 | ||
27 | #ifndef CONFIG_FAT_DEFAULT_IOCHARSET | 29 | #ifndef CONFIG_FAT_DEFAULT_IOCHARSET |
@@ -48,51 +50,97 @@ static int fat_add_cluster(struct inode *inode) | |||
48 | return err; | 50 | return err; |
49 | } | 51 | } |
50 | 52 | ||
51 | static int fat_get_block(struct inode *inode, sector_t iblock, | 53 | static int __fat_get_blocks(struct inode *inode, sector_t iblock, |
52 | struct buffer_head *bh_result, int create) | 54 | unsigned long *max_blocks, |
55 | struct buffer_head *bh_result, int create) | ||
53 | { | 56 | { |
54 | struct super_block *sb = inode->i_sb; | 57 | struct super_block *sb = inode->i_sb; |
58 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
55 | sector_t phys; | 59 | sector_t phys; |
56 | int err; | 60 | unsigned long mapped_blocks; |
61 | int err, offset; | ||
57 | 62 | ||
58 | err = fat_bmap(inode, iblock, &phys); | 63 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks); |
59 | if (err) | 64 | if (err) |
60 | return err; | 65 | return err; |
61 | if (phys) { | 66 | if (phys) { |
62 | map_bh(bh_result, sb, phys); | 67 | map_bh(bh_result, sb, phys); |
68 | *max_blocks = min(mapped_blocks, *max_blocks); | ||
63 | return 0; | 69 | return 0; |
64 | } | 70 | } |
65 | if (!create) | 71 | if (!create) |
66 | return 0; | 72 | return 0; |
73 | |||
67 | if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { | 74 | if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { |
68 | fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", | 75 | fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", |
69 | MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); | 76 | MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); |
70 | return -EIO; | 77 | return -EIO; |
71 | } | 78 | } |
72 | if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) { | 79 | |
80 | offset = (unsigned long)iblock & (sbi->sec_per_clus - 1); | ||
81 | if (!offset) { | ||
82 | /* TODO: multiple cluster allocation would be desirable. */ | ||
73 | err = fat_add_cluster(inode); | 83 | err = fat_add_cluster(inode); |
74 | if (err) | 84 | if (err) |
75 | return err; | 85 | return err; |
76 | } | 86 | } |
77 | MSDOS_I(inode)->mmu_private += sb->s_blocksize; | 87 | /* available blocks on this cluster */ |
78 | err = fat_bmap(inode, iblock, &phys); | 88 | mapped_blocks = sbi->sec_per_clus - offset; |
89 | |||
90 | *max_blocks = min(mapped_blocks, *max_blocks); | ||
91 | MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; | ||
92 | |||
93 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks); | ||
79 | if (err) | 94 | if (err) |
80 | return err; | 95 | return err; |
81 | if (!phys) | 96 | BUG_ON(!phys); |
82 | BUG(); | 97 | BUG_ON(*max_blocks != mapped_blocks); |
83 | set_buffer_new(bh_result); | 98 | set_buffer_new(bh_result); |
84 | map_bh(bh_result, sb, phys); | 99 | map_bh(bh_result, sb, phys); |
85 | return 0; | 100 | return 0; |
86 | } | 101 | } |
87 | 102 | ||
103 | static int fat_get_blocks(struct inode *inode, sector_t iblock, | ||
104 | unsigned long max_blocks, | ||
105 | struct buffer_head *bh_result, int create) | ||
106 | { | ||
107 | struct super_block *sb = inode->i_sb; | ||
108 | int err; | ||
109 | |||
110 | err = __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create); | ||
111 | if (err) | ||
112 | return err; | ||
113 | bh_result->b_size = max_blocks << sb->s_blocksize_bits; | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int fat_get_block(struct inode *inode, sector_t iblock, | ||
118 | struct buffer_head *bh_result, int create) | ||
119 | { | ||
120 | unsigned long max_blocks = 1; | ||
121 | return __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create); | ||
122 | } | ||
123 | |||
88 | static int fat_writepage(struct page *page, struct writeback_control *wbc) | 124 | static int fat_writepage(struct page *page, struct writeback_control *wbc) |
89 | { | 125 | { |
90 | return block_write_full_page(page, fat_get_block, wbc); | 126 | return block_write_full_page(page, fat_get_block, wbc); |
91 | } | 127 | } |
92 | 128 | ||
129 | static int fat_writepages(struct address_space *mapping, | ||
130 | struct writeback_control *wbc) | ||
131 | { | ||
132 | return mpage_writepages(mapping, wbc, fat_get_block); | ||
133 | } | ||
134 | |||
93 | static int fat_readpage(struct file *file, struct page *page) | 135 | static int fat_readpage(struct file *file, struct page *page) |
94 | { | 136 | { |
95 | return block_read_full_page(page, fat_get_block); | 137 | return mpage_readpage(page, fat_get_block); |
138 | } | ||
139 | |||
140 | static int fat_readpages(struct file *file, struct address_space *mapping, | ||
141 | struct list_head *pages, unsigned nr_pages) | ||
142 | { | ||
143 | return mpage_readpages(mapping, pages, nr_pages, fat_get_block); | ||
96 | } | 144 | } |
97 | 145 | ||
98 | static int fat_prepare_write(struct file *file, struct page *page, | 146 | static int fat_prepare_write(struct file *file, struct page *page, |
@@ -115,6 +163,34 @@ static int fat_commit_write(struct file *file, struct page *page, | |||
115 | return err; | 163 | return err; |
116 | } | 164 | } |
117 | 165 | ||
166 | static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, | ||
167 | const struct iovec *iov, | ||
168 | loff_t offset, unsigned long nr_segs) | ||
169 | { | ||
170 | struct file *file = iocb->ki_filp; | ||
171 | struct inode *inode = file->f_mapping->host; | ||
172 | |||
173 | if (rw == WRITE) { | ||
174 | /* | ||
175 | * FIXME: blockdev_direct_IO() doesn't use ->prepare_write(), | ||
176 | * so we need to update the ->mmu_private to block boundary. | ||
177 | * | ||
178 | * But we must fill the remaining area or hole by nul for | ||
179 | * updating ->mmu_private. | ||
180 | */ | ||
181 | loff_t size = offset + iov_length(iov, nr_segs); | ||
182 | if (MSDOS_I(inode)->mmu_private < size) | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * FAT need to use the DIO_LOCKING for avoiding the race | ||
188 | * condition of fat_get_block() and ->truncate(). | ||
189 | */ | ||
190 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | ||
191 | offset, nr_segs, fat_get_blocks, NULL); | ||
192 | } | ||
193 | |||
118 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) | 194 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) |
119 | { | 195 | { |
120 | return generic_block_bmap(mapping, block, fat_get_block); | 196 | return generic_block_bmap(mapping, block, fat_get_block); |
@@ -122,10 +198,13 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block) | |||
122 | 198 | ||
123 | static struct address_space_operations fat_aops = { | 199 | static struct address_space_operations fat_aops = { |
124 | .readpage = fat_readpage, | 200 | .readpage = fat_readpage, |
201 | .readpages = fat_readpages, | ||
125 | .writepage = fat_writepage, | 202 | .writepage = fat_writepage, |
203 | .writepages = fat_writepages, | ||
126 | .sync_page = block_sync_page, | 204 | .sync_page = block_sync_page, |
127 | .prepare_write = fat_prepare_write, | 205 | .prepare_write = fat_prepare_write, |
128 | .commit_write = fat_commit_write, | 206 | .commit_write = fat_commit_write, |
207 | .direct_IO = fat_direct_IO, | ||
129 | .bmap = _fat_bmap | 208 | .bmap = _fat_bmap |
130 | }; | 209 | }; |
131 | 210 | ||
@@ -182,7 +261,7 @@ void fat_attach(struct inode *inode, loff_t i_pos) | |||
182 | spin_unlock(&sbi->inode_hash_lock); | 261 | spin_unlock(&sbi->inode_hash_lock); |
183 | } | 262 | } |
184 | 263 | ||
185 | EXPORT_SYMBOL(fat_attach); | 264 | EXPORT_SYMBOL_GPL(fat_attach); |
186 | 265 | ||
187 | void fat_detach(struct inode *inode) | 266 | void fat_detach(struct inode *inode) |
188 | { | 267 | { |
@@ -193,7 +272,7 @@ void fat_detach(struct inode *inode) | |||
193 | spin_unlock(&sbi->inode_hash_lock); | 272 | spin_unlock(&sbi->inode_hash_lock); |
194 | } | 273 | } |
195 | 274 | ||
196 | EXPORT_SYMBOL(fat_detach); | 275 | EXPORT_SYMBOL_GPL(fat_detach); |
197 | 276 | ||
198 | struct inode *fat_iget(struct super_block *sb, loff_t i_pos) | 277 | struct inode *fat_iget(struct super_block *sb, loff_t i_pos) |
199 | { | 278 | { |
@@ -347,7 +426,7 @@ out: | |||
347 | return inode; | 426 | return inode; |
348 | } | 427 | } |
349 | 428 | ||
350 | EXPORT_SYMBOL(fat_build_inode); | 429 | EXPORT_SYMBOL_GPL(fat_build_inode); |
351 | 430 | ||
352 | static void fat_delete_inode(struct inode *inode) | 431 | static void fat_delete_inode(struct inode *inode) |
353 | { | 432 | { |
@@ -374,12 +453,17 @@ static void fat_clear_inode(struct inode *inode) | |||
374 | unlock_kernel(); | 453 | unlock_kernel(); |
375 | } | 454 | } |
376 | 455 | ||
377 | static void fat_put_super(struct super_block *sb) | 456 | static void fat_write_super(struct super_block *sb) |
378 | { | 457 | { |
379 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 458 | sb->s_dirt = 0; |
380 | 459 | ||
381 | if (!(sb->s_flags & MS_RDONLY)) | 460 | if (!(sb->s_flags & MS_RDONLY)) |
382 | fat_clusters_flush(sb); | 461 | fat_clusters_flush(sb); |
462 | } | ||
463 | |||
464 | static void fat_put_super(struct super_block *sb) | ||
465 | { | ||
466 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
383 | 467 | ||
384 | if (sbi->nls_disk) { | 468 | if (sbi->nls_disk) { |
385 | unload_nls(sbi->nls_disk); | 469 | unload_nls(sbi->nls_disk); |
@@ -537,7 +621,7 @@ int fat_sync_inode(struct inode *inode) | |||
537 | return fat_write_inode(inode, 1); | 621 | return fat_write_inode(inode, 1); |
538 | } | 622 | } |
539 | 623 | ||
540 | EXPORT_SYMBOL(fat_sync_inode); | 624 | EXPORT_SYMBOL_GPL(fat_sync_inode); |
541 | 625 | ||
542 | static int fat_show_options(struct seq_file *m, struct vfsmount *mnt); | 626 | static int fat_show_options(struct seq_file *m, struct vfsmount *mnt); |
543 | static struct super_operations fat_sops = { | 627 | static struct super_operations fat_sops = { |
@@ -546,6 +630,7 @@ static struct super_operations fat_sops = { | |||
546 | .write_inode = fat_write_inode, | 630 | .write_inode = fat_write_inode, |
547 | .delete_inode = fat_delete_inode, | 631 | .delete_inode = fat_delete_inode, |
548 | .put_super = fat_put_super, | 632 | .put_super = fat_put_super, |
633 | .write_super = fat_write_super, | ||
549 | .statfs = fat_statfs, | 634 | .statfs = fat_statfs, |
550 | .clear_inode = fat_clear_inode, | 635 | .clear_inode = fat_clear_inode, |
551 | .remount_fs = fat_remount, | 636 | .remount_fs = fat_remount, |
@@ -1347,7 +1432,7 @@ out_fail: | |||
1347 | return error; | 1432 | return error; |
1348 | } | 1433 | } |
1349 | 1434 | ||
1350 | EXPORT_SYMBOL(fat_fill_super); | 1435 | EXPORT_SYMBOL_GPL(fat_fill_super); |
1351 | 1436 | ||
1352 | int __init fat_cache_init(void); | 1437 | int __init fat_cache_init(void); |
1353 | void fat_cache_destroy(void); | 1438 | void fat_cache_destroy(void); |