Merge git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-drm-fsl-dcu.git] / fs / sync.c
index aab5ffe77e9fd67e3ac9173a4cb9488fd393f074..d0feff61e6aad6cce80df1d7cad635320b8b25eb 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/writeback.h>
 #include <linux/syscalls.h>
 #include <linux/linkage.h>
 #include <linux/pagemap.h>
+#include <linux/quotaops.h>
+#include <linux/buffer_head.h>
 
 #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
                        SYNC_FILE_RANGE_WAIT_AFTER)
 
+/*
+ * sync everything.  Start out by waking pdflush, because that writes back
+ * all queues in parallel.
+ */
+static void do_sync(unsigned long wait)
+{
+       wakeup_pdflush(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;
+}
+
+void emergency_sync(void)
+{
+       pdflush_operation(do_sync, 0);
+}
+
+/*
+ * Generic function to fsync a file.
+ *
+ * filp may be NULL if called via the msync of a vma.
+ */
+int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+{
+       struct inode * inode = dentry->d_inode;
+       struct super_block * sb;
+       int ret, err;
+
+       /* sync the inode to buffers */
+       ret = write_inode_now(inode, 0);
+
+       /* sync the superblock to buffers */
+       sb = inode->i_sb;
+       lock_super(sb);
+       if (sb->s_op->write_super)
+               sb->s_op->write_super(sb);
+       unlock_super(sb);
+
+       /* .. finally sync the buffers to disk */
+       err = sync_blockdev(sb->s_bdev);
+       if (!ret)
+               ret = err;
+       return ret;
+}
+
+long do_fsync(struct file *file, int datasync)
+{
+       int ret;
+       int err;
+       struct address_space *mapping = file->f_mapping;
+
+       if (!file->f_op || !file->f_op->fsync) {
+               /* Why?  We can still call filemap_fdatawrite */
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = filemap_fdatawrite(mapping);
+
+       /*
+        * We need to protect against concurrent writers, which could cause
+        * livelocks in fsync_buffers_list().
+        */
+       mutex_lock(&mapping->host->i_mutex);
+       err = file->f_op->fsync(file, file->f_path.dentry, datasync);
+       if (!ret)
+               ret = err;
+       mutex_unlock(&mapping->host->i_mutex);
+       err = filemap_fdatawait(mapping);
+       if (!ret)
+               ret = err;
+out:
+       return ret;
+}
+
+static long __do_fsync(unsigned int fd, int datasync)
+{
+       struct file *file;
+       int ret = -EBADF;
+
+       file = fget(fd);
+       if (file) {
+               ret = do_fsync(file, datasync);
+               fput(file);
+       }
+       return ret;
+}
+
+asmlinkage long sys_fsync(unsigned int fd)
+{
+       return __do_fsync(fd, 0);
+}
+
+asmlinkage long sys_fdatasync(unsigned int fd)
+{
+       return __do_fsync(fd, 1);
+}
+
 /*
  * sys_sync_file_range() permits finely controlled syncing over a segment of
  * a file in the range offset .. (offset+nbytes-1) inclusive.  If nbytes is
@@ -100,7 +214,7 @@ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
        }
 
        if (nbytes == 0)
-               endbyte = -1;
+               endbyte = LLONG_MAX;
        else
                endbyte--;              /* inclusive */
 
@@ -109,7 +223,7 @@ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
        if (!file)
                goto out;
 
-       i_mode = file->f_dentry->d_inode->i_mode;
+       i_mode = file->f_path.dentry->d_inode->i_mode;
        ret = -ESPIPE;
        if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
                        !S_ISLNK(i_mode))