aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat/inode.c')
-rw-r--r--fs/fat/inode.c119
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
51static int fat_get_block(struct inode *inode, sector_t iblock, 53static 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
103static 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
117static 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
88static int fat_writepage(struct page *page, struct writeback_control *wbc) 124static 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
129static int fat_writepages(struct address_space *mapping,
130 struct writeback_control *wbc)
131{
132 return mpage_writepages(mapping, wbc, fat_get_block);
133}
134
93static int fat_readpage(struct file *file, struct page *page) 135static 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
140static 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
98static int fat_prepare_write(struct file *file, struct page *page, 146static 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
166static 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
118static sector_t _fat_bmap(struct address_space *mapping, sector_t block) 194static 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
123static struct address_space_operations fat_aops = { 199static 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
185EXPORT_SYMBOL(fat_attach); 264EXPORT_SYMBOL_GPL(fat_attach);
186 265
187void fat_detach(struct inode *inode) 266void 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
196EXPORT_SYMBOL(fat_detach); 275EXPORT_SYMBOL_GPL(fat_detach);
197 276
198struct inode *fat_iget(struct super_block *sb, loff_t i_pos) 277struct 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
350EXPORT_SYMBOL(fat_build_inode); 429EXPORT_SYMBOL_GPL(fat_build_inode);
351 430
352static void fat_delete_inode(struct inode *inode) 431static 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
377static void fat_put_super(struct super_block *sb) 456static 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
464static 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
540EXPORT_SYMBOL(fat_sync_inode); 624EXPORT_SYMBOL_GPL(fat_sync_inode);
541 625
542static int fat_show_options(struct seq_file *m, struct vfsmount *mnt); 626static int fat_show_options(struct seq_file *m, struct vfsmount *mnt);
543static struct super_operations fat_sops = { 627static 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
1350EXPORT_SYMBOL(fat_fill_super); 1435EXPORT_SYMBOL_GPL(fat_fill_super);
1351 1436
1352int __init fat_cache_init(void); 1437int __init fat_cache_init(void);
1353void fat_cache_destroy(void); 1438void fat_cache_destroy(void);