]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zfs_vnops.c
Fix link count of root inode when snapdir is visible
[mirror_zfs.git] / module / zfs / zfs_vnops.c
index bbc171bd2830ac1a07483ecd56e6ea50c2c8adde..41c1bd255753467a272f0677cbcfae2068a1143a 100644 (file)
@@ -439,6 +439,7 @@ int
 zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 {
        int error = 0;
+       boolean_t frsync = B_FALSE;
 
        znode_t *zp = ITOZ(ip);
        zfsvfs_t *zfsvfs = ITOZSB(ip);
@@ -466,12 +467,19 @@ zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                return (0);
        }
 
+#ifdef FRSYNC
        /*
         * If we're in FRSYNC mode, sync out this znode before reading it.
         * Only do this for non-snapshots.
+        *
+        * Some platforms do not support FRSYNC and instead map it
+        * to FSYNC, which results in unnecessary calls to zil_commit. We
+        * only honor FRSYNC requests on platforms which support it.
         */
+       frsync = !!(ioflag & FRSYNC);
+#endif
        if (zfsvfs->z_log &&
-           (ioflag & FRSYNC || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS))
+           (frsync || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS))
                zil_commit(zfsvfs->z_log, zp->z_id);
 
        /*
@@ -814,6 +822,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                        uio->uio_fault_disable = B_TRUE;
                        error = dmu_write_uio_dbuf(sa_get_db(zp->z_sa_hdl),
                            uio, nbytes, tx);
+                       uio->uio_fault_disable = B_FALSE;
                        if (error == EFAULT) {
                                dmu_tx_commit(tx);
                                if (uio_prefaultpages(MIN(n, max_blksz), uio)) {
@@ -1283,7 +1292,7 @@ zfs_lookup(struct inode *dip, char *nm, struct inode **ipp, int flags,
  *             excl    - flag indicating exclusive or non-exclusive mode.
  *             mode    - mode to open file with.
  *             cr      - credentials of caller.
- *             flag    - large file flag [UNUSED].
+ *             flag    - file flag.
  *             vsecp   - ACL to be set
  *
  *     OUT:    ipp     - inode of created or trunc'd entry.
@@ -2648,6 +2657,12 @@ zfs_getattr_fast(struct inode *ip, struct kstat *sp)
        mutex_enter(&zp->z_lock);
 
        generic_fillattr(ip, sp);
+       /*
+        * +1 link count for root inode with visible '.zfs' directory.
+        */
+       if ((zp->z_id == zfsvfs->z_root) && zfs_show_ctldir(zp))
+               if (sp->nlink < ZFS_LINK_MAX)
+                       sp->nlink++;
 
        sa_object_size(zp->z_sa_hdl, &blksize, &nblocks);
        sp->blksize = blksize;
@@ -2702,11 +2717,12 @@ zfs_setattr_dir(znode_t *dzp)
        dmu_tx_t        *tx = NULL;
        uint64_t        uid, gid;
        sa_bulk_attr_t  bulk[4];
-       int             count = 0;
+       int             count;
        int             err;
 
        zap_cursor_init(&zc, os, dzp->z_id);
        while ((err = zap_cursor_retrieve(&zc, &zap)) == 0) {
+               count = 0;
                if (zap.za_integer_length != 8 || zap.za_num_integers != 1) {
                        err = ENXIO;
                        break;
@@ -4858,19 +4874,19 @@ convoff(struct inode *ip, flock64_t *lckdat, int  whence, offset_t offset)
        vattr_t vap;
        int error;
 
-       if ((lckdat->l_whence == 2) || (whence == 2)) {
+       if ((lckdat->l_whence == SEEK_END) || (whence == SEEK_END)) {
                if ((error = zfs_getattr(ip, &vap, 0, CRED())))
                        return (error);
        }
 
        switch (lckdat->l_whence) {
-       case 1:
+       case SEEK_CUR:
                lckdat->l_start += offset;
                break;
-       case 2:
+       case SEEK_END:
                lckdat->l_start += vap.va_size;
                /* FALLTHRU */
-       case 0:
+       case SEEK_SET:
                break;
        default:
                return (SET_ERROR(EINVAL));
@@ -4880,13 +4896,13 @@ convoff(struct inode *ip, flock64_t *lckdat, int  whence, offset_t offset)
                return (SET_ERROR(EINVAL));
 
        switch (whence) {
-       case 1:
+       case SEEK_CUR:
                lckdat->l_start -= offset;
                break;
-       case 2:
+       case SEEK_END:
                lckdat->l_start -= vap.va_size;
                /* FALLTHRU */
-       case 0:
+       case SEEK_SET:
                break;
        default:
                return (SET_ERROR(EINVAL));
@@ -4907,7 +4923,7 @@ convoff(struct inode *ip, flock64_t *lckdat, int  whence, offset_t offset)
  *             bfp     - section of file to free/alloc.
  *             flag    - current file open mode flags.
  *             offset  - current file offset.
- *             cr      - credentials of caller [UNUSED].
+ *             cr      - credentials of caller.
  *
  *     RETURN: 0 on success, error code on failure.
  *
@@ -4941,7 +4957,7 @@ zfs_space(struct inode *ip, int cmd, flock64_t *bfp, int flag,
                return (SET_ERROR(EROFS));
        }
 
-       if ((error = convoff(ip, bfp, 0, offset))) {
+       if ((error = convoff(ip, bfp, SEEK_SET, offset))) {
                ZFS_EXIT(zfsvfs);
                return (error);
        }