[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: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
OGAWA Hirofumi 2006-01-08 01:02:14 -08:00 committed by Linus Torvalds
parent 05eb0b51fb
commit 28fd129827
16 changed files with 48 additions and 61 deletions

View file

@ -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,

View file

@ -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);
} }

View file

@ -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);

View 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,
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;

View file

@ -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

View file

@ -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);

View file

@ -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)
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);
} }

View file

@ -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);
* }
*/ */
/* /*

View file

@ -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)
* 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);

View file

@ -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 */

View file

@ -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);

View file

@ -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)
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);
} }
/* /*

View 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();

View file

@ -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)

View file

@ -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);
} }

View file

@ -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) {
lstart >> PAGE_CACHE_SHIFT, int err2 = wait_on_page_writeback_range(mapping,
lend >> PAGE_CACHE_SHIFT); lstart >> PAGE_CACHE_SHIFT,
lend >> PAGE_CACHE_SHIFT);
if (!err)
err = err2;
}
} }
return retval; return err;
} }
/* /*