aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
authorOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>2006-01-08 04:02:13 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:13:47 -0500
commit05eb0b51fb46430050d5873458612f53e0234f2e (patch)
tree88b9398079f53f29dff7533fb27487ae725983b1 /fs/fat
parent268fc16e343b4f8e249468747db2e658da46a814 (diff)
[PATCH] fat: support a truncate() for expanding size (generic_cont_expand)
This patch changes generic_cont_expand(), in order to share the code with fatfs. - Use vmtruncate() if ->prepare_write() returns a error. Even if ->prepare_write() returns an error, it may already have added some blocks. So, this truncates blocks outside of ->i_size by vmtruncate(). - Add generic_cont_expand_simple(). The generic_cont_expand_simple() assumes that ->prepare_write() can handle the block boundary. With this, we don't need to care the extra byte. And for expanding a file size by truncate(), fatfs uses the added generic_cont_expand_simple(). Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/fat')
-rw-r--r--fs/fat/file.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 15229fe569c3..9b07c328a6fc 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -11,6 +11,7 @@
11#include <linux/msdos_fs.h> 11#include <linux/msdos_fs.h>
12#include <linux/smp_lock.h> 12#include <linux/smp_lock.h>
13#include <linux/buffer_head.h> 13#include <linux/buffer_head.h>
14#include <linux/writeback.h>
14 15
15int fat_generic_ioctl(struct inode *inode, struct file *filp, 16int fat_generic_ioctl(struct inode *inode, struct file *filp,
16 unsigned int cmd, unsigned long arg) 17 unsigned int cmd, unsigned long arg)
@@ -124,6 +125,24 @@ struct file_operations fat_file_operations = {
124 .sendfile = generic_file_sendfile, 125 .sendfile = generic_file_sendfile,
125}; 126};
126 127
128static int fat_cont_expand(struct inode *inode, loff_t size)
129{
130 struct address_space *mapping = inode->i_mapping;
131 loff_t start = inode->i_size, count = size - inode->i_size;
132 int err;
133
134 err = generic_cont_expand_simple(inode, size);
135 if (err)
136 goto out;
137
138 inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
139 mark_inode_dirty(inode);
140 if (IS_SYNC(inode))
141 err = sync_page_range_nolock(inode, mapping, start, count);
142out:
143 return err;
144}
145
127int fat_notify_change(struct dentry *dentry, struct iattr *attr) 146int fat_notify_change(struct dentry *dentry, struct iattr *attr)
128{ 147{
129 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); 148 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -132,11 +151,17 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
132 151
133 lock_kernel(); 152 lock_kernel();
134 153
135 /* FAT cannot truncate to a longer file */ 154 /*
155 * Expand the file. Since inode_setattr() updates ->i_size
156 * before calling the ->truncate(), but FAT needs to fill the
157 * hole before it.
158 */
136 if (attr->ia_valid & ATTR_SIZE) { 159 if (attr->ia_valid & ATTR_SIZE) {
137 if (attr->ia_size > inode->i_size) { 160 if (attr->ia_size > inode->i_size) {
138 error = -EPERM; 161 error = fat_cont_expand(inode, attr->ia_size);
139 goto out; 162 if (error || attr->ia_valid == ATTR_SIZE)
163 goto out;
164 attr->ia_valid &= ~ATTR_SIZE;
140 } 165 }
141 } 166 }
142 167