]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zfs_vnops.c
Fix ENOSPC in "Handle zap_add() failures in ..."
[mirror_zfs.git] / module / zfs / zfs_vnops.c
index c065c0c59b18023863ee869750c6647b769116cb..5a2e55eb19afb6bdc0b0f75662396df81dcb1c7a 100644 (file)
  *
  *     If dmu_tx_assign() returns ERESTART and zfsvfs->z_assign is TXG_NOWAIT,
  *     then drop all locks, call dmu_tx_wait(), and try again.  On subsequent
- *     calls to dmu_tx_assign(), pass TXG_WAITED rather than TXG_NOWAIT,
+ *     calls to dmu_tx_assign(), pass TXG_NOTHROTTLE in addition to TXG_NOWAIT,
  *     to indicate that this operation has already called dmu_tx_wait().
  *     This will ensure that we don't retry forever, waiting a short bit
  *     each time.
  *     rw_enter(...);                  // grab any other locks you need
  *     tx = dmu_tx_create(...);        // get DMU tx
  *     dmu_tx_hold_*();                // hold each object you might modify
- *     error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+ *     error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
  *     if (error) {
  *             rw_exit(...);           // drop locks
  *             zfs_dirent_unlock(dl);  // unlock directory entry
@@ -398,6 +398,7 @@ mappedread(struct inode *ip, int nbytes, uio_t *uio)
                pp = find_lock_page(mp, start >> PAGE_SHIFT);
                if (pp) {
                        ASSERT(PageUptodate(pp));
+                       unlock_page(pp);
 
                        pb = kmap(pp);
                        error = uiomove(pb + off, bytes, UIO_READ, uio);
@@ -407,7 +408,6 @@ mappedread(struct inode *ip, int nbytes, uio_t *uio)
                                flush_dcache_page(pp);
 
                        mark_page_accessed(pp);
-                       unlock_page(pp);
                        put_page(pp);
                } else {
                        error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl),
@@ -482,8 +482,10 @@ zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 
        /*
         * If we're in FRSYNC mode, sync out this znode before reading it.
+        * Only do this for non-snapshots.
         */
-       if (ioflag & FRSYNC || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
+       if (zfsvfs->z_log &&
+           (ioflag & FRSYNC || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS))
                zil_commit(zfsvfs->z_log, zp->z_id);
 
        /*
@@ -834,7 +836,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                            aiov->iov_base != abuf->b_data)) {
                                ASSERT(xuio);
                                dmu_write(zfsvfs->z_os, zp->z_id, woff,
-                                   // cppcheck-suppress nullPointer
+                                   /* cppcheck-suppress nullPointer */
                                    aiov->iov_len, aiov->iov_base, tx);
                                dmu_return_arcbuf(abuf);
                                xuio_stat_wbuf_copied();
@@ -1002,7 +1004,6 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
        uint64_t object = lr->lr_foid;
        uint64_t offset = lr->lr_offset;
        uint64_t size = lr->lr_length;
-       blkptr_t *bp = &lr->lr_blkptr;
        dmu_buf_t *db;
        zgd_t *zgd;
        int error = 0;
@@ -1049,7 +1050,7 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
        } else { /* indirect write */
                /*
                 * Have to lock the whole block to ensure when it's
-                * written out and it's checksum is being calculated
+                * written out and its checksum is being calculated
                 * that no one can change the data. We need to re-check
                 * blocksize after we get the lock in case it's changed!
                 */
@@ -1079,11 +1080,7 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
                            DMU_READ_NO_PREFETCH);
 
                if (error == 0) {
-                       blkptr_t *obp = dmu_buf_get_blkptr(db);
-                       if (obp) {
-                               ASSERT(BP_IS_HOLE(bp));
-                               *bp = *obp;
-                       }
+                       blkptr_t *bp = &lr->lr_blkptr;
 
                        zgd->zgd_db = db;
                        zgd->zgd_bp = bp;
@@ -1430,7 +1427,9 @@ top:
                        dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
                            0, acl_ids.z_aclp->z_acl_bytes);
                }
