]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zpl_file.c
cstyle: Resolve C style issues
[mirror_zfs.git] / module / zfs / zpl_file.c
index 5ac41c9d24e9747a649e7e28e1a8bb5fb731e577..3737bb51911dc2a207c8f31c5cf3677bd8dce7b4 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 
+#include <sys/dmu_objset.h>
 #include <sys/zfs_vfsops.h>
 #include <sys/zfs_vnops.h>
 #include <sys/zfs_znode.h>
@@ -35,15 +36,16 @@ zpl_open(struct inode *ip, struct file *filp)
        cred_t *cr = CRED();
        int error;
 
+       error = generic_file_open(ip, filp);
+       if (error)
+               return (error);
+
        crhold(cr);
        error = -zfs_open(ip, filp->f_mode, filp->f_flags, cr);
        crfree(cr);
        ASSERT3S(error, <=, 0);
 
-       if (error)
-               return (error);
-
-       return generic_file_open(ip, filp);
+       return (error);
 }
 
 static int
@@ -52,6 +54,9 @@ zpl_release(struct inode *ip, struct file *filp)
        cred_t *cr = CRED();
        int error;
 
+       if (ITOZ(ip)->z_atime_dirty)
+               mark_inode_dirty(ip);
+
        crhold(cr);
        error = -zfs_close(ip, filp->f_flags, cr);
        crfree(cr);
@@ -61,21 +66,34 @@ zpl_release(struct inode *ip, struct file *filp)
 }
 
 static int
-zpl_readdir(struct file *filp, void *dirent, filldir_t filldir)
+zpl_iterate(struct file *filp, struct dir_context *ctx)
 {
        struct dentry *dentry = filp->f_path.dentry;
        cred_t *cr = CRED();
        int error;
 
        crhold(cr);
-       error = -zfs_readdir(dentry->d_inode, dirent, filldir,
-           &filp->f_pos, cr);
+       error = -zfs_readdir(dentry->d_inode, ctx, cr);
        crfree(cr);
        ASSERT3S(error, <=, 0);
 
        return (error);
 }
 
+#if !defined(HAVE_VFS_ITERATE)
+static int
+zpl_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
+       int error;
+
+       error = zpl_iterate(filp, &ctx);
+       filp->f_pos = ctx.pos;
+
+       return (error);
+}
+#endif /* HAVE_VFS_ITERATE */
+
 #if defined(HAVE_FSYNC_WITH_DENTRY)
 /*
  * Linux 2.6.x - 2.6.34 API,
@@ -151,9 +169,10 @@ zpl_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 
 ssize_t
 zpl_read_common(struct inode *ip, const char *buf, size_t len, loff_t pos,
-     uio_seg_t segment, int flags, cred_t *cr)
+    uio_seg_t segment, int flags, cred_t *cr)
 {
        int error;
+       ssize_t read;
        struct iovec iov;
        uio_t uio;
 
@@ -171,7 +190,10 @@ zpl_read_common(struct inode *ip, const char *buf, size_t len, loff_t pos,
        if (error < 0)
                return (error);
 
-       return (len - uio.uio_resid);
+       read = len - uio.uio_resid;
+       task_io_account_read(read);
+
+       return (read);
 }
 
 static ssize_t
@@ -197,6 +219,7 @@ zpl_write_common(struct inode *ip, const char *buf, size_t len, loff_t pos,
     uio_seg_t segment, int flags, cred_t *cr)
 {
        int error;
+       ssize_t wrote;
        struct iovec iov;
        uio_t uio;
 
@@ -214,7 +237,10 @@ zpl_write_common(struct inode *ip, const char *buf, size_t len, loff_t pos,
        if (error < 0)
                return (error);
 
-       return (len - uio.uio_resid);
+       wrote = len - uio.uio_resid;
+       task_io_account_write(wrote);
+
+       return (wrote);
 }
 
 static ssize_t
@@ -235,6 +261,28 @@ zpl_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
        return (wrote);
 }
 
+static loff_t
+zpl_llseek(struct file *filp, loff_t offset, int whence)
+{
+#if defined(SEEK_HOLE) && defined(SEEK_DATA)
+       if (whence == SEEK_DATA || whence == SEEK_HOLE) {
+               struct inode *ip = filp->f_mapping->host;
+               loff_t maxbytes = ip->i_sb->s_maxbytes;
+               loff_t error;
+
+               spl_inode_lock(ip);
+               error = -zfs_holey(ip, whence, &offset);
+               if (error == 0)
+                       error = lseek_execute(filp, ip, offset, maxbytes);
+               spl_inode_unlock(ip);
+
+               return (error);
+       }
+#endif /* SEEK_HOLE && SEEK_DATA */
+
+       return (generic_file_llseek(filp, offset, whence));
+}
+
 /*
  * It's worth taking a moment to describe how mmap is implemented
  * for zfs because it differs considerably from other Linux filesystems.
@@ -333,7 +381,7 @@ zpl_readpage(struct file *filp, struct page *pp)
        }
 
        unlock_page(pp);
-       return error;
+       return (error);
 }
 
 /*
@@ -357,21 +405,16 @@ zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data)
 
        ASSERT(PageLocked(pp));
        ASSERT(!PageWriteback(pp));
+       ASSERT(!(current->flags & PF_NOFS));
 
        /*
-        * Disable the normal reclaim path for zpl_putpage().  This
-        * ensures that all memory allocations under this call path
-        * will never enter direct reclaim.  If this were to happen
-        * the VM might try to write out additional pages by calling
-        * zpl_putpage() again resulting in a deadlock.
+        * Annotate this call path with a flag that indicates that it is
+        * unsafe to use KM_SLEEP during memory allocations due to the
+        * potential for a deadlock.  KM_PUSHPAGE should be used instead.
         */
