Commit 28fd1298 authored by OGAWA Hirofumi's avatar OGAWA Hirofumi Committed by Linus Torvalds

[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)

This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.

See mm/filemap.c:

And changes the filemap_write_and_wait() and filemap_write_and_wait_range().

Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error.  However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)

<quotation>
Andrew Morton writes,

If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc.  Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>

So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.

Trond, could you please review the nfs part?  Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: default avatarTrond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 05eb0b51
...@@ -193,8 +193,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) ...@@ -193,8 +193,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
fid->fid); fid->fid);
fidnum = fid->fid; fidnum = fid->fid;
filemap_fdatawrite(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
filemap_fdatawait(inode->i_mapping);
if (fidnum >= 0) { if (fidnum >= 0) {
dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen,
......
...@@ -165,8 +165,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -165,8 +165,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
return -ENOLCK; return -ENOLCK;
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
filemap_fdatawrite(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
filemap_fdatawait(inode->i_mapping);
invalidate_inode_pages(&inode->i_data); invalidate_inode_pages(&inode->i_data);
} }
......
...@@ -153,14 +153,8 @@ int sync_blockdev(struct block_device *bdev) ...@@ -153,14 +153,8 @@ int sync_blockdev(struct block_device *bdev)
{ {
int ret = 0; int ret = 0;
if (bdev) { if (bdev)
int err; ret = filemap_write_and_wait(bdev->bd_inode->i_mapping);
ret = filemap_fdatawrite(bdev->bd_inode->i_mapping);
err = filemap_fdatawait(bdev->bd_inode->i_mapping);
if (!ret)
ret = err;
}
return ret; return ret;
} }
EXPORT_SYMBOL(sync_blockdev); EXPORT_SYMBOL(sync_blockdev);
......
...@@ -127,8 +127,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, ...@@ -127,8 +127,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
if (file->f_dentry->d_inode->i_mapping) { if (file->f_dentry->d_inode->i_mapping) {
/* BB no need to lock inode until after invalidate /* BB no need to lock inode until after invalidate
since namei code should already have it locked? */ since namei code should already have it locked? */
filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
} }
cFYI(1, ("invalidating remote inode since open detected it " cFYI(1, ("invalidating remote inode since open detected it "
"changed")); "changed"));
...@@ -419,8 +418,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, ...@@ -419,8 +418,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
pCifsInode = CIFS_I(inode); pCifsInode = CIFS_I(inode);
if (pCifsInode) { if (pCifsInode) {
if (can_flush) { if (can_flush) {
filemap_fdatawrite(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
filemap_fdatawait(inode->i_mapping);
/* temporarily disable caching while we /* temporarily disable caching while we
go to server to get inode info */ go to server to get inode info */
pCifsInode->clientCanCacheAll = FALSE; pCifsInode->clientCanCacheAll = FALSE;
......
...@@ -1148,8 +1148,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1148,8 +1148,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
/* BB check if we need to refresh inode from server now ? BB */ /* BB check if we need to refresh inode from server now ? BB */
/* need to flush data before changing file size on server */ /* need to flush data before changing file size on server */
filemap_fdatawrite(direntry->d_inode->i_mapping); filemap_write_and_wait(direntry->d_inode->i_mapping);
filemap_fdatawait(direntry->d_inode->i_mapping);
if (attrs->ia_valid & ATTR_SIZE) { if (attrs->ia_valid & ATTR_SIZE) {
/* To avoid spurious oplock breaks from server, in the case of /* To avoid spurious oplock breaks from server, in the case of
......
...@@ -302,8 +302,7 @@ int dbSync(struct inode *ipbmap) ...@@ -302,8 +302,7 @@ int dbSync(struct inode *ipbmap)
/* /*
* write out dirty pages of bmap * write out dirty pages of bmap
*/ */
filemap_fdatawrite(ipbmap->i_mapping); filemap_write_and_wait(ipbmap->i_mapping);
filemap_fdatawait(ipbmap->i_mapping);
diWriteSpecial(ipbmap, 0); diWriteSpecial(ipbmap, 0);
......
...@@ -265,8 +265,7 @@ int diSync(struct inode *ipimap) ...@@ -265,8 +265,7 @@ int diSync(struct inode *ipimap)
/* /*
* write out dirty pages of imap * write out dirty pages of imap
*/ */
filemap_fdatawrite(ipimap->i_mapping); filemap_write_and_wait(ipimap->i_mapping);
filemap_fdatawait(ipimap->i_mapping);
diWriteSpecial(ipimap, 0); diWriteSpecial(ipimap, 0);
...@@ -565,8 +564,7 @@ void diFreeSpecial(struct inode *ip) ...@@ -565,8 +564,7 @@ void diFreeSpecial(struct inode *ip)
jfs_err("diFreeSpecial called with NULL ip!"); jfs_err("diFreeSpecial called with NULL ip!");
return; return;
} }
filemap_fdatawrite(ip->i_mapping); filemap_write_and_wait(ip->i_mapping);
filemap_fdatawait(ip->i_mapping);
truncate_inode_pages(ip->i_mapping, 0); truncate_inode_pages(ip->i_mapping, 0);
iput(ip); iput(ip);
} }
......
...@@ -1231,10 +1231,8 @@ int txCommit(tid_t tid, /* transaction identifier */ ...@@ -1231,10 +1231,8 @@ int txCommit(tid_t tid, /* transaction identifier */
* when we don't need to worry about it at all. * when we don't need to worry about it at all.
* *
* if ((!S_ISDIR(ip->i_mode)) * if ((!S_ISDIR(ip->i_mode))
* && (tblk->flag & COMMIT_DELETE) == 0) { * && (tblk->flag & COMMIT_DELETE) == 0)
* filemap_fdatawrite(ip->i_mapping); * filemap_write_and_wait(ip->i_mapping);
* filemap_fdatawait(ip->i_mapping);
* }
*/ */
/* /*
......
...@@ -108,8 +108,7 @@ int jfs_umount(struct super_block *sb) ...@@ -108,8 +108,7 @@ int jfs_umount(struct super_block *sb)
* Make sure all metadata makes it to disk before we mark * Make sure all metadata makes it to disk before we mark
* the superblock as clean * the superblock as clean
*/ */
filemap_fdatawrite(sbi->direct_inode->i_mapping); filemap_write_and_wait(sbi->direct_inode->i_mapping);
filemap_fdatawait(sbi->direct_inode->i_mapping);
/* /*
* ensure all file system file pages are propagated to their * ensure all file system file pages are propagated to their
...@@ -161,8 +160,7 @@ int jfs_umount_rw(struct super_block *sb) ...@@ -161,8 +160,7 @@ int jfs_umount_rw(struct super_block *sb)
* mark the superblock clean before everything is flushed to * mark the superblock clean before everything is flushed to
* disk. * disk.
*/ */
filemap_fdatawrite(sbi->direct_inode->i_mapping); filemap_write_and_wait(sbi->direct_inode->i_mapping);
filemap_fdatawait(sbi->direct_inode->i_mapping);
updateSuper(sb, FM_CLEAN); updateSuper(sb, FM_CLEAN);
......
...@@ -376,8 +376,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) ...@@ -376,8 +376,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
* by txCommit(); * by txCommit();
*/ */
filemap_fdatawait(ipbmap->i_mapping); filemap_fdatawait(ipbmap->i_mapping);
filemap_fdatawrite(ipbmap->i_mapping); filemap_write_and_wait(ipbmap->i_mapping);
filemap_fdatawait(ipbmap->i_mapping);
diWriteSpecial(ipbmap, 0); diWriteSpecial(ipbmap, 0);
newPage = nPages; /* first new page number */ newPage = nPages; /* first new page number */
......
...@@ -502,8 +502,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -502,8 +502,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
jfs_err("jfs_umount failed with return code %d", rc); jfs_err("jfs_umount failed with return code %d", rc);
} }
out_mount_failed: out_mount_failed:
filemap_fdatawrite(sbi->direct_inode->i_mapping); filemap_write_and_wait(sbi->direct_inode->i_mapping);
filemap_fdatawait(sbi->direct_inode->i_mapping);
truncate_inode_pages(sbi->direct_inode->i_mapping, 0); truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
make_bad_inode(sbi->direct_inode); make_bad_inode(sbi->direct_inode);
iput(sbi->direct_inode); iput(sbi->direct_inode);
......
...@@ -644,10 +644,7 @@ int nfs_sync_mapping(struct address_space *mapping) ...@@ -644,10 +644,7 @@ int nfs_sync_mapping(struct address_space *mapping)
if (mapping->nrpages == 0) if (mapping->nrpages == 0)
return 0; return 0;
unmap_mapping_range(mapping, 0, 0, 0); unmap_mapping_range(mapping, 0, 0, 0);
ret = filemap_fdatawrite(mapping); ret = filemap_write_and_wait(mapping);
if (ret != 0)
goto out;
ret = filemap_fdatawait(mapping);
if (ret != 0) if (ret != 0)
goto out; goto out;
ret = nfs_wb_all(mapping->host); ret = nfs_wb_all(mapping->host);
...@@ -864,8 +861,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -864,8 +861,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
nfs_begin_data_update(inode); nfs_begin_data_update(inode);
/* Write all dirty data if we're changing file permissions or size */ /* Write all dirty data if we're changing file permissions or size */
if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) { if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) {
if (filemap_fdatawrite(inode->i_mapping) == 0) filemap_write_and_wait(inode->i_mapping);
filemap_fdatawait(inode->i_mapping);
nfs_wb_all(inode); nfs_wb_all(inode);
} }
/* /*
......
...@@ -374,8 +374,7 @@ smb_file_release(struct inode *inode, struct file * file) ...@@ -374,8 +374,7 @@ smb_file_release(struct inode *inode, struct file * file)
/* We must flush any dirty pages now as we won't be able to /* We must flush any dirty pages now as we won't be able to
write anything after close. mmap can trigger this. write anything after close. mmap can trigger this.
"openers" should perhaps include mmap'ers ... */ "openers" should perhaps include mmap'ers ... */
filemap_fdatawrite(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
filemap_fdatawait(inode->i_mapping);
smb_close(inode); smb_close(inode);
} }
unlock_kernel(); unlock_kernel();
......
...@@ -697,8 +697,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr) ...@@ -697,8 +697,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr)
DENTRY_PATH(dentry), DENTRY_PATH(dentry),
(long) inode->i_size, (long) attr->ia_size); (long) inode->i_size, (long) attr->ia_size);
filemap_fdatawrite(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
filemap_fdatawait(inode->i_mapping);
error = smb_open(dentry, O_WRONLY); error = smb_open(dentry, O_WRONLY);
if (error) if (error)
......
...@@ -79,8 +79,7 @@ fs_flushinval_pages( ...@@ -79,8 +79,7 @@ fs_flushinval_pages(
struct inode *ip = LINVFS_GET_IP(vp); struct inode *ip = LINVFS_GET_IP(vp);
if (VN_CACHED(vp)) { if (VN_CACHED(vp)) {
filemap_fdatawrite(ip->i_mapping); filemap_write_and_wait(ip->i_mapping);
filemap_fdatawait(ip->i_mapping);
truncate_inode_pages(ip->i_mapping, first); truncate_inode_pages(ip->i_mapping, first);
} }
......
...@@ -343,30 +343,44 @@ EXPORT_SYMBOL(filemap_fdatawait); ...@@ -343,30 +343,44 @@ EXPORT_SYMBOL(filemap_fdatawait);
int filemap_write_and_wait(struct address_space *mapping) int filemap_write_and_wait(struct address_space *mapping)
{ {
int retval = 0; int err = 0;
if (mapping->nrpages) { if (mapping->nrpages) {
retval = filemap_fdatawrite(mapping); err = filemap_fdatawrite(mapping);
if (retval == 0) /*
retval = filemap_fdatawait(mapping); * Even if the above returned error, the pages may be
* written partially (e.g. -ENOSPC), so we wait for it.
* But the -EIO is special case, it may indicate the worst
* thing (e.g. bug) happened, so we avoid waiting for it.
*/
if (err != -EIO) {
int err2 = filemap_fdatawait(mapping);
if (!err)
err = err2;
} }
return retval; }
return err;
} }
EXPORT_SYMBOL(filemap_write_and_wait);
int filemap_write_and_wait_range(struct address_space *mapping, int filemap_write_and_wait_range(struct address_space *mapping,
loff_t lstart, loff_t lend) loff_t lstart, loff_t lend)
{ {
int retval = 0; int err = 0;
if (mapping->nrpages) { if (mapping->nrpages) {
retval = __filemap_fdatawrite_range(mapping, lstart, lend, err = __filemap_fdatawrite_range(mapping, lstart, lend,
WB_SYNC_ALL); WB_SYNC_ALL);
if (retval == 0) /* See comment of filemap_write_and_wait() */
retval = wait_on_page_writeback_range(mapping, if (err != -EIO) {
int err2 = wait_on_page_writeback_range(mapping,
lstart >> PAGE_CACHE_SHIFT, lstart >> PAGE_CACHE_SHIFT,
lend >> PAGE_CACHE_SHIFT); lend >> PAGE_CACHE_SHIFT);
if (!err)
err = err2;
} }
return retval; }
return err;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment