exofs: New truncate sequence
These changes are crafted based on the similar conversion done to ext2 by Nick Piggin. * Remove the deprecated ->truncate vector. Let exofs_setattr take care of on-disk size updates. * Call truncate_pagecache on the unused pages if write_begin/end fails. * Cleanup exofs_delete_inode that did stupid inode writes and updates on an inode that will be removed. * And finally get rid of exofs_get_block. We never had any blocks it was all for calling nobh_truncate_page. nobh_truncate_page is not actually needed in exofs since the last page is complete and gone, just like all the other pages. There is no partial blocks in exofs. I've tested with this patch, and there are no apparent failures, so far. CC: Nick Piggin <npiggin@suse.de> CC: Christoph Hellwig <hch@lst.de> Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
41cce647f8
commit
2f246fd0f1
|
@ -256,7 +256,6 @@ static inline int exofs_oi_read(struct exofs_i_info *oi,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* inode.c */
|
/* inode.c */
|
||||||
void exofs_truncate(struct inode *inode);
|
|
||||||
int exofs_setattr(struct dentry *, struct iattr *);
|
int exofs_setattr(struct dentry *, struct iattr *);
|
||||||
int exofs_write_begin(struct file *file, struct address_space *mapping,
|
int exofs_write_begin(struct file *file, struct address_space *mapping,
|
||||||
loff_t pos, unsigned len, unsigned flags,
|
loff_t pos, unsigned len, unsigned flags,
|
||||||
|
|
|
@ -86,6 +86,5 @@ const struct file_operations exofs_file_operations = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct inode_operations exofs_file_inode_operations = {
|
const struct inode_operations exofs_file_inode_operations = {
|
||||||
.truncate = exofs_truncate,
|
|
||||||
.setattr = exofs_setattr,
|
.setattr = exofs_setattr,
|
||||||
};
|
};
|
||||||
|
|
115
fs/exofs/inode.c
115
fs/exofs/inode.c
|
@ -697,6 +697,13 @@ static int exofs_writepage(struct page *page, struct writeback_control *wbc)
|
||||||
return write_exec(&pcol);
|
return write_exec(&pcol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* i_mutex held using inode->i_size directly */
|
||||||
|
static void _write_failed(struct inode *inode, loff_t to)
|
||||||
|
{
|
||||||
|
if (to > inode->i_size)
|
||||||
|
truncate_pagecache(inode, to, inode->i_size);
|
||||||
|
}
|
||||||
|
|
||||||
int exofs_write_begin(struct file *file, struct address_space *mapping,
|
int exofs_write_begin(struct file *file, struct address_space *mapping,
|
||||||
loff_t pos, unsigned len, unsigned flags,
|
loff_t pos, unsigned len, unsigned flags,
|
||||||
struct page **pagep, void **fsdata)
|
struct page **pagep, void **fsdata)
|
||||||
|
@ -710,7 +717,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
|
||||||
fsdata);
|
fsdata);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
EXOFS_DBGMSG("simple_write_begin faild\n");
|
EXOFS_DBGMSG("simple_write_begin faild\n");
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
page = *pagep;
|
page = *pagep;
|
||||||
|
@ -725,6 +732,9 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
|
||||||
EXOFS_DBGMSG("__readpage_filler faild\n");
|
EXOFS_DBGMSG("__readpage_filler faild\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
if (unlikely(ret))
|
||||||
|
_write_failed(mapping->host, pos + len);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -750,6 +760,10 @@ static int exofs_write_end(struct file *file, struct address_space *mapping,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata);
|
ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata);
|
||||||
|
if (unlikely(ret))
|
||||||
|
_write_failed(inode, pos + len);
|
||||||
|
|
||||||
|
/* TODO: once simple_write_end marks inode dirty remove */
|
||||||
if (i_size != inode->i_size)
|
if (i_size != inode->i_size)
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -808,91 +822,49 @@ static inline int exofs_inode_is_fast_symlink(struct inode *inode)
|
||||||
return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0);
|
return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* get_block_t - Fill in a buffer_head
|
|
||||||
* An OSD takes care of block allocation so we just fake an allocation by
|
|
||||||
* putting in the inode's sector_t in the buffer_head.
|
|
||||||
* TODO: What about the case of create==0 and @iblock does not exist in the
|
|
||||||
* object?
|
|
||||||
*/
|
|
||||||
static int exofs_get_block(struct inode *inode, sector_t iblock,
|
|
||||||
struct buffer_head *bh_result, int create)
|
|
||||||
{
|
|
||||||
map_bh(bh_result, inode->i_sb, iblock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct osd_attr g_attr_logical_length = ATTR_DEF(
|
const struct osd_attr g_attr_logical_length = ATTR_DEF(
|
||||||
OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
|
OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8);
|
||||||
|
|
||||||
static int _do_truncate(struct inode *inode)
|
static int _do_truncate(struct inode *inode, loff_t newsize)
|
||||||
{
|
{
|
||||||
struct exofs_i_info *oi = exofs_i(inode);
|
struct exofs_i_info *oi = exofs_i(inode);
|
||||||
loff_t isize = i_size_read(inode);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||||
|
|
||||||
nobh_truncate_page(inode->i_mapping, isize, exofs_get_block);
|
ret = exofs_oi_truncate(oi, (u64)newsize);
|
||||||
|
if (likely(!ret))
|
||||||
|
truncate_setsize(inode, newsize);
|
||||||
|
|
||||||
ret = exofs_oi_truncate(oi, (u64)isize);
|
EXOFS_DBGMSG("(0x%lx) size=0x%llx ret=>%d\n",
|
||||||
EXOFS_DBGMSG("(0x%lx) size=0x%llx\n", inode->i_ino, isize);
|
inode->i_ino, newsize, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Truncate a file to the specified size - all we have to do is set the size
|
* Set inode attributes - update size attribute on OSD if needed,
|
||||||
* attribute. We make sure the object exists first.
|
* otherwise just call generic functions.
|
||||||
*/
|
|
||||||
void exofs_truncate(struct inode *inode)
|
|
||||||
{
|
|
||||||
struct exofs_i_info *oi = exofs_i(inode);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|
|
||||||
|| S_ISLNK(inode->i_mode)))
|
|
||||||
return;
|
|
||||||
if (exofs_inode_is_fast_symlink(inode))
|
|
||||||
return;
|
|
||||||
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* if we are about to truncate an object, and it hasn't been
|
|
||||||
* created yet, wait
|
|
||||||
*/
|
|
||||||
if (unlikely(wait_obj_created(oi)))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
ret = _do_truncate(inode);
|
|
||||||
if (ret)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
out:
|
|
||||||
mark_inode_dirty(inode);
|
|
||||||
return;
|
|
||||||
fail:
|
|
||||||
make_bad_inode(inode);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set inode attributes - just call generic functions.
|
|
||||||
*/
|
*/
|
||||||
int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
|
int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
/* if we are about to modify an object, and it hasn't been
|
||||||
|
* created yet, wait
|
||||||
|
*/
|
||||||
|
error = wait_obj_created(exofs_i(inode));
|
||||||
|
if (unlikely(error))
|
||||||
|
return error;
|
||||||
|
|
||||||
error = inode_change_ok(inode, iattr);
|
error = inode_change_ok(inode, iattr);
|
||||||
if (error)
|
if (unlikely(error))
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if ((iattr->ia_valid & ATTR_SIZE) &&
|
if ((iattr->ia_valid & ATTR_SIZE) &&
|
||||||
iattr->ia_size != i_size_read(inode)) {
|
iattr->ia_size != i_size_read(inode)) {
|
||||||
int error;
|
error = _do_truncate(inode, iattr->ia_size);
|
||||||
|
if (unlikely(error))
|
||||||
error = vmtruncate(inode, iattr->ia_size);
|
|
||||||
if (error)
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,28 +1317,25 @@ void exofs_delete_inode(struct inode *inode)
|
||||||
|
|
||||||
truncate_inode_pages(&inode->i_data, 0);
|
truncate_inode_pages(&inode->i_data, 0);
|
||||||
|
|
||||||
|
/* TODO: should do better here */
|
||||||
if (is_bad_inode(inode))
|
if (is_bad_inode(inode))
|
||||||
goto no_delete;
|
goto no_delete;
|
||||||
|
|
||||||
mark_inode_dirty(inode);
|
|
||||||
exofs_update_inode(inode, inode_needs_sync(inode));
|
|
||||||
|
|
||||||
inode->i_size = 0;
|
inode->i_size = 0;
|
||||||
if (inode->i_blocks)
|
|
||||||
exofs_truncate(inode);
|
|
||||||
|
|
||||||
clear_inode(inode);
|
clear_inode(inode);
|
||||||
|
|
||||||
ret = exofs_get_io_state(&sbi->layout, &ios);
|
|
||||||
if (unlikely(ret)) {
|
|
||||||
EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we are deleting an obj that hasn't been created yet, wait */
|
/* if we are deleting an obj that hasn't been created yet, wait */
|
||||||
if (!obj_created(oi)) {
|
if (!obj_created(oi)) {
|
||||||
BUG_ON(!obj_2bcreated(oi));
|
BUG_ON(!obj_2bcreated(oi));
|
||||||
wait_event(oi->i_wq, obj_created(oi));
|
wait_event(oi->i_wq, obj_created(oi));
|
||||||
|
/* ignore the error attempt a remove anyway */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now Remove the OSD objects */
|
||||||
|
ret = exofs_get_io_state(&sbi->layout, &ios);
|
||||||
|
if (unlikely(ret)) {
|
||||||
|
EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ios->obj.id = exofs_oi_objno(oi);
|
ios->obj.id = exofs_oi_objno(oi);
|
||||||
|
|
Loading…
Reference in New Issue