* [patch 5/5] ext2: convert to use the new truncate convention.
[not found] <20090710073028.782561541@suse.de>
@ 2009-07-10 7:30 ` npiggin
2009-09-01 18:29 ` Jan Kara
0 siblings, 1 reply; 9+ messages in thread
From: npiggin @ 2009-07-10 7:30 UTC (permalink / raw)
To: linux-fsdevel; +Cc: hch, viro, jack, linux-ext4
[-- Attachment #1: ext2-new-truncate.patch --]
[-- Type: text/plain, Size: 8218 bytes --]
I have some questions, marked with XXX.
Cc: linux-ext4@vger.kernel.org
Signed-off-by: Nick Piggin <npiggin@suse.de>
---
fs/ext2/ext2.h | 1
fs/ext2/file.c | 2
fs/ext2/inode.c | 138 +++++++++++++++++++++++++++++++++++++++++++++-----------
3 files changed, 113 insertions(+), 28 deletions(-)
Index: linux-2.6/fs/ext2/inode.c
===================================================================
--- linux-2.6.orig/fs/ext2/inode.c
+++ linux-2.6/fs/ext2/inode.c
@@ -53,6 +53,8 @@ static inline int ext2_inode_is_fast_sym
inode->i_blocks - ea_blocks == 0);
}
+static void ext2_truncate_blocks(struct inode *inode, loff_t offset);
+
/*
* Called at the last iput() if i_nlink is zero.
*/
@@ -66,9 +68,10 @@ void ext2_delete_inode (struct inode * i
mark_inode_dirty(inode);
ext2_write_inode(inode, inode_needs_sync(inode));
+ /* XXX: where is truncate_inode_pages? */
inode->i_size = 0;
if (inode->i_blocks)
- ext2_truncate (inode);
+ ext2_truncate_blocks(inode, 0);
ext2_free_inode (inode);
return;
@@ -761,8 +764,33 @@ ext2_write_begin(struct file *file, stru
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
*pagep = NULL;
- return __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata);
+ ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata);
+ if (ret < 0) {
+ struct inode *inode = mapping->host;
+ loff_t isize = inode->i_size;
+ if (pos + len > isize)
+ ext2_truncate_blocks(inode, isize);
+ }
+ return ret;
+}
+
+static int ext2_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
+{
+ int ret;
+
+ ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+ if (ret < len) {
+ struct inode *inode = mapping->host;
+ loff_t isize = inode->i_size;
+ if (pos + len > isize)
+ ext2_truncate_blocks(inode, isize);
+ }
+ return ret;
}
static int
@@ -770,13 +798,22 @@ ext2_nobh_write_begin(struct file *file,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
/*
* Dir-in-pagecache still uses ext2_write_begin. Would have to rework
* directory handling code to pass around offsets rather than struct
* pages in order to make this work easily.
*/
- return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ ret = nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ext2_get_block);
+ if (ret < 0) {
+ struct inode *inode = mapping->host;
+ loff_t isize = inode->i_size;
+ if (pos + len > isize)
+ ext2_truncate_blocks(inode, isize);
+ }
+ return ret;
}
static int ext2_nobh_writepage(struct page *page,
@@ -796,9 +833,15 @@ ext2_direct_IO(int rw, struct kiocb *ioc
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
+ ssize_t ret;
- return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, ext2_get_block, NULL);
+ if (ret < 0 && (rw & WRITE)) {
+ loff_t isize = inode->i_size;
+ ext2_truncate_blocks(inode, isize);
+ }
+ return ret;
}
static int
@@ -813,7 +856,7 @@ const struct address_space_operations ex
.writepage = ext2_writepage,
.sync_page = block_sync_page,
.write_begin = ext2_write_begin,
- .write_end = generic_write_end,
+ .write_end = ext2_write_end,
.bmap = ext2_bmap,
.direct_IO = ext2_direct_IO,
.writepages = ext2_writepages,
@@ -1020,7 +1063,7 @@ static void ext2_free_branches(struct in
ext2_free_data(inode, p, q);
}
-void ext2_truncate(struct inode *inode)
+static void __ext2_truncate_blocks(struct inode *inode, loff_t offset)
{
__le32 *i_data = EXT2_I(inode)->i_data;
struct ext2_inode_info *ei = EXT2_I(inode);
@@ -1032,27 +1075,8 @@ void ext2_truncate(struct inode *inode)
int n;
long iblock;
unsigned blocksize;
-
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return;
- if (ext2_inode_is_fast_symlink(inode))
- return;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return;
-
blocksize = inode->i_sb->s_blocksize;
- iblock = (inode->i_size + blocksize-1)
- >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
-
- if (mapping_is_xip(inode->i_mapping))
- xip_truncate_page(inode->i_mapping, inode->i_size);
- else if (test_opt(inode->i_sb, NOBH))
- nobh_truncate_page(inode->i_mapping,
- inode->i_size, ext2_get_block);
- else
- block_truncate_page(inode->i_mapping,
- inode->i_size, ext2_get_block);
+ iblock = (offset + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
n = ext2_block_to_path(inode, iblock, offsets, NULL);
if (n == 0)
@@ -1120,6 +1144,59 @@ do_indirects:
ext2_discard_reservation(inode);
mutex_unlock(&ei->truncate_mutex);
+}
+
+static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
+{
+ /*
+ * XXX: it seems like a bug here that we don't allow
+ * IS_APPEND inode to have blocks-past-i_size trimmed off.
+ * review and fix this.
+ */
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return -EINVAL;
+ if (ext2_inode_is_fast_symlink(inode))
+ return -EINVAL;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return -EPERM;
+ __ext2_truncate_blocks(inode, offset);
+}
+
+int ext2_setsize(struct inode *inode, loff_t newsize)
+{
+ loff_t oldsize;
+ int error;
+
+ error = inode_newsize_ok(inode, newsize);
+ if (error)
+ return error;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return -EINVAL;
+ if (ext2_inode_is_fast_symlink(inode))
+ return -EINVAL;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return -EPERM;
+
+ if (mapping_is_xip(inode->i_mapping))
+ error = xip_truncate_page(inode->i_mapping, newsize);
+ else if (test_opt(inode->i_sb, NOBH))
+ error = nobh_truncate_page(inode->i_mapping,
+ newsize, ext2_get_block);
+ else
+ error = block_truncate_page(inode->i_mapping,
+ newsize, ext2_get_block);
+ if (error)
+ return error;
+
+ oldsize = inode->i_size;
+ i_size_write(inode, newsize);
+ truncate_pagecache(inode, oldsize, newsize);
+
+ __ext2_truncate_blocks(inode, newsize);
+
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
if (inode_needs_sync(inode)) {
sync_mapping_buffers(inode->i_mapping);
@@ -1127,6 +1204,8 @@ do_indirects:
} else {
mark_inode_dirty(inode);
}
+
+ return 0;
}
static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino,
@@ -1459,6 +1538,13 @@ int ext2_setattr(struct dentry *dentry,
if (error)
return error;
}
+ if (iattr->ia_valid & ATTR_SIZE) {
+ error = ext2_setsize(inode, iattr->ia_size);
+ if (error)
+ return error;
+ iattr->ia_valid &= ~ATTR_SIZE;
+ /* strip ATTR_SIZE for inode_setattr */
+ }
error = inode_setattr(inode, iattr);
if (!error && (iattr->ia_valid & ATTR_MODE))
error = ext2_acl_chmod(inode);
Index: linux-2.6/fs/ext2/ext2.h
===================================================================
--- linux-2.6.orig/fs/ext2/ext2.h
+++ linux-2.6/fs/ext2/ext2.h
@@ -122,7 +122,6 @@ extern int ext2_write_inode (struct inod
extern void ext2_delete_inode (struct inode *);
extern int ext2_sync_inode (struct inode *);
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
-extern void ext2_truncate (struct inode *);
extern int ext2_setattr (struct dentry *, struct iattr *);
extern void ext2_set_inode_flags(struct inode *inode);
extern void ext2_get_inode_flags(struct ext2_inode_info *);
Index: linux-2.6/fs/ext2/file.c
===================================================================
--- linux-2.6.orig/fs/ext2/file.c
+++ linux-2.6/fs/ext2/file.c
@@ -77,13 +77,13 @@ const struct file_operations ext2_xip_fi
#endif
const struct inode_operations ext2_file_inode_operations = {
- .truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
.removexattr = generic_removexattr,
#endif
+ .new_truncate = 1,
.setattr = ext2_setattr,
.permission = ext2_permission,
.fiemap = ext2_fiemap,
^ permalink raw reply [flat|nested] 9+ messages in thread
* [patch 5/5] ext2: convert to use the new truncate convention.
[not found] <20090816102533.329473921@suse.de>
@ 2009-08-16 10:25 ` npiggin
2009-08-16 20:16 ` Christoph Hellwig
0 siblings, 1 reply; 9+ messages in thread
From: npiggin @ 2009-08-16 10:25 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-fsdevel, linux-ext4, Christoph Hellwig
[-- Attachment #1: ext2-new-truncate.patch --]
[-- Type: text/plain, Size: 8258 bytes --]
I also have some questions, marked with XXX.
Cc: linux-ext4@vger.kernel.org
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nick Piggin <npiggin@suse.de>
---
fs/ext2/ext2.h | 1
fs/ext2/file.c | 2
fs/ext2/inode.c | 138 +++++++++++++++++++++++++++++++++++++++++++++-----------
3 files changed, 113 insertions(+), 28 deletions(-)
Index: linux-2.6/fs/ext2/inode.c
===================================================================
--- linux-2.6.orig/fs/ext2/inode.c
+++ linux-2.6/fs/ext2/inode.c
@@ -53,6 +53,8 @@ static inline int ext2_inode_is_fast_sym
inode->i_blocks - ea_blocks == 0);
}
+static void ext2_truncate_blocks(struct inode *inode, loff_t offset);
+
/*
* Called at the last iput() if i_nlink is zero.
*/
@@ -66,9 +68,10 @@ void ext2_delete_inode (struct inode * i
mark_inode_dirty(inode);
ext2_write_inode(inode, inode_needs_sync(inode));
+ /* XXX: where is truncate_inode_pages? */
inode->i_size = 0;
if (inode->i_blocks)
- ext2_truncate (inode);
+ ext2_truncate_blocks(inode, 0);
ext2_free_inode (inode);
return;
@@ -761,8 +764,33 @@ ext2_write_begin(struct file *file, stru
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
*pagep = NULL;
- return __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata);
+ ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata);
+ if (ret < 0) {
+ struct inode *inode = mapping->host;
+ loff_t isize = inode->i_size;
+ if (pos + len > isize)
+ ext2_truncate_blocks(inode, isize);
+ }
+ return ret;
+}
+
+static int ext2_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
+{
+ int ret;
+
+ ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+ if (ret < len) {
+ struct inode *inode = mapping->host;
+ loff_t isize = inode->i_size;
+ if (pos + len > isize)
+ ext2_truncate_blocks(inode, isize);
+ }
+ return ret;
}
static int
@@ -770,13 +798,22 @@ ext2_nobh_write_begin(struct file *file,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
/*
* Dir-in-pagecache still uses ext2_write_begin. Would have to rework
* directory handling code to pass around offsets rather than struct
* pages in order to make this work easily.
*/
- return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ ret = nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
ext2_get_block);
+ if (ret < 0) {
+ struct inode *inode = mapping->host;
+ loff_t isize = inode->i_size;
+ if (pos + len > isize)
+ ext2_truncate_blocks(inode, isize);
+ }
+ return ret;
}
static int ext2_nobh_writepage(struct page *page,
@@ -796,9 +833,15 @@ ext2_direct_IO(int rw, struct kiocb *ioc
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
+ ssize_t ret;
- return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, ext2_get_block, NULL);
+ if (ret < 0 && (rw & WRITE)) {
+ loff_t isize = inode->i_size;
+ ext2_truncate_blocks(inode, isize);
+ }
+ return ret;
}
static int
@@ -813,7 +856,7 @@ const struct address_space_operations ex
.writepage = ext2_writepage,
.sync_page = block_sync_page,
.write_begin = ext2_write_begin,
- .write_end = generic_write_end,
+ .write_end = ext2_write_end,
.bmap = ext2_bmap,
.direct_IO = ext2_direct_IO,
.writepages = ext2_writepages,
@@ -1020,7 +1063,7 @@ static void ext2_free_branches(struct in
ext2_free_data(inode, p, q);
}
-void ext2_truncate(struct inode *inode)
+static void __ext2_truncate_blocks(struct inode *inode, loff_t offset)
{
__le32 *i_data = EXT2_I(inode)->i_data;
struct ext2_inode_info *ei = EXT2_I(inode);
@@ -1032,27 +1075,8 @@ void ext2_truncate(struct inode *inode)
int n;
long iblock;
unsigned blocksize;
-
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return;
- if (ext2_inode_is_fast_symlink(inode))
- return;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return;
-
blocksize = inode->i_sb->s_blocksize;
- iblock = (inode->i_size + blocksize-1)
- >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
-
- if (mapping_is_xip(inode->i_mapping))
- xip_truncate_page(inode->i_mapping, inode->i_size);
- else if (test_opt(inode->i_sb, NOBH))
- nobh_truncate_page(inode->i_mapping,
- inode->i_size, ext2_get_block);
- else
- block_truncate_page(inode->i_mapping,
- inode->i_size, ext2_get_block);
+ iblock = (offset + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
n = ext2_block_to_path(inode, iblock, offsets, NULL);
if (n == 0)
@@ -1120,6 +1144,59 @@ do_indirects:
ext2_discard_reservation(inode);
mutex_unlock(&ei->truncate_mutex);
+}
+
+static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
+{
+ /*
+ * XXX: it seems like a bug here that we don't allow
+ * IS_APPEND inode to have blocks-past-i_size trimmed off.
+ * review and fix this.
+ */
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return -EINVAL;
+ if (ext2_inode_is_fast_symlink(inode))
+ return -EINVAL;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return -EPERM;
+ __ext2_truncate_blocks(inode, offset);
+}
+
+int ext2_setsize(struct inode *inode, loff_t newsize)
+{
+ loff_t oldsize;
+ int error;
+
+ error = inode_newsize_ok(inode, newsize);
+ if (error)
+ return error;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return -EINVAL;
+ if (ext2_inode_is_fast_symlink(inode))
+ return -EINVAL;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return -EPERM;
+
+ if (mapping_is_xip(inode->i_mapping))
+ error = xip_truncate_page(inode->i_mapping, newsize);
+ else if (test_opt(inode->i_sb, NOBH))
+ error = nobh_truncate_page(inode->i_mapping,
+ newsize, ext2_get_block);
+ else
+ error = block_truncate_page(inode->i_mapping,
+ newsize, ext2_get_block);
+ if (error)
+ return error;
+
+ oldsize = inode->i_size;
+ i_size_write(inode, newsize);
+ truncate_pagecache(inode, oldsize, newsize);
+
+ __ext2_truncate_blocks(inode, newsize);
+
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
if (inode_needs_sync(inode)) {
sync_mapping_buffers(inode->i_mapping);
@@ -1127,6 +1204,8 @@ do_indirects:
} else {
mark_inode_dirty(inode);
}
+
+ return 0;
}
static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino,
@@ -1459,6 +1538,13 @@ int ext2_setattr(struct dentry *dentry,
if (error)
return error;
}
+ if (iattr->ia_valid & ATTR_SIZE) {
+ error = ext2_setsize(inode, iattr->ia_size);
+ if (error)
+ return error;
+ iattr->ia_valid &= ~ATTR_SIZE;
+ /* strip ATTR_SIZE for inode_setattr */
+ }
error = inode_setattr(inode, iattr);
if (!error && (iattr->ia_valid & ATTR_MODE))
error = ext2_acl_chmod(inode);
Index: linux-2.6/fs/ext2/ext2.h
===================================================================
--- linux-2.6.orig/fs/ext2/ext2.h
+++ linux-2.6/fs/ext2/ext2.h
@@ -122,7 +122,6 @@ extern int ext2_write_inode (struct inod
extern void ext2_delete_inode (struct inode *);
extern int ext2_sync_inode (struct inode *);
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
-extern void ext2_truncate (struct inode *);
extern int ext2_setattr (struct dentry *, struct iattr *);
extern void ext2_set_inode_flags(struct inode *inode);
extern void ext2_get_inode_flags(struct ext2_inode_info *);
Index: linux-2.6/fs/ext2/file.c
===================================================================
--- linux-2.6.orig/fs/ext2/file.c
+++ linux-2.6/fs/ext2/file.c
@@ -77,13 +77,13 @@ const struct file_operations ext2_xip_fi
#endif
const struct inode_operations ext2_file_inode_operations = {
- .truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
.removexattr = generic_removexattr,
#endif
+ .new_truncate = 1,
.setattr = ext2_setattr,
.permission = ext2_permission,
.fiemap = ext2_fiemap,
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch 5/5] ext2: convert to use the new truncate convention.
2009-08-16 10:25 ` npiggin
@ 2009-08-16 20:16 ` Christoph Hellwig
2009-08-17 6:42 ` Nick Piggin
0 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2009-08-16 20:16 UTC (permalink / raw)
To: npiggin; +Cc: Andrew Morton, linux-fsdevel, linux-ext4, Christoph Hellwig
On Sun, Aug 16, 2009 at 08:25:38PM +1000, npiggin@suse.de wrote:
> @@ -66,9 +68,10 @@ void ext2_delete_inode (struct inode * i
> mark_inode_dirty(inode);
> ext2_write_inode(inode, inode_needs_sync(inode));
>
> + /* XXX: where is truncate_inode_pages? */
> inode->i_size = 0;
> if (inode->i_blocks)
> - ext2_truncate (inode);
> + ext2_truncate_blocks(inode, 0);
> ext2_free_inode (inode);
At the beginning of the function, just before the diff window. Because
this is ->delete_inode we truncate away all pages, down to offset 0.
> +static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
> +{
> + /*
> + * XXX: it seems like a bug here that we don't allow
> + * IS_APPEND inode to have blocks-past-i_size trimmed off.
> + * review and fix this.
> + */
> + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
> + S_ISLNK(inode->i_mode)))
> + return -EINVAL;
> + if (ext2_inode_is_fast_symlink(inode))
> + return -EINVAL;
> + if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
> + return -EPERM;
> + __ext2_truncate_blocks(inode, offset);
Yes, I think the IS_APPEND(inode) || IS_IMMUTABLE(inode) checks should move
into ext2_setsize. But let's leave that for a separate patch.
Btw, the above code gives me warnings like this:
/home/hch/work/linux-2.6/fs/ext2/inode.c: In function
'ext2_truncate_blocks':
/home/hch/work/linux-2.6/fs/ext2/inode.c:1158: warning: 'return' with a
value, in function returning void
/home/hch/work/linux-2.6/fs/ext2/inode.c:1160: warning: 'return' with a
value, in function returning void
/home/hch/work/linux-2.6/fs/ext2/inode.c:1162: warning: 'return' with a
value, in function returning void
because you try to return errors from a function delcared as void.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch 5/5] ext2: convert to use the new truncate convention.
2009-08-16 20:16 ` Christoph Hellwig
@ 2009-08-17 6:42 ` Nick Piggin
2009-08-17 11:09 ` Boaz Harrosh
0 siblings, 1 reply; 9+ messages in thread
From: Nick Piggin @ 2009-08-17 6:42 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Andrew Morton, linux-fsdevel, linux-ext4, Christoph Hellwig
On Sun, Aug 16, 2009 at 04:16:26PM -0400, Christoph Hellwig wrote:
> On Sun, Aug 16, 2009 at 08:25:38PM +1000, npiggin@suse.de wrote:
> > @@ -66,9 +68,10 @@ void ext2_delete_inode (struct inode * i
> > mark_inode_dirty(inode);
> > ext2_write_inode(inode, inode_needs_sync(inode));
> >
> > + /* XXX: where is truncate_inode_pages? */
> > inode->i_size = 0;
> > if (inode->i_blocks)
> > - ext2_truncate (inode);
> > + ext2_truncate_blocks(inode, 0);
> > ext2_free_inode (inode);
>
> At the beginning of the function, just before the diff window. Because
> this is ->delete_inode we truncate away all pages, down to offset 0.
OK, weird. I thought I couldn't see it when I wrote that :) maybe my
tree was corrupted or I'm stupid.
> > +static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
> > +{
> > + /*
> > + * XXX: it seems like a bug here that we don't allow
> > + * IS_APPEND inode to have blocks-past-i_size trimmed off.
> > + * review and fix this.
> > + */
> > + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
> > + S_ISLNK(inode->i_mode)))
> > + return -EINVAL;
> > + if (ext2_inode_is_fast_symlink(inode))
> > + return -EINVAL;
> > + if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
> > + return -EPERM;
> > + __ext2_truncate_blocks(inode, offset);
>
> Yes, I think the IS_APPEND(inode) || IS_IMMUTABLE(inode) checks should move
> into ext2_setsize. But let's leave that for a separate patch.
Yeah agreed.
> Btw, the above code gives me warnings like this:
>
> /home/hch/work/linux-2.6/fs/ext2/inode.c: In function
> 'ext2_truncate_blocks':
> /home/hch/work/linux-2.6/fs/ext2/inode.c:1158: warning: 'return' with a
> value, in function returning void
> /home/hch/work/linux-2.6/fs/ext2/inode.c:1160: warning: 'return' with a
> value, in function returning void
> /home/hch/work/linux-2.6/fs/ext2/inode.c:1162: warning: 'return' with a
> value, in function returning void
>
> because you try to return errors from a function delcared as void.
Hm, sorry. I thought it was in good shape... I'll recheck that I sent
out the correct versions and resend according to feedback from you
and Hugh.
Thanks,
Nick
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch 5/5] ext2: convert to use the new truncate convention.
2009-08-17 6:42 ` Nick Piggin
@ 2009-08-17 11:09 ` Boaz Harrosh
2009-08-17 16:44 ` Nick Piggin
0 siblings, 1 reply; 9+ messages in thread
From: Boaz Harrosh @ 2009-08-17 11:09 UTC (permalink / raw)
To: Nick Piggin
Cc: Christoph Hellwig, Andrew Morton, linux-fsdevel, linux-ext4,
Christoph Hellwig
On 08/17/2009 09:42 AM, Nick Piggin wrote:
> On Sun, Aug 16, 2009 at 04:16:26PM -0400, Christoph Hellwig wrote:
>> On Sun, Aug 16, 2009 at 08:25:38PM +1000, npiggin@suse.de wrote:
>>> @@ -66,9 +68,10 @@ void ext2_delete_inode (struct inode * i
>>> mark_inode_dirty(inode);
>>> ext2_write_inode(inode, inode_needs_sync(inode));
>>>
>>> + /* XXX: where is truncate_inode_pages? */
>>> inode->i_size = 0;
>>> if (inode->i_blocks)
>>> - ext2_truncate (inode);
>>> + ext2_truncate_blocks(inode, 0);
>>> ext2_free_inode (inode);
>>
>> At the beginning of the function, just before the diff window. Because
>> this is ->delete_inode we truncate away all pages, down to offset 0.
>
> OK, weird. I thought I couldn't see it when I wrote that :) maybe my
> tree was corrupted or I'm stupid.
>
>
>>> +static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
>>> +{
>>> + /*
>>> + * XXX: it seems like a bug here that we don't allow
>>> + * IS_APPEND inode to have blocks-past-i_size trimmed off.
>>> + * review and fix this.
>>> + */
>>> + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
>>> + S_ISLNK(inode->i_mode)))
>>> + return -EINVAL;
>>> + if (ext2_inode_is_fast_symlink(inode))
>>> + return -EINVAL;
>>> + if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
>>> + return -EPERM;
>>> + __ext2_truncate_blocks(inode, offset);
>>
>> Yes, I think the IS_APPEND(inode) || IS_IMMUTABLE(inode) checks should move
>> into ext2_setsize. But let's leave that for a separate patch.
>
> Yeah agreed.
>
>
>> Btw, the above code gives me warnings like this:
>>
>> /home/hch/work/linux-2.6/fs/ext2/inode.c: In function
>> 'ext2_truncate_blocks':
>> /home/hch/work/linux-2.6/fs/ext2/inode.c:1158: warning: 'return' with a
>> value, in function returning void
>> /home/hch/work/linux-2.6/fs/ext2/inode.c:1160: warning: 'return' with a
>> value, in function returning void
>> /home/hch/work/linux-2.6/fs/ext2/inode.c:1162: warning: 'return' with a
>> value, in function returning void
>>
>> because you try to return errors from a function delcared as void.
>
> Hm, sorry. I thought it was in good shape... I'll recheck that I sent
> out the correct versions and resend according to feedback from you
> and Hugh.
>
> Thanks,
> Nick
>
Nick do you have a public tree with these latest patches? I would like to
try out an exofs conversion and testing.
Thanks
Boaz
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch 5/5] ext2: convert to use the new truncate convention.
2009-08-17 11:09 ` Boaz Harrosh
@ 2009-08-17 16:44 ` Nick Piggin
0 siblings, 0 replies; 9+ messages in thread
From: Nick Piggin @ 2009-08-17 16:44 UTC (permalink / raw)
To: Boaz Harrosh
Cc: Christoph Hellwig, Andrew Morton, linux-fsdevel, linux-ext4,
Christoph Hellwig
On Mon, Aug 17, 2009 at 02:09:54PM +0300, Boaz Harrosh wrote:
> On 08/17/2009 09:42 AM, Nick Piggin wrote:
> > On Sun, Aug 16, 2009 at 04:16:26PM -0400, Christoph Hellwig wrote:
> >> On Sun, Aug 16, 2009 at 08:25:38PM +1000, npiggin@suse.de wrote:
> >>> @@ -66,9 +68,10 @@ void ext2_delete_inode (struct inode * i
> >>> mark_inode_dirty(inode);
> >>> ext2_write_inode(inode, inode_needs_sync(inode));
> >>>
> >>> + /* XXX: where is truncate_inode_pages? */
> >>> inode->i_size = 0;
> >>> if (inode->i_blocks)
> >>> - ext2_truncate (inode);
> >>> + ext2_truncate_blocks(inode, 0);
> >>> ext2_free_inode (inode);
> >>
> >> At the beginning of the function, just before the diff window. Because
> >> this is ->delete_inode we truncate away all pages, down to offset 0.
> >
> > OK, weird. I thought I couldn't see it when I wrote that :) maybe my
> > tree was corrupted or I'm stupid.
> >
> >
> >>> +static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
> >>> +{
> >>> + /*
> >>> + * XXX: it seems like a bug here that we don't allow
> >>> + * IS_APPEND inode to have blocks-past-i_size trimmed off.
> >>> + * review and fix this.
> >>> + */
> >>> + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
> >>> + S_ISLNK(inode->i_mode)))
> >>> + return -EINVAL;
> >>> + if (ext2_inode_is_fast_symlink(inode))
> >>> + return -EINVAL;
> >>> + if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
> >>> + return -EPERM;
> >>> + __ext2_truncate_blocks(inode, offset);
> >>
> >> Yes, I think the IS_APPEND(inode) || IS_IMMUTABLE(inode) checks should move
> >> into ext2_setsize. But let's leave that for a separate patch.
> >
> > Yeah agreed.
> >
> >
> >> Btw, the above code gives me warnings like this:
> >>
> >> /home/hch/work/linux-2.6/fs/ext2/inode.c: In function
> >> 'ext2_truncate_blocks':
> >> /home/hch/work/linux-2.6/fs/ext2/inode.c:1158: warning: 'return' with a
> >> value, in function returning void
> >> /home/hch/work/linux-2.6/fs/ext2/inode.c:1160: warning: 'return' with a
> >> value, in function returning void
> >> /home/hch/work/linux-2.6/fs/ext2/inode.c:1162: warning: 'return' with a
> >> value, in function returning void
> >>
> >> because you try to return errors from a function delcared as void.
> >
> > Hm, sorry. I thought it was in good shape... I'll recheck that I sent
> > out the correct versions and resend according to feedback from you
> > and Hugh.
> >
> > Thanks,
> > Nick
> >
>
> Nick do you have a public tree with these latest patches? I would like to
> try out an exofs conversion and testing.
Hi Boaz,
I don't have a public tree. I can send you a rollup if you ping me or
just take the patches from the list. I will send out a new set shortly
(with very minor differences -- a couple of new helper functions to
use).
That will be great if you can convert your fs. I will really appreciate
it.
Thanks,
Nick
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch 5/5] ext2: convert to use the new truncate convention.
2009-07-10 7:30 ` [patch 5/5] ext2: convert to use the new truncate convention npiggin
@ 2009-09-01 18:29 ` Jan Kara
2009-09-02 9:14 ` Nick Piggin
0 siblings, 1 reply; 9+ messages in thread
From: Jan Kara @ 2009-09-01 18:29 UTC (permalink / raw)
To: npiggin; +Cc: linux-fsdevel, hch, viro, jack, linux-ext4, Andrew Morton
Hi Nick,
On Fri 10-07-09 17:30:33, npiggin@suse.de wrote:
> I have some questions, marked with XXX.
>
> Cc: linux-ext4@vger.kernel.org
> Signed-off-by: Nick Piggin <npiggin@suse.de>
> ---
> fs/ext2/ext2.h | 1
> fs/ext2/file.c | 2
> fs/ext2/inode.c | 138 +++++++++++++++++++++++++++++++++++++++++++++-----------
> 3 files changed, 113 insertions(+), 28 deletions(-)
>
> Index: linux-2.6/fs/ext2/inode.c
> ===================================================================
> --- linux-2.6.orig/fs/ext2/inode.c
> +++ linux-2.6/fs/ext2/inode.c
...
> +static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
> +{
> + /*
> + * XXX: it seems like a bug here that we don't allow
> + * IS_APPEND inode to have blocks-past-i_size trimmed off.
> + * review and fix this.
> + */
> + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
> + S_ISLNK(inode->i_mode)))
> + return -EINVAL;
> + if (ext2_inode_is_fast_symlink(inode))
> + return -EINVAL;
> + if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
> + return -EPERM;
> + __ext2_truncate_blocks(inode, offset);
> +}
Actually, looking again into this, I think you've introduced a subtle bug
into the code. When a write fails for some reason, we did vmtruncate()
previously which called block_truncate_page() which zeroed a tail of the
last block. Now, ext2_truncate_blocks() does not do this and I think it
could be a problem because at least in direct IO case, we could have written
some data into that block on disk.
We really rely on the tail of the block being zeroed because otherwise
extending truncate will show those old data in the block. I plan to change
that in my mkwrite fixes but until then, we should preserve the old
assumptions.
So I think that ext2_truncate_blocks() should do all that tail page magic
as well (although it's not needed in all cases).
Honza
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch 5/5] ext2: convert to use the new truncate convention.
2009-09-01 18:29 ` Jan Kara
@ 2009-09-02 9:14 ` Nick Piggin
2009-09-02 11:14 ` Jan Kara
0 siblings, 1 reply; 9+ messages in thread
From: Nick Piggin @ 2009-09-02 9:14 UTC (permalink / raw)
To: Jan Kara; +Cc: linux-fsdevel, hch, viro, linux-ext4, Andrew Morton
On Tue, Sep 01, 2009 at 08:29:29PM +0200, Jan Kara wrote:
> Hi Nick,
>
> On Fri 10-07-09 17:30:33, npiggin@suse.de wrote:
> > I have some questions, marked with XXX.
> >
> > Cc: linux-ext4@vger.kernel.org
> > Signed-off-by: Nick Piggin <npiggin@suse.de>
> > ---
> > fs/ext2/ext2.h | 1
> > fs/ext2/file.c | 2
> > fs/ext2/inode.c | 138 +++++++++++++++++++++++++++++++++++++++++++++-----------
> > 3 files changed, 113 insertions(+), 28 deletions(-)
> >
> > Index: linux-2.6/fs/ext2/inode.c
> > ===================================================================
> > --- linux-2.6.orig/fs/ext2/inode.c
> > +++ linux-2.6/fs/ext2/inode.c
> ...
> > +static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
> > +{
> > + /*
> > + * XXX: it seems like a bug here that we don't allow
> > + * IS_APPEND inode to have blocks-past-i_size trimmed off.
> > + * review and fix this.
> > + */
> > + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
> > + S_ISLNK(inode->i_mode)))
> > + return -EINVAL;
> > + if (ext2_inode_is_fast_symlink(inode))
> > + return -EINVAL;
> > + if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
> > + return -EPERM;
> > + __ext2_truncate_blocks(inode, offset);
> > +}
> Actually, looking again into this, I think you've introduced a subtle bug
> into the code. When a write fails for some reason, we did vmtruncate()
> previously which called block_truncate_page() which zeroed a tail of the
> last block. Now, ext2_truncate_blocks() does not do this and I think it
> could be a problem because at least in direct IO case, we could have written
> some data into that block on disk.
> We really rely on the tail of the block being zeroed because otherwise
> extending truncate will show those old data in the block. I plan to change
> that in my mkwrite fixes but until then, we should preserve the old
> assumptions.
> So I think that ext2_truncate_blocks() should do all that tail page magic
> as well (although it's not needed in all cases).
Hi Jan,
Yeah I did think about this and yes we usually do need to zero out
the page but for these error cases with normal writes we shouldn't
write anything in there. For direct IO... I don't see the problem
because we're not coherent with pagecache anyway...
Hmm, but possiby it is a good idea just to keep the same block_truncate_page
calls for this patchset and we can look at it again with your truncate
patches. I'll work on fixing these up.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch 5/5] ext2: convert to use the new truncate convention.
2009-09-02 9:14 ` Nick Piggin
@ 2009-09-02 11:14 ` Jan Kara
0 siblings, 0 replies; 9+ messages in thread
From: Jan Kara @ 2009-09-02 11:14 UTC (permalink / raw)
To: Nick Piggin; +Cc: linux-fsdevel, hch, viro, linux-ext4, Andrew Morton
On Wed 02-09-09 11:14:26, Nick Piggin wrote:
> On Tue, Sep 01, 2009 at 08:29:29PM +0200, Jan Kara wrote:
> > Hi Nick,
> >
> > On Fri 10-07-09 17:30:33, npiggin@suse.de wrote:
> > > I have some questions, marked with XXX.
> > >
> > > Cc: linux-ext4@vger.kernel.org
> > > Signed-off-by: Nick Piggin <npiggin@suse.de>
> > > ---
> > > fs/ext2/ext2.h | 1
> > > fs/ext2/file.c | 2
> > > fs/ext2/inode.c | 138 +++++++++++++++++++++++++++++++++++++++++++++-----------
> > > 3 files changed, 113 insertions(+), 28 deletions(-)
> > >
> > > Index: linux-2.6/fs/ext2/inode.c
> > > ===================================================================
> > > --- linux-2.6.orig/fs/ext2/inode.c
> > > +++ linux-2.6/fs/ext2/inode.c
> > ...
> > > +static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
> > > +{
> > > + /*
> > > + * XXX: it seems like a bug here that we don't allow
> > > + * IS_APPEND inode to have blocks-past-i_size trimmed off.
> > > + * review and fix this.
> > > + */
> > > + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
> > > + S_ISLNK(inode->i_mode)))
> > > + return -EINVAL;
> > > + if (ext2_inode_is_fast_symlink(inode))
> > > + return -EINVAL;
> > > + if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
> > > + return -EPERM;
> > > + __ext2_truncate_blocks(inode, offset);
> > > +}
> > Actually, looking again into this, I think you've introduced a subtle bug
> > into the code. When a write fails for some reason, we did vmtruncate()
> > previously which called block_truncate_page() which zeroed a tail of the
> > last block. Now, ext2_truncate_blocks() does not do this and I think it
> > could be a problem because at least in direct IO case, we could have written
> > some data into that block on disk.
> > We really rely on the tail of the block being zeroed because otherwise
> > extending truncate will show those old data in the block. I plan to change
> > that in my mkwrite fixes but until then, we should preserve the old
> > assumptions.
> > So I think that ext2_truncate_blocks() should do all that tail page magic
> > as well (although it's not needed in all cases).
>
> Hi Jan,
>
> Yeah I did think about this and yes we usually do need to zero out
> the page but for these error cases with normal writes we shouldn't
> write anything in there. For direct IO... I don't see the problem
> because we're not coherent with pagecache anyway...
We are not coherent but that's irrelevant - if a failed direct write
is followed by an extending truncate and read, it will read the block
from disk and could see non-zeros where there should be zeros...
> Hmm, but possiby it is a good idea just to keep the same block_truncate_page
> calls for this patchset and we can look at it again with your truncate
> patches. I'll work on fixing these up.
Yes, I think that keeping this change for a separate patch is definitely
better.
Honza
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2009-09-02 11:14 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20090710073028.782561541@suse.de>
2009-07-10 7:30 ` [patch 5/5] ext2: convert to use the new truncate convention npiggin
2009-09-01 18:29 ` Jan Kara
2009-09-02 9:14 ` Nick Piggin
2009-09-02 11:14 ` Jan Kara
[not found] <20090816102533.329473921@suse.de>
2009-08-16 10:25 ` npiggin
2009-08-16 20:16 ` Christoph Hellwig
2009-08-17 6:42 ` Nick Piggin
2009-08-17 11:09 ` Boaz Harrosh
2009-08-17 16:44 ` Nick Piggin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).