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); |
