diff options
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/cache.c | 14 | ||||
-rw-r--r-- | fs/fat/dir.c | 28 | ||||
-rw-r--r-- | fs/fat/fatent.c | 10 | ||||
-rw-r--r-- | fs/fat/file.c | 38 | ||||
-rw-r--r-- | fs/fat/inode.c | 119 | ||||
-rw-r--r-- | fs/fat/misc.c | 8 |
6 files changed, 169 insertions, 48 deletions
diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 77c24fcf71..1acc941245 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c | |||
@@ -295,7 +295,8 @@ static int fat_bmap_cluster(struct inode *inode, int cluster) | |||
295 | return dclus; | 295 | return dclus; |
296 | } | 296 | } |
297 | 297 | ||
298 | int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys) | 298 | int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, |
299 | unsigned long *mapped_blocks) | ||
299 | { | 300 | { |
300 | struct super_block *sb = inode->i_sb; | 301 | struct super_block *sb = inode->i_sb; |
301 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 302 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
@@ -303,9 +304,12 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys) | |||
303 | int cluster, offset; | 304 | int cluster, offset; |
304 | 305 | ||
305 | *phys = 0; | 306 | *phys = 0; |
307 | *mapped_blocks = 0; | ||
306 | if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) { | 308 | if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) { |
307 | if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) | 309 | if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) { |
308 | *phys = sector + sbi->dir_start; | 310 | *phys = sector + sbi->dir_start; |
311 | *mapped_blocks = 1; | ||
312 | } | ||
309 | return 0; | 313 | return 0; |
310 | } | 314 | } |
311 | last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1)) | 315 | last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1)) |
@@ -318,7 +322,11 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys) | |||
318 | cluster = fat_bmap_cluster(inode, cluster); | 322 | cluster = fat_bmap_cluster(inode, cluster); |
319 | if (cluster < 0) | 323 | if (cluster < 0) |
320 | return cluster; | 324 | return cluster; |
321 | else if (cluster) | 325 | else if (cluster) { |
322 | *phys = fat_clus_to_blknr(sbi, cluster) + offset; | 326 | *phys = fat_clus_to_blknr(sbi, cluster) + offset; |
327 | *mapped_blocks = sbi->sec_per_clus - offset; | ||
328 | if (*mapped_blocks > last_block - sector) | ||
329 | *mapped_blocks = last_block - sector; | ||
330 | } | ||
323 | return 0; | 331 | return 0; |
324 | } | 332 | } |
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index ba824964b9..db0de5c621 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -45,8 +45,8 @@ static inline void fat_dir_readahead(struct inode *dir, sector_t iblock, | |||
45 | if ((sbi->fat_bits != 32) && (dir->i_ino == MSDOS_ROOT_INO)) | 45 | if ((sbi->fat_bits != 32) && (dir->i_ino == MSDOS_ROOT_INO)) |
46 | return; | 46 | return; |
47 | 47 | ||
48 | bh = sb_getblk(sb, phys); | 48 | bh = sb_find_get_block(sb, phys); |
49 | if (bh && !buffer_uptodate(bh)) { | 49 | if (bh == NULL || !buffer_uptodate(bh)) { |
50 | for (sec = 0; sec < sbi->sec_per_clus; sec++) | 50 | for (sec = 0; sec < sbi->sec_per_clus; sec++) |
51 | sb_breadahead(sb, phys + sec); | 51 | sb_breadahead(sb, phys + sec); |
52 | } | 52 | } |
@@ -68,8 +68,8 @@ static int fat__get_entry(struct inode *dir, loff_t *pos, | |||
68 | { | 68 | { |
69 | struct super_block *sb = dir->i_sb; | 69 | struct super_block *sb = dir->i_sb; |
70 | sector_t phys, iblock; | 70 | sector_t phys, iblock; |
71 | int offset; | 71 | unsigned long mapped_blocks; |
72 | int err; | 72 | int err, offset; |
73 | 73 | ||
74 | next: | 74 | next: |
75 | if (*bh) | 75 | if (*bh) |
@@ -77,7 +77,7 @@ next: | |||
77 | 77 | ||
78 | *bh = NULL; | 78 | *bh = NULL; |
79 | iblock = *pos >> sb->s_blocksize_bits; | 79 | iblock = *pos >> sb->s_blocksize_bits; |
80 | err = fat_bmap(dir, iblock, &phys); | 80 | err = fat_bmap(dir, iblock, &phys, &mapped_blocks); |
81 | if (err || !phys) | 81 | if (err || !phys) |
82 | return -1; /* beyond EOF or error */ | 82 | return -1; /* beyond EOF or error */ |
83 | 83 | ||
@@ -418,7 +418,7 @@ EODir: | |||
418 | return err; | 418 | return err; |
419 | } | 419 | } |
420 | 420 | ||
421 | EXPORT_SYMBOL(fat_search_long); | 421 | EXPORT_SYMBOL_GPL(fat_search_long); |
422 | 422 | ||
423 | struct fat_ioctl_filldir_callback { | 423 | struct fat_ioctl_filldir_callback { |
424 | struct dirent __user *dirent; | 424 | struct dirent __user *dirent; |
@@ -729,13 +729,13 @@ static int fat_dir_ioctl(struct inode * inode, struct file * filp, | |||
729 | 729 | ||
730 | buf.dirent = d1; | 730 | buf.dirent = d1; |
731 | buf.result = 0; | 731 | buf.result = 0; |
732 | down(&inode->i_sem); | 732 | mutex_lock(&inode->i_mutex); |
733 | ret = -ENOENT; | 733 | ret = -ENOENT; |
734 | if (!IS_DEADDIR(inode)) { | 734 | if (!IS_DEADDIR(inode)) { |
735 | ret = __fat_readdir(inode, filp, &buf, fat_ioctl_filldir, | 735 | ret = __fat_readdir(inode, filp, &buf, fat_ioctl_filldir, |
736 | short_only, both); | 736 | short_only, both); |
737 | } | 737 | } |
738 | up(&inode->i_sem); | 738 | mutex_unlock(&inode->i_mutex); |
739 | if (ret >= 0) | 739 | if (ret >= 0) |
740 | ret = buf.result; | 740 | ret = buf.result; |
741 | return ret; | 741 | return ret; |
@@ -780,7 +780,7 @@ int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, | |||
780 | return -ENOENT; | 780 | return -ENOENT; |
781 | } | 781 | } |
782 | 782 | ||
783 | EXPORT_SYMBOL(fat_get_dotdot_entry); | 783 | EXPORT_SYMBOL_GPL(fat_get_dotdot_entry); |
784 | 784 | ||
785 | /* See if directory is empty */ | 785 | /* See if directory is empty */ |
786 | int fat_dir_empty(struct inode *dir) | 786 | int fat_dir_empty(struct inode *dir) |
@@ -803,7 +803,7 @@ int fat_dir_empty(struct inode *dir) | |||
803 | return result; | 803 | return result; |
804 | } | 804 | } |
805 | 805 | ||
806 | EXPORT_SYMBOL(fat_dir_empty); | 806 | EXPORT_SYMBOL_GPL(fat_dir_empty); |
807 | 807 | ||
808 | /* | 808 | /* |
809 | * fat_subdirs counts the number of sub-directories of dir. It can be run | 809 | * fat_subdirs counts the number of sub-directories of dir. It can be run |
@@ -849,7 +849,7 @@ int fat_scan(struct inode *dir, const unsigned char *name, | |||
849 | return -ENOENT; | 849 | return -ENOENT; |
850 | } | 850 | } |
851 | 851 | ||
852 | EXPORT_SYMBOL(fat_scan); | 852 | EXPORT_SYMBOL_GPL(fat_scan); |
853 | 853 | ||
854 | static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) | 854 | static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) |
855 | { | 855 | { |
@@ -936,7 +936,7 @@ int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo) | |||
936 | return 0; | 936 | return 0; |
937 | } | 937 | } |
938 | 938 | ||
939 | EXPORT_SYMBOL(fat_remove_entries); | 939 | EXPORT_SYMBOL_GPL(fat_remove_entries); |
940 | 940 | ||
941 | static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, | 941 | static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, |
942 | struct buffer_head **bhs, int nr_bhs) | 942 | struct buffer_head **bhs, int nr_bhs) |
@@ -1048,7 +1048,7 @@ error: | |||
1048 | return err; | 1048 | return err; |
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | EXPORT_SYMBOL(fat_alloc_new_dir); | 1051 | EXPORT_SYMBOL_GPL(fat_alloc_new_dir); |
1052 | 1052 | ||
1053 | static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, | 1053 | static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, |
1054 | int *nr_cluster, struct msdos_dir_entry **de, | 1054 | int *nr_cluster, struct msdos_dir_entry **de, |
@@ -1264,4 +1264,4 @@ error_remove: | |||
1264 | return err; | 1264 | return err; |
1265 | } | 1265 | } |
1266 | 1266 | ||
1267 | EXPORT_SYMBOL(fat_add_entries); | 1267 | EXPORT_SYMBOL_GPL(fat_add_entries); |
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 4164cd54c4..a1a9e04512 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c | |||
@@ -476,6 +476,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) | |||
476 | sbi->prev_free = entry; | 476 | sbi->prev_free = entry; |
477 | if (sbi->free_clusters != -1) | 477 | if (sbi->free_clusters != -1) |
478 | sbi->free_clusters--; | 478 | sbi->free_clusters--; |
479 | sb->s_dirt = 1; | ||
479 | 480 | ||
480 | cluster[idx_clus] = entry; | 481 | cluster[idx_clus] = entry; |
481 | idx_clus++; | 482 | idx_clus++; |
@@ -496,6 +497,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) | |||
496 | 497 | ||
497 | /* Couldn't allocate the free entries */ | 498 | /* Couldn't allocate the free entries */ |
498 | sbi->free_clusters = 0; | 499 | sbi->free_clusters = 0; |
500 | sb->s_dirt = 1; | ||
499 | err = -ENOSPC; | 501 | err = -ENOSPC; |
500 | 502 | ||
501 | out: | 503 | out: |
@@ -509,7 +511,6 @@ out: | |||
509 | } | 511 | } |
510 | for (i = 0; i < nr_bhs; i++) | 512 | for (i = 0; i < nr_bhs; i++) |
511 | brelse(bhs[i]); | 513 | brelse(bhs[i]); |
512 | fat_clusters_flush(sb); | ||
513 | 514 | ||
514 | if (err && idx_clus) | 515 | if (err && idx_clus) |
515 | fat_free_clusters(inode, cluster[0]); | 516 | fat_free_clusters(inode, cluster[0]); |
@@ -542,8 +543,10 @@ int fat_free_clusters(struct inode *inode, int cluster) | |||
542 | } | 543 | } |
543 | 544 | ||
544 | ops->ent_put(&fatent, FAT_ENT_FREE); | 545 | ops->ent_put(&fatent, FAT_ENT_FREE); |
545 | if (sbi->free_clusters != -1) | 546 | if (sbi->free_clusters != -1) { |
546 | sbi->free_clusters++; | 547 | sbi->free_clusters++; |
548 | sb->s_dirt = 1; | ||
549 | } | ||
547 | 550 | ||
548 | if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) { | 551 | if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) { |
549 | if (sb->s_flags & MS_SYNCHRONOUS) { | 552 | if (sb->s_flags & MS_SYNCHRONOUS) { |
@@ -578,7 +581,7 @@ error: | |||
578 | return err; | 581 | return err; |
579 | } | 582 | } |
580 | 583 | ||
581 | EXPORT_SYMBOL(fat_free_clusters); | 584 | EXPORT_SYMBOL_GPL(fat_free_clusters); |
582 | 585 | ||
583 | int fat_count_free_clusters(struct super_block *sb) | 586 | int fat_count_free_clusters(struct super_block *sb) |
584 | { | 587 | { |
@@ -605,6 +608,7 @@ int fat_count_free_clusters(struct super_block *sb) | |||
605 | } while (fat_ent_next(sbi, &fatent)); | 608 | } while (fat_ent_next(sbi, &fatent)); |
606 | } | 609 | } |
607 | sbi->free_clusters = free; | 610 | sbi->free_clusters = free; |
611 | sb->s_dirt = 1; | ||
608 | fatent_brelse(&fatent); | 612 | fatent_brelse(&fatent); |
609 | out: | 613 | out: |
610 | unlock_fat(sbi); | 614 | unlock_fat(sbi); |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 7134403d5b..e99c5a73b3 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -6,11 +6,13 @@ | |||
6 | * regular file handling primitives for fat-based filesystems | 6 | * regular file handling primitives for fat-based filesystems |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/capability.h> | ||
9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
10 | #include <linux/time.h> | 11 | #include <linux/time.h> |
11 | #include <linux/msdos_fs.h> | 12 | #include <linux/msdos_fs.h> |
12 | #include <linux/smp_lock.h> | 13 | #include <linux/smp_lock.h> |
13 | #include <linux/buffer_head.h> | 14 | #include <linux/buffer_head.h> |
15 | #include <linux/writeback.h> | ||
14 | 16 | ||
15 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | 17 | int fat_generic_ioctl(struct inode *inode, struct file *filp, |
16 | unsigned int cmd, unsigned long arg) | 18 | unsigned int cmd, unsigned long arg) |
@@ -40,7 +42,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
40 | if (err) | 42 | if (err) |
41 | return err; | 43 | return err; |
42 | 44 | ||
43 | down(&inode->i_sem); | 45 | mutex_lock(&inode->i_mutex); |
44 | 46 | ||
45 | if (IS_RDONLY(inode)) { | 47 | if (IS_RDONLY(inode)) { |
46 | err = -EROFS; | 48 | err = -EROFS; |
@@ -102,7 +104,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
102 | MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED; | 104 | MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED; |
103 | mark_inode_dirty(inode); | 105 | mark_inode_dirty(inode); |
104 | up: | 106 | up: |
105 | up(&inode->i_sem); | 107 | mutex_unlock(&inode->i_mutex); |
106 | return err; | 108 | return err; |
107 | } | 109 | } |
108 | default: | 110 | default: |
@@ -124,6 +126,24 @@ struct file_operations fat_file_operations = { | |||
124 | .sendfile = generic_file_sendfile, | 126 | .sendfile = generic_file_sendfile, |
125 | }; | 127 | }; |
126 | 128 | ||
129 | static int fat_cont_expand(struct inode *inode, loff_t size) | ||
130 | { | ||
131 | struct address_space *mapping = inode->i_mapping; | ||
132 | loff_t start = inode->i_size, count = size - inode->i_size; | ||
133 | int err; | ||
134 | |||
135 | err = generic_cont_expand_simple(inode, size); | ||
136 | if (err) | ||
137 | goto out; | ||
138 | |||
139 | inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; | ||
140 | mark_inode_dirty(inode); | ||
141 | if (IS_SYNC(inode)) | ||
142 | err = sync_page_range_nolock(inode, mapping, start, count); | ||
143 | out: | ||
144 | return err; | ||
145 | } | ||
146 | |||
127 | int fat_notify_change(struct dentry *dentry, struct iattr *attr) | 147 | int fat_notify_change(struct dentry *dentry, struct iattr *attr) |
128 | { | 148 | { |
129 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | 149 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); |
@@ -132,11 +152,17 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr) | |||
132 | 152 | ||
133 | lock_kernel(); | 153 | lock_kernel(); |
134 | 154 | ||
135 | /* FAT cannot truncate to a longer file */ | 155 | /* |
156 | * Expand the file. Since inode_setattr() updates ->i_size | ||
157 | * before calling the ->truncate(), but FAT needs to fill the | ||
158 | * hole before it. | ||
159 | */ | ||
136 | if (attr->ia_valid & ATTR_SIZE) { | 160 | if (attr->ia_valid & ATTR_SIZE) { |
137 | if (attr->ia_size > inode->i_size) { | 161 | if (attr->ia_size > inode->i_size) { |
138 | error = -EPERM; | 162 | error = fat_cont_expand(inode, attr->ia_size); |
139 | goto out; | 163 | if (error || attr->ia_valid == ATTR_SIZE) |
164 | goto out; | ||
165 | attr->ia_valid &= ~ATTR_SIZE; | ||
140 | } | 166 | } |
141 | } | 167 | } |
142 | 168 | ||
@@ -173,7 +199,7 @@ out: | |||
173 | return error; | 199 | return error; |
174 | } | 200 | } |
175 | 201 | ||
176 | EXPORT_SYMBOL(fat_notify_change); | 202 | EXPORT_SYMBOL_GPL(fat_notify_change); |
177 | 203 | ||
178 | /* Free all clusters after the skip'th cluster. */ | 204 | /* Free all clusters after the skip'th cluster. */ |
179 | static int fat_free(struct inode *inode, int skip) | 205 | static int fat_free(struct inode *inode, int skip) |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index a0f9b9fe13..e7f4aa7fc6 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); |
diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 2a0df2122f..32fb0a3f1d 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c | |||
@@ -33,7 +33,7 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...) | |||
33 | } | 33 | } |
34 | } | 34 | } |
35 | 35 | ||
36 | EXPORT_SYMBOL(fat_fs_panic); | 36 | EXPORT_SYMBOL_GPL(fat_fs_panic); |
37 | 37 | ||
38 | /* Flushes the number of free clusters on FAT32 */ | 38 | /* Flushes the number of free clusters on FAT32 */ |
39 | /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ | 39 | /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ |
@@ -67,8 +67,6 @@ void fat_clusters_flush(struct super_block *sb) | |||
67 | if (sbi->prev_free != -1) | 67 | if (sbi->prev_free != -1) |
68 | fsinfo->next_cluster = cpu_to_le32(sbi->prev_free); | 68 | fsinfo->next_cluster = cpu_to_le32(sbi->prev_free); |
69 | mark_buffer_dirty(bh); | 69 | mark_buffer_dirty(bh); |
70 | if (sb->s_flags & MS_SYNCHRONOUS) | ||
71 | sync_dirty_buffer(bh); | ||
72 | } | 70 | } |
73 | brelse(bh); | 71 | brelse(bh); |
74 | } | 72 | } |
@@ -194,7 +192,7 @@ void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date) | |||
194 | *date = cpu_to_le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9)); | 192 | *date = cpu_to_le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9)); |
195 | } | 193 | } |
196 | 194 | ||
197 | EXPORT_SYMBOL(fat_date_unix2dos); | 195 | EXPORT_SYMBOL_GPL(fat_date_unix2dos); |
198 | 196 | ||
199 | int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) | 197 | int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) |
200 | { | 198 | { |
@@ -222,4 +220,4 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) | |||
222 | return err; | 220 | return err; |
223 | } | 221 | } |
224 | 222 | ||
225 | EXPORT_SYMBOL(fat_sync_bhs); | 223 | EXPORT_SYMBOL_GPL(fat_sync_bhs); |