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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello, 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 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;
}



--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
FAQ:           http://kernelnewbies.org/faq/


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux