Illumos #1092: zfs refratio property
[zfs.git] / module / zfs / zfs_vnops.c
index 53d3194..262c1ed 100644 (file)
@@ -399,18 +399,14 @@ zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                return (0);
        }
 
-#ifdef HAVE_MANDLOCKS
        /*
         * Check for mandatory locks
         */
-       if (MANDMODE(zp->z_mode)) {
-               if (error = chklock(ip, FREAD,
-                   uio->uio_loffset, uio->uio_resid, uio->uio_fmode, ct)) {
-                       ZFS_EXIT(zsb);
-                       return (error);
-               }
+       if (mandatory_lock(ip) &&
+           !lock_may_read(ip, uio->uio_loffset, uio->uio_resid)) {
+               ZFS_EXIT(zsb);
+               return (EAGAIN);
        }
-#endif /* HAVE_MANDLOCK */
 
        /*
         * If we're in FRSYNC mode, sync out this znode before reading it.
@@ -581,17 +577,14 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                return (EINVAL);
        }
 
-#ifdef HAVE_MANDLOCKS
        /*
         * Check for mandatory locks before calling zfs_range_lock()
         * in order to prevent a deadlock with locks set via fcntl().
         */
-       if (MANDMODE((mode_t)zp->z_mode) &&
-           (error = chklock(ip, FWRITE, woff, n, uio->uio_fmode, ct)) != 0) {
+       if (mandatory_lock(ip) && !lock_may_write(ip, woff, n)) {
                ZFS_EXIT(zsb);
-               return (error);
+               return (EAGAIN);
        }
-#endif /* HAVE_MANDLOCKS */
 
 #ifdef HAVE_UIO_ZEROCOPY
        /*
@@ -1120,14 +1113,6 @@ zfs_lookup(struct inode *dip, char *nm, struct inode **ipp, int flags,
 
        if (flags & LOOKUP_XATTR) {
                /*
-                * If the xattr property is off, refuse the lookup request.
-                */
-               if (!(zsb->z_flags & ZSB_XATTR_USER)) {
-                       ZFS_EXIT(zsb);
-                       return (EINVAL);
-               }
-
-               /*
                 * We don't allow recursive attributes..
                 * Maybe someday we will.
                 */
@@ -2298,6 +2283,44 @@ zfs_getattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
 EXPORT_SYMBOL(zfs_getattr);
 
 /*
+ * Get the basic file attributes and place them in the provided kstat
+ * structure.  The inode is assumed to be the authoritative source
+ * for most of the attributes.  However, the znode currently has the
+ * authoritative atime, blksize, and block count.
+ *
+ *     IN:     ip      - inode of file.
+ *
+ *     OUT:    sp      - kstat values.
+ *
+ *     RETURN: 0 (always succeeds)
+ */
+/* ARGSUSED */
+int
+zfs_getattr_fast(struct inode *ip, struct kstat *sp)
+{
+       znode_t *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
+
+       mutex_enter(&zp->z_lock);
+
+       generic_fillattr(ip, sp);
+       ZFS_TIME_DECODE(&sp->atime, zp->z_atime);
+
+       sa_object_size(zp->z_sa_hdl, (uint32_t *)&sp->blksize, &sp->blocks);
+       if (unlikely(zp->z_blksz == 0)) {
+               /*
+                * Block size hasn't been set; suggest maximal I/O transfers.
+                */
+               sp->blksize = zsb->z_max_blksz;
+       }
+
+       mutex_exit(&zp->z_lock);
+
+       return (0);
+}
+EXPORT_SYMBOL(zfs_getattr_fast);
+
+/*
  * Set the file attributes to the values contained in the
  * vattr structure.
  *
@@ -2420,7 +2443,7 @@ top:
        aclp = NULL;
 
        /* Can this be moved to before the top label? */
-       if (zsb->z_vfs->mnt_flags & MNT_READONLY) {
+       if (zfs_is_readonly(zsb)) {
                err = EROFS;
                goto out3;
        }
@@ -3815,7 +3838,6 @@ zfs_putpage(struct page *page, struct writeback_control *wbc, void *data)
        struct inode         *ip      = mapping->host;
        znode_t              *zp      = ITOZ(ip);
        zfs_sb_t             *zsb     = ITOZSB(ip);
-       rl_t                 *rl;
        u_offset_t           io_off;
        size_t               io_len;
        size_t               len;
@@ -3827,11 +3849,8 @@ zfs_putpage(struct page *page, struct writeback_control *wbc, void *data)
        ZFS_ENTER(zsb);
        ZFS_VERIFY_ZP(zp);
 
-       rl = zfs_range_lock(zp, io_off, io_len, RL_WRITER);
-
        if (io_off > zp->z_size) {
                /* past end of file */
-               zfs_range_unlock(rl);
                ZFS_EXIT(zsb);
                return (0);
        }
@@ -3839,7 +3858,6 @@ zfs_putpage(struct page *page, struct writeback_control *wbc, void *data)
        len = MIN(io_len, P2ROUNDUP(zp->z_size, PAGESIZE) - io_off);
 
        error = zfs_putapage(ip, page, io_off, len);
-       zfs_range_unlock(rl);
 
        if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
                zil_commit(zsb->z_log, zp->z_id);
@@ -3995,144 +4013,50 @@ zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages)
 }
 EXPORT_SYMBOL(zfs_getpage);
 
-#ifdef HAVE_MMAP
 /*
- * Request a memory map for a section of a file.  This code interacts
- * with common code and the VM system as follows:
- *
- *     common code calls mmap(), which ends up in smmap_common()
- *
- *     this calls VOP_MAP(), which takes you into (say) zfs
- *
- *     zfs_map() calls as_map(), passing segvn_create() as the callback
+ * Check ZFS specific permissions to memory map a section of a file.
  *
- *     segvn_create() creates the new segment and calls VOP_ADDMAP()
+ *     IN:     ip      - inode of the file to mmap
+ *             off     - file offset
+ *             addrp   - start address in memory region
+ *             len     - length of memory region
+ *             vm_flags- address flags
  *
- *     zfs_addmap() updates z_mapcnt
+ *     RETURN: 0 if success
+ *             error code if failure
  */
 /*ARGSUSED*/
-static int
-zfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
-    size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+int
+zfs_map(struct inode *ip, offset_t off, caddr_t *addrp, size_t len,
+    unsigned long vm_flags)
 {
-       znode_t *zp = VTOZ(vp);
-       zfsvfs_t *zfsvfs = zp->z_zfsvfs;
-       segvn_crargs_t  vn_a;
-       int             error;
+       znode_t  *zp = ITOZ(ip);
+       zfs_sb_t *zsb = ITOZSB(ip);
 
-       ZFS_ENTER(zfsvfs);
+       ZFS_ENTER(zsb);
        ZFS_VERIFY_ZP(zp);
 
-       if ((prot & PROT_WRITE) && (zp->z_pflags &
+       if ((vm_flags & VM_WRITE) && (zp->z_pflags &
            (ZFS_IMMUTABLE | ZFS_READONLY | ZFS_APPENDONLY))) {
-               ZFS_EXIT(zfsvfs);
+               ZFS_EXIT(zsb);
                return (EPERM);
        }
 
-       if ((prot & (PROT_READ | PROT_EXEC)) &&
+       if ((vm_flags & (VM_READ | VM_EXEC)) &&
            (zp->z_pflags & ZFS_AV_QUARANTINED)) {
-               ZFS_EXIT(zfsvfs);
+               ZFS_EXIT(zsb);
                return (EACCES);
        }
 
-       if (vp->v_flag & VNOMAP) {
-               ZFS_EXIT(zfsvfs);
-               return (ENOSYS);
-       }
-
        if (off < 0 || len > MAXOFFSET_T - off) {
-               ZFS_EXIT(zfsvfs);
+               ZFS_EXIT(zsb);
                return (ENXIO);
        }
 
-       if (vp->v_type != VREG) {
-               ZFS_EXIT(zfsvfs);
-               return (ENODEV);
-       }
-
-       /*
-        * If file is locked, disallow mapping.
-        */
-       if (MANDMODE(zp->z_mode) && vn_has_flocks(vp)) {
-               ZFS_EXIT(zfsvfs);
-               return (EAGAIN);
-       }
-
-       as_rangelock(as);
-       error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
-       if (error != 0) {
-               as_rangeunlock(as);
-               ZFS_EXIT(zfsvfs);
-               return (error);
-       }
-
-       vn_a.vp = vp;
-       vn_a.offset = (u_offset_t)off;
-       vn_a.type = flags & MAP_TYPE;
-       vn_a.prot = prot;
-       vn_a.maxprot = maxprot;
-       vn_a.cred = cr;
-       vn_a.amp = NULL;
-       vn_a.flags = flags & ~MAP_TYPE;
-       vn_a.szc = 0;
-       vn_a.lgrp_mem_policy_flags = 0;
-
-       error = as_map(as, *addrp, len, segvn_create, &vn_a);
-
-       as_rangeunlock(as);
-       ZFS_EXIT(zfsvfs);
-       return (error);
-}
-
-/* ARGSUSED */
-static int
-zfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
-    size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
-{
-       uint64_t pages = btopr(len);
-
-       atomic_add_64(&VTOZ(vp)->z_mapcnt, pages);
-       return (0);
-}
-
-/*
- * The reason we push dirty pages as part of zfs_delmap() is so that we get a
- * more accurate mtime for the associated file.  Since we don't have a way of
- * detecting when the data was actually modified, we have to resort to
- * heuristics.  If an explicit msync() is done, then we mark the mtime when the
- * last page is pushed.  The problem occurs when the msync() call is omitted,
- * which by far the most common case:
- *
- *     open()
- *     mmap()
- *     <modify memory>
- *     munmap()
- *     close()
- *     <time lapse>
- *     putpage() via fsflush
- *
- * If we wait until fsflush to come along, we can have a modification time that
- * is some arbitrary point in the future.  In order to prevent this in the
- * common case, we flush pages whenever a (MAP_SHARED, PROT_WRITE) mapping is
- * torn down.
- */
-/* ARGSUSED */
-static int
-zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
-    size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
-{
-       uint64_t pages = btopr(len);
-
-       ASSERT3U(VTOZ(vp)->z_mapcnt, >=, pages);
-       atomic_add_64(&VTOZ(vp)->z_mapcnt, -pages);
-
-       if ((flags & MAP_SHARED) && (prot & PROT_WRITE) &&
-           vn_has_cached_data(vp))
-               (void) VOP_PUTPAGE(vp, off, len, B_ASYNC, cr, ct);
-
+       ZFS_EXIT(zsb);
        return (0);
 }
-#endif /* HAVE_MMAP */
+EXPORT_SYMBOL(zfs_map);
 
 /*
  * convoff - converts the given data (start, whence) to the