-       if (current->flags & PF_MEMALLOC) {
-               (void) zfs_putpage(mapping->host, pp, wbc);
-       } else {
-               current->flags |= PF_MEMALLOC;
-               (void) zfs_putpage(mapping->host, pp, wbc);
-               current->flags &= ~PF_MEMALLOC;
-       }
+       current->flags |= PF_NOFS;
+       (void) zfs_putpage(mapping->host, pp, wbc);
+       current->flags &= ~PF_NOFS;
 
        return (0);
 }
@@ -379,7 +422,43 @@ zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data)
 static int
 zpl_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
-       return write_cache_pages(mapping, wbc, zpl_putpage, mapping);
+       znode_t         *zp = ITOZ(mapping->host);
+       zfs_sb_t        *zsb = ITOZSB(mapping->host);
+       enum writeback_sync_modes sync_mode;
+       int result;
+
+       ZFS_ENTER(zsb);
+       if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               wbc->sync_mode = WB_SYNC_ALL;
+       ZFS_EXIT(zsb);
+       sync_mode = wbc->sync_mode;
+
+       /*
+        * We don't want to run write_cache_pages() in SYNC mode here, because
+        * that would make putpage() wait for a single page to be committed to
+        * disk every single time, resulting in atrocious performance. Instead
+        * we run it once in non-SYNC mode so that the ZIL gets all the data,
+        * and then we commit it all in one go.
+        */
+       wbc->sync_mode = WB_SYNC_NONE;
+       result = write_cache_pages(mapping, wbc, zpl_putpage, mapping);
+       if (sync_mode != wbc->sync_mode) {
+               ZFS_ENTER(zsb);
+               ZFS_VERIFY_ZP(zp);
+               zil_commit(zsb->z_log, zp->z_id);
+               ZFS_EXIT(zsb);
+
+               /*
+                * We need to call write_cache_pages() again (we can't just
+                * return after the commit) because the previous call in
+                * non-SYNC mode does not guarantee that we got all the dirty
+                * pages (see the implementation of write_cache_pages() for
+                * details). That being said, this is a no-op in most cases.
+                */
+               wbc->sync_mode = sync_mode;
+               result = write_cache_pages(mapping, wbc, zpl_putpage, mapping);
+       }
+       return (result);
 }
 
 /*
@@ -391,7 +470,10 @@ zpl_writepages(struct address_space *mapping, struct writeback_control *wbc)
 static int
 zpl_writepage(struct page *pp, struct writeback_control *wbc)
 {
-       return zpl_putpage(pp, wbc, pp->mapping);
+       if (ITOZSB(pp->mapping->host)->z_os->os_sync == ZFS_SYNC_ALWAYS)
+               wbc->sync_mode = WB_SYNC_ALL;
+
+       return (zpl_putpage(pp, wbc, pp->mapping));
 }
 
 /*
@@ -438,30 +520,62 @@ zpl_fallocate(struct file *filp, int mode, loff_t offset, loff_t len)
 }
 #endif /* HAVE_FILE_FALLOCATE */
 
+static long
+zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case ZFS_IOC_GETFLAGS:
+       case ZFS_IOC_SETFLAGS:
+               return (-EOPNOTSUPP);
+       default:
+               return (-ENOTTY);
+       }
+}
+
+#ifdef CONFIG_COMPAT
+static long
+zpl_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       return (zpl_ioctl(filp, cmd, arg));
+}
+#endif /* CONFIG_COMPAT */
+
+
 const struct address_space_operations zpl_address_space_operations = {
        .readpages      = zpl_readpages,
        .readpage       = zpl_readpage,
        .writepage      = zpl_writepage,
-       .writepages     = zpl_writepages,
+       .writepages     = zpl_writepages,
 };
 
 const struct file_operations zpl_file_operations = {
        .open           = zpl_open,
        .release        = zpl_release,
-       .llseek         = generic_file_llseek,
+       .llseek         = zpl_llseek,
        .read           = zpl_read,
        .write          = zpl_write,
-       .readdir        = zpl_readdir,
        .mmap           = zpl_mmap,
        .fsync          = zpl_fsync,
 #ifdef HAVE_FILE_FALLOCATE
-       .fallocate      = zpl_fallocate,
+       .fallocate      = zpl_fallocate,
 #endif /* HAVE_FILE_FALLOCATE */
+       .unlocked_ioctl = zpl_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = zpl_compat_ioctl,
+#endif
 };
 
 const struct file_operations zpl_dir_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
+#ifdef HAVE_VFS_ITERATE
+       .iterate        = zpl_iterate,
+#else
        .readdir        = zpl_readdir,
+#endif
        .fsync          = zpl_fsync,
+       .unlocked_ioctl = zpl_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = zpl_compat_ioctl,
+#endif
 };