-               error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+
+               error = dmu_tx_assign(tx,
+                   (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
                if (error) {
                        zfs_dirent_unlock(dl);
                        if (error == ERESTART) {
@@ -1446,10 +1445,22 @@ top:
                }
                zfs_mknode(dzp, vap, tx, cr, 0, &zp, &acl_ids);
 
+               error = zfs_link_create(dl, zp, tx, ZNEW);
+               if (error != 0) {
+                       /*
+                        * Since, we failed to add the directory entry for it,
+                        * delete the newly created dnode.
+                        */
+                       zfs_znode_delete(zp, tx);
+                       remove_inode_hash(ZTOI(zp));
+                       zfs_acl_ids_free(&acl_ids);
+                       dmu_tx_commit(tx);
+                       goto out;
+               }
+
                if (fuid_dirtied)
                        zfs_fuid_sync(zfsvfs, tx);
 
-               (void) zfs_link_create(dl, zp, tx, ZNEW);
                txtype = zfs_log_create_txtype(Z_FILE, vsecp, vap);
                if (flag & FIGNORECASE)
                        txtype |= TX_CI;
@@ -1605,7 +1616,7 @@ top:
                dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
                    0, acl_ids.z_aclp->z_acl_bytes);
        }
-       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
        if (error) {
                if (error == ERESTART) {
                        waited = B_TRUE;
@@ -1778,7 +1789,7 @@ top:
         */
        dmu_tx_mark_netfree(tx);
 
-       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
        if (error) {
                zfs_dirent_unlock(dl);
                if (error == ERESTART) {
@@ -2020,7 +2031,7 @@ top:
        dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
            ZFS_SA_BASE_ATTR_SIZE);
 
-       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
        if (error) {
                zfs_dirent_unlock(dl);
                if (error == ERESTART) {
@@ -2040,13 +2051,18 @@ top:
         */
        zfs_mknode(dzp, vap, tx, cr, 0, &zp, &acl_ids);
 
-       if (fuid_dirtied)
-               zfs_fuid_sync(zfsvfs, tx);
-
        /*
         * Now put new name in parent dir.
         */
-       (void) zfs_link_create(dl, zp, tx, ZNEW);
+       error = zfs_link_create(dl, zp, tx, ZNEW);
+       if (error != 0) {
+               zfs_znode_delete(zp, tx);
+               remove_inode_hash(ZTOI(zp));
+               goto out;
+       }
+
+       if (fuid_dirtied)
+               zfs_fuid_sync(zfsvfs, tx);
 
        *ipp = ZTOI(zp);
 
@@ -2056,6 +2072,7 @@ top:
        zfs_log_create(zilog, tx, txtype, dzp, zp, dirname, vsecp,
            acl_ids.z_fuidp, vap);
 
+out:
        zfs_acl_ids_free(&acl_ids);
 
        dmu_tx_commit(tx);
@@ -2065,10 +2082,14 @@ top:
        if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
                zil_commit(zilog, 0);
 
-       zfs_inode_update(dzp);
-       zfs_inode_update(zp);
+       if (error != 0) {
+               iput(ZTOI(zp));
+       } else {
+               zfs_inode_update(dzp);
+               zfs_inode_update(zp);
+       }
        ZFS_EXIT(zfsvfs);
-       return (0);
+       return (error);
 }
 
 /*
@@ -2159,7 +2180,7 @@ top:
        zfs_sa_upgrade_txholds(tx, zp);
        zfs_sa_upgrade_txholds(tx, dzp);
        dmu_tx_mark_netfree(tx);
-       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
        if (error) {
                rw_exit(&zp->z_parent_lock);
                rw_exit(&zp->z_name_lock);
@@ -2226,7 +2247,7 @@ out:
  */
 /* ARGSUSED */
 int
-zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
+zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr)
 {
        znode_t         *zp = ITOZ(ip);
        zfsvfs_t        *zfsvfs = ITOZSB(ip);
@@ -2331,7 +2352,7 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
                        type = ZFS_DIRENT_TYPE(zap.za_first_integer);
                }
 
-               done = !dir_emit(ctx, zap.za_name, strlen(zap.za_name),
+               done = !zpl_dir_emit(ctx, zap.za_name, strlen(zap.za_name),
                    objnum, type);
                if (done)
                        break;
@@ -3159,18 +3180,18 @@ top:
                    &atime, sizeof (atime));
        }
 
-       if (mask & ATTR_MTIME) {
+       if (mask & (ATTR_MTIME | ATTR_SIZE)) {
                ZFS_TIME_ENCODE(&vap->va_mtime, mtime);
-               ZTOI(zp)->i_mtime = timespec_trunc(vap->va_mtime,
+               ZTOI(zp)->i_mtime = zpl_inode_timespec_trunc(vap->va_mtime,
                    ZTOI(zp)->i_sb->s_time_gran);
 
                SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL,
                    mtime, sizeof (mtime));
        }
 
-       if (mask & ATTR_CTIME) {
+       if (mask & (ATTR_CTIME | ATTR_SIZE)) {
                ZFS_TIME_ENCODE(&vap->va_ctime, ctime);
-               ZTOI(zp)->i_ctime = timespec_trunc(vap->va_ctime,
+               ZTOI(zp)->i_ctime = zpl_inode_timespec_trunc(vap->va_ctime,
                    ZTOI(zp)->i_sb->s_time_gran);
                SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
                    ctime, sizeof (ctime));
@@ -3626,7 +3647,7 @@ top:
 
        zfs_sa_upgrade_txholds(tx, szp);
        dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
-       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
        if (error) {
                if (zl != NULL)
                        zfs_rename_unlock(&zl);
@@ -3686,6 +3707,13 @@ top:
                                VERIFY3U(zfs_link_destroy(tdl, szp, tx,
                                    ZRENAMING, NULL), ==, 0);
                        }
+               } else {
+                       /*
+                        * If we had removed the existing target, subsequent
+                        * call to zfs_link_create() to add back the same entry
+                        * but, the new dnode (szp) should not fail.
+                        */
+                       ASSERT(tzp == NULL);
                }
        }
 
@@ -3818,7 +3846,7 @@ top:
        }
        if (fuid_dirtied)
                zfs_fuid_txhold(zfsvfs, tx);
-       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
        if (error) {
                zfs_dirent_unlock(dl);
                if (error == ERESTART) {
@@ -3856,14 +3884,18 @@ top:
        /*
         * Insert the new object into the directory.
         */
-       (void) zfs_link_create(dl, zp, tx, ZNEW);
-
-       if (flags & FIGNORECASE)
-               txtype |= TX_CI;
-       zfs_log_symlink(zilog, tx, txtype, dzp, zp, name, link);
+       error = zfs_link_create(dl, zp, tx, ZNEW);
+       if (error != 0) {
+               zfs_znode_delete(zp, tx);
+               remove_inode_hash(ZTOI(zp));
+       } else {
+               if (flags & FIGNORECASE)
+                       txtype |= TX_CI;
+               zfs_log_symlink(zilog, tx, txtype, dzp, zp, name, link);
 
-       zfs_inode_update(dzp);
-       zfs_inode_update(zp);
+               zfs_inode_update(dzp);
+               zfs_inode_update(zp);
+       }
 
        zfs_acl_ids_free(&acl_ids);
 
@@ -3871,10 +3903,14 @@ top:
 
        zfs_dirent_unlock(dl);
 
-       *ipp = ZTOI(zp);
+       if (error == 0) {
+               *ipp = ZTOI(zp);
 
-       if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
-               zil_commit(zilog, 0);
+               if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
+                       zil_commit(zilog, 0);
+       } else {
+               iput(ZTOI(zp));
+       }
 
        ZFS_EXIT(zfsvfs);
        return (error);
@@ -4044,7 +4080,7 @@ top:
 
        zfs_sa_upgrade_txholds(tx, szp);
        zfs_sa_upgrade_txholds(tx, dzp);
-       error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
+       error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT);
        if (error) {
                zfs_dirent_unlock(dl);
                if (error == ERESTART) {
@@ -4566,7 +4602,7 @@ convoff(struct inode *ip, flock64_t *lckdat, int  whence, offset_t offset)
        int error;
 
        if ((lckdat->l_whence == 2) || (whence == 2)) {
-               if ((error = zfs_getattr(ip, &vap, 0, CRED()) != 0))
+               if ((error = zfs_getattr(ip, &vap, 0, CRED())))
                        return (error);
        }