Question about sys_fsync() of memory-mapped pages and private buffers

From: josephl
Date: Sun Dec 26 2004 - 05:51:47 EST


Dear All,

I'm sorry I posted this question for several times.

I have some questions about syncing of memory-mapped pages and private
buffers of files. I cannot not find answer elsewhere on the web and hope
some real kernel developers could help me.

1. Why should sys_fsync() call filemap_fdatawrite()? Isn't it redundant in
kernel 2.6? since do_writepages() -> mpage_writepages() will walk the
list of dirty pages of the given address space and writepage() all of
them, and, both filemap_fdatawrite() andfile->f_op->fsync() (ext2, for
example) eventually call do_writepages() function.

(In Linux 2.4, filemap_fdatasync() is necessary because ext2_sync_file()
doesn't take care of dirty memory-mapped pages. It only deals with
dirty buffers listed in the inode)

-----------------------------
asmlinkage long sys_fsync(unsigned int fd)
{
struct file * file;
struct address_space *mapping;
int ret, err;

ret = -EBADF;
file = fget(fd);
if (!file)
goto out;

mapping = file->f_mapping;

ret = -EINVAL;
if (!file->f_op || !file->f_op->fsync) {
/* Why? We can still call filemap_fdatawrite */
goto out_putf;
}

/* We need to protect against concurrent writers.. */
down(&mapping->host->i_sem);
current->flags |= PF_SYNCWRITE;
ret = filemap_fdatawrite(mapping);
err = file->f_op->fsync(file, file->f_dentry, 0);
if (!ret)
ret = err;
err = filemap_fdatawait(mapping);
if (!ret)
ret = err;
current->flags &= ~PF_SYNCWRITE;
up(&mapping->host->i_sem);

out_putf:
fput(file);
out:
return ret;
}
-----------------------------


2. for ext2, the purpose of sync_mapping_buffers() is to write out all
indirect blocks of an address_space, which is called by
ext2_sync_file()<-sys_fsync(). How do these buffers got sync'ed at
sys_sync()? I don't find code writing out these private buffers.

Is it because that these buffers' pages are tagged dirty in radix_tree
and are written out via sync_inodes(). If so,this should apply for
ext2_sync_file(), ie. sync_mapping_buffers() is not necessary.

-----------------------------
int ext2_sync_file(struct file *file, struct dentry *dentry, int datasync)
{
struct inode *inode = dentry->d_inode;
int err;
int ret;

ret = sync_mapping_buffers(inode->i_mapping);
if (!(inode->i_state & I_DIRTY))
return ret;
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
return ret;

err = ext2_sync_inode(inode);
if (ret == 0)
ret = err;
return ret;
}

static void do_sync(unsigned long wait)
{
wakeup_bdflush(0);
sync_inodes(0); /* All mappings, inodes and their blockdevs
*/
DQUOT_SYNC(NULL);
sync_supers(); /* Write the superblocks */
sync_filesystems(0); /* Start syncing the filesystems */
sync_filesystems(wait); /* Waitingly sync the filesystems */
sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */
if (!wait)
printk("Emergency Sync complete\n");
if (unlikely(laptop_mode))
laptop_sync_completion();
}

asmlinkage long sys_sync(void)
{
do_sync(1);
return 0;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/