diff options
author | OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> | 2014-05-13 20:56:34 +0900 |
---|---|---|
committer | Daniel Phillips <daniel@tux3.org> | 2014-05-13 20:56:34 +0900 |
commit | 9f27a764bbc6b388a80dd1aaf8b86b5c7077511f (patch) | |
tree | ccf8d6a15469cc549bece040379db248c1056746 | |
parent | f84ac75d56bd4b8319198d1d4cb9ee64f96492c0 (diff) | |
download | linux-tux3-9f27a764bbc6b388a80dd1aaf8b86b5c7077511f.tar.gz |
tux3: Fix tux3_iattrdirty() usages
Now, on some paths, mark_inode_dirty() is not called after
tux3_iattrdirty() was called.
E.g. If inode->i_ctime is same with current time, file_update_time()
skips to dirty inode.
tux3_iattrdirty()
file_update_time() {
if (!timespec_equal(&inode->i_ctime, &now))
sync_it |= S_CTIME;
if (sync_it)
mark_inode_dirty_sync()
}
This is wrong as tux3_iattrdirty() usage. tux3_iattrdirty() was
called, the caller must call mark_inode_dirty() too.
Otherwise,
delta = 1
tux3_iattrdirty(inode)
iattr_delta = delta
/* flush delta 1 */
inode is not dirty, so iattr_delta == 1 is remaining
/* flush delta 2 for data pages */
read_idata_for_i_size()
if (iattr_delta != delta)
/*
* iattr_delta is still 1, so read from idata[], but
* idata[] is invalid.
*/
By remaining iattr_delta, future inode flush is confused, and hits to
assertion.
To fix this, this makes sure to call tux3_iattrdirty() only when we call
mark_inode_dirty().
[FIXME: file_update_time() of mmap and write can race.]
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
-rw-r--r-- | fs/tux3/inode.c | 37 | ||||
-rw-r--r-- | fs/tux3/inode_vfslib.c | 7 | ||||
-rw-r--r-- | fs/tux3/writeback_iattrfork.c | 9 |
3 files changed, 39 insertions, 14 deletions
diff --git a/fs/tux3/inode.c b/fs/tux3/inode.c index 9d9f6ff9bffb74..1bfb28f3f5c184 100644 --- a/fs/tux3/inode.c +++ b/fs/tux3/inode.c @@ -572,17 +572,15 @@ static int tux3_truncate(struct inode *inode, loff_t newsize) } /* Change i_size, then clean buffers */ + tux3_iattrdirty(inode); i_size_write(inode, newsize); /* Roundup. Partial page is handled by tux3_truncate_partial_block() */ holebegin = round_up(newsize, boundary); if (newsize <= holebegin) /* Check overflow */ tux3_truncate_pagecache(inode, holebegin); - if (!is_expand) { + if (!is_expand) err = tux3_add_truncate_hole(inode, newsize); - if (err) - goto error; - } inode->i_mtime = inode->i_ctime = gettime(); tux3_mark_inode_dirty(inode); @@ -833,13 +831,13 @@ int tux3_setattr(struct dentry *dentry, struct iattr *iattr) down_write(&tux_inode(inode)->truncate_lock); change_begin(sb); - tux3_iattrdirty(inode); - if (need_truncate) err = tux3_truncate(inode, iattr->ia_size); - if (!err) + if (!err) { + tux3_iattrdirty(inode); setattr_copy(inode, iattr); - tux3_mark_inode_dirty(inode); + tux3_mark_inode_dirty(inode); + } change_end(sb); if (need_lock) @@ -848,6 +846,26 @@ int tux3_setattr(struct dentry *dentry, struct iattr *iattr) return err; } +static int tux3_file_update_time(struct inode *inode, struct timespec *time, + int flags) +{ + /* FIXME: atime is not supported yet */ + if (flags & S_ATIME) + inode->i_atime = *time; + if (!(flags & ~S_ATIME)) + return 0; + + tux3_iattrdirty(inode); + if (flags & S_VERSION) + inode_inc_iversion(inode); + if (flags & S_CTIME) + inode->i_ctime = *time; + if (flags & S_MTIME) + inode->i_mtime = *time; + mark_inode_dirty_sync(inode); + return 0; +} + #include "inode_vfslib.c" static const struct file_operations tux_file_fops = { @@ -870,7 +888,7 @@ static const struct file_operations tux_file_fops = { static const struct inode_operations tux_file_iops = { // .permission = ext4_permission, .setattr = tux3_setattr, - .getattr = tux3_getattr + .getattr = tux3_getattr, #ifdef CONFIG_EXT4DEV_FS_XATTR // .setxattr = generic_setxattr, // .getxattr = generic_getxattr, @@ -879,6 +897,7 @@ static const struct inode_operations tux_file_iops = { #endif // .fallocate = ext4_fallocate, // .fiemap = ext4_fiemap, + .update_time = tux3_file_update_time, }; static const struct inode_operations tux_special_iops = { diff --git a/fs/tux3/inode_vfslib.c b/fs/tux3/inode_vfslib.c index cc096230859875..819a0fd12f8d8d 100644 --- a/fs/tux3/inode_vfslib.c +++ b/fs/tux3/inode_vfslib.c @@ -25,8 +25,7 @@ static ssize_t tux3_file_aio_write(struct kiocb *iocb, const struct iovec *iov, mutex_lock(&inode->i_mutex); /* For each ->write_end() calls change_end(). */ change_begin(sb); - /* For timestamp. FIXME: convert this to ->update_time handler? */ - tux3_iattrdirty(inode); + /* FIXME: file_update_time() in this can be race with mmap */ ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); change_end_if_needed(sb); mutex_unlock(&inode->i_mutex); @@ -71,11 +70,9 @@ static ssize_t tux3_file_splice_write(struct pipe_inode_info *pipe, mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); /* For each ->write_end() calls change_end(). */ change_begin(sb); - /* For timestamp. FIXME: convert this to ->update_time - * handler? */ - tux3_iattrdirty(inode); ret = file_remove_suid(out); if (!ret) { + /* FIXME: file_update_time() can be race with mmap */ ret = file_update_time(out); if (!ret) ret = splice_from_pipe_feed(pipe, &sd, diff --git a/fs/tux3/writeback_iattrfork.c b/fs/tux3/writeback_iattrfork.c index 53f197b377e3e6..8e6c42ca9424e3 100644 --- a/fs/tux3/writeback_iattrfork.c +++ b/fs/tux3/writeback_iattrfork.c @@ -45,6 +45,15 @@ static void idata_copy(struct inode *inode, struct tux3_iattr_data *idata) idata->i_version = inode->i_version; } +/* + * Inode attributes fork. (See comment on top of this source) + * + * NOTE: caller must call tux3_mark_inode_dirty() after + * this. Otherwise, inode state will be remaining after flush, and + * will confuses flusher in future. + * + * FIXME: this is better to call tux3_mark_inode_dirty() too? + */ void tux3_iattrdirty(struct inode *inode) { struct tux3_inode *tuxnode = tux_inode(inode); |