reset directory link counts on I/O failure
[unix-history] / usr / src / sys / ufs / ffs / ufs_vnops.c
index 2c69e20..8716f21 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ufs_vnops.c 7.53 (Berkeley) %G%
+ *     @(#)ufs_vnops.c 7.56 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -113,7 +113,7 @@ int spec_lookup(),
        ufsspec_close(),
        spec_advlock(),
        spec_badop(),
        ufsspec_close(),
        spec_advlock(),
        spec_badop(),
-       spec_nullop();
+       nullop();
 
 struct vnodeops spec_inodeops = {
        spec_lookup,            /* lookup */
 
 struct vnodeops spec_inodeops = {
        spec_lookup,            /* lookup */
@@ -129,7 +129,7 @@ struct vnodeops spec_inodeops = {
        spec_ioctl,             /* ioctl */
        spec_select,            /* select */
        spec_badop,             /* mmap */
        spec_ioctl,             /* ioctl */
        spec_select,            /* select */
        spec_badop,             /* mmap */
-       spec_nullop,            /* fsync */
+       nullop,                 /* fsync */
        spec_badop,             /* seek */
        spec_badop,             /* remove */
        spec_badop,             /* link */
        spec_badop,             /* seek */
        spec_badop,             /* remove */
        spec_badop,             /* link */
@@ -162,8 +162,7 @@ int fifo_lookup(),
        ufsfifo_close(),
        fifo_print(),
        fifo_advlock(),
        ufsfifo_close(),
        fifo_print(),
        fifo_advlock(),
-       fifo_badop(),
-       fifo_nullop();
+       fifo_badop();
 
 struct vnodeops fifo_inodeops = {
        fifo_lookup,            /* lookup */
 
 struct vnodeops fifo_inodeops = {
        fifo_lookup,            /* lookup */
@@ -179,7 +178,7 @@ struct vnodeops fifo_inodeops = {
        fifo_ioctl,             /* ioctl */
        fifo_select,            /* select */
        fifo_badop,             /* mmap */
        fifo_ioctl,             /* ioctl */
        fifo_select,            /* select */
        fifo_badop,             /* mmap */
-       fifo_nullop,            /* fsync */
+       nullop,                 /* fsync */
        fifo_badop,             /* seek */
        fifo_badop,             /* remove */
        fifo_badop,             /* link */
        fifo_badop,             /* seek */
        fifo_badop,             /* remove */
        fifo_badop,             /* link */
@@ -860,6 +859,7 @@ ufs_link(vp, ndp)
                error = direnter(ip, ndp);
        if (ndp->ni_dvp != vp)
                IUNLOCK(ip);
                error = direnter(ip, ndp);
        if (ndp->ni_dvp != vp)
                IUNLOCK(ip);
+       vput(ndp->ni_dvp);
        if (error) {
                ip->i_nlink--;
                ip->i_flag |= ICHG;
        if (error) {
                ip->i_nlink--;
                ip->i_flag |= ICHG;
@@ -962,7 +962,8 @@ ufs_rename(fndp, tndp)
                VOP_UNLOCK(fndp->ni_vp);
                if (error)
                        goto bad;
                VOP_UNLOCK(fndp->ni_vp);
                if (error)
                        goto bad;
-               tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
+               tndp->ni_nameiop &= ~(MODMASK | OPMASK);
+               tndp->ni_nameiop |= RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
                do {
                        dp = VTOI(tndp->ni_dvp);
                        if (xp != NULL)
                do {
                        dp = VTOI(tndp->ni_dvp);
                        if (xp != NULL)
@@ -1001,8 +1002,14 @@ ufs_rename(fndp, tndp)
                        if (error = iupdat(dp, &time, &time, 1))
                                goto bad;
                }
                        if (error = iupdat(dp, &time, &time, 1))
                                goto bad;
                }
-               if (error = direnter(ip, tndp))
-                       goto out;
+               if (error = direnter(ip, tndp)) {
+                       if (doingdirectory && newparent) {
+                               dp->i_nlink--;
+                               dp->i_flag |= ICHG;
+                               (void) iupdat(dp, &time, &time, 1);
+                       }
+                       goto bad;
+               }
        } else {
                if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
                        panic("rename: EXDEV");
        } else {
                if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
                        panic("rename: EXDEV");
@@ -1082,7 +1089,8 @@ ufs_rename(fndp, tndp)
        /*
         * 3) Unlink the source.
         */
        /*
         * 3) Unlink the source.
         */
-       fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+       fndp->ni_nameiop &= ~(MODMASK | OPMASK);
+       fndp->ni_nameiop |= DELETE | LOCKPARENT | LOCKLEAF;
        (void)namei(fndp);
        if (fndp->ni_vp != NULL) {
                xp = VTOI(fndp->ni_vp);
        (void)namei(fndp);
        if (fndp->ni_vp != NULL) {
                xp = VTOI(fndp->ni_vp);
@@ -1232,7 +1240,8 @@ ufs_mkdir(ndp, vap)
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
-       error = iupdat(dp, &time, &time, 1);
+       if (error = iupdat(dp, &time, &time, 1))
+               goto bad;
 
        /*
         * Initialize directory with "."
 
        /*
         * Initialize directory with "."
@@ -1260,12 +1269,12 @@ ufs_mkdir(ndp, vap)
         * install the entry for it in
         * the parent directory.
         */
         * install the entry for it in
         * the parent directory.
         */
-       error = direnter(ip, ndp);
-       dp = NULL;
-       if (error) {
-               ndp->ni_nameiop = LOOKUP | NOCACHE;
+       if (error = direnter(ip, ndp)) {
+               ndp->ni_nameiop &= ~(MODMASK | OPMASK);
+               ndp->ni_nameiop |= LOOKUP | LOCKLEAF | NOCACHE;
                error = namei(ndp);
                if (!error) {
                error = namei(ndp);
                if (!error) {
+                       iput(dp);
                        dp = VTOI(ndp->ni_vp);
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        dp = VTOI(ndp->ni_vp);
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
@@ -1283,8 +1292,7 @@ bad:
                iput(ip);
        } else
                ndp->ni_vp = ITOV(ip);
                iput(ip);
        } else
                ndp->ni_vp = ITOV(ip);
-       if (dp)
-               iput(dp);
+       iput(dp);
        return (error);
 }
 
        return (error);
 }
 
@@ -1715,10 +1723,9 @@ maknode(mode, ndp, ipp)
         */
        if (error = iupdat(ip, &time, &time, 1))
                goto bad;
         */
        if (error = iupdat(ip, &time, &time, 1))
                goto bad;
-       if (error = direnter(ip, ndp)) {
-               pdir = NULL;
+       if (error = direnter(ip, ndp))
                goto bad;
                goto bad;
-       }
+       iput(pdir);
        *ipp = ip;
        return (0);
 
        *ipp = ip;
        return (0);
 
@@ -1727,8 +1734,7 @@ bad:
         * Write error occurred trying to update the inode
         * or the directory so must deallocate the inode.
         */
         * Write error occurred trying to update the inode
         * or the directory so must deallocate the inode.
         */
-       if (pdir)
-               iput(pdir);
+       iput(pdir);
        ip->i_nlink = 0;
        ip->i_flag |= ICHG;
        iput(ip);
        ip->i_nlink = 0;
        ip->i_flag |= ICHG;
        iput(ip);
@@ -1803,13 +1809,17 @@ ufs_advlock(vp, id, op, fl, flags)
         */
        switch(op) {
        case F_SETLK:
         */
        switch(op) {
        case F_SETLK:
-               return (ufs_setlock(lock));
+               return (lf_setlock(lock));
 
        case F_UNLCK:
 
        case F_UNLCK:
-               return (ufs_advunlock(lock));
+               error = lf_clearlock(lock);
+               FREE(lock, M_LOCKF);
+               return (error);
 
        case F_GETLK:
 
        case F_GETLK:
-               return (ufs_advgetlock(lock, fl));
+               error = lf_getlock(lock, fl);
+               FREE(lock, M_LOCKF);
+               return (error);
        
        default:
                free(lock, M_LOCKF);
        
        default:
                free(lock, M_LOCKF);
@@ -1817,168 +1827,3 @@ ufs_advlock(vp, id, op, fl, flags)
        }
        /* NOTREACHED */
 }
        }
        /* NOTREACHED */
 }
-
-/*
- * This variable controls the maximum number of processes that will
- * be checked in doing deadlock detection.
- */
-int maxlockdepth = MAXDEPTH;
-
-/*
- * Set a byte-range lock.
- */
-ufs_setlock(lock)
-       register struct lockf *lock;
-{
-       register struct inode *ip = lock->lf_inode;
-       register struct lockf *block;
-       static char lockstr[] = "lockf";
-       int priority, error;
-
-#ifdef LOCKF_DEBUG
-       if (lockf_debug & 4)
-               lf_print("ufs_setlock", lock);
-#endif /* LOCKF_DEBUG */
-
-       /*
-        * Set the priority
-        */
-       priority = PLOCK;
-       if ((lock->lf_type & F_WRLCK) == 0)
-               priority += 4;
-       priority |= PCATCH;
-       /*
-        * Scan lock list for this file looking for locks that would block us.
-        */
-       while (block = lf_getblock(lock)) {
-               /*
-                * Free the structure and return if nonblocking.
-                */
-               if ((lock->lf_flags & F_WAIT) == 0) {
-                       free(lock, M_LOCKF);
-                       return (EAGAIN);
-               }
-               /*
-                * We are blocked. Since flock style locks cover
-                * the whole file, there is no chance for deadlock.
-                * For byte-range locks we must check for deadlock.
-                *
-                * Deadlock detection is done by looking through the
-                * wait channels to see if there are any cycles that
-                * involve us. MAXDEPTH is set just to make sure we
-                * do not go off into neverland.
-                */
-               if ((lock->lf_flags & F_POSIX) &&
-                   (block->lf_flags & F_POSIX)) {
-                       register struct proc *wproc;
-                       register struct lockf *waitblock;
-                       int i = 0;
-
-                       /* The block is waiting on something */
-                       wproc = (struct proc *)block->lf_id;
-                       while (wproc->p_wchan &&
-                              (wproc->p_wmesg == lockstr) &&
-                              (i++ < maxlockdepth)) {
-                               waitblock = (struct lockf *)wproc->p_wchan;
-                               /* Get the owner of the blocking lock */
-                               waitblock = waitblock->lf_next;
-                               if ((waitblock->lf_flags & F_POSIX) == 0)
-                                       break;
-                               wproc = (struct proc *)waitblock->lf_id;
-                               if (wproc == (struct proc *)lock->lf_id) {
-                                       free(lock, M_LOCKF);
-                                       return (EDEADLK);
-                               }
-                       }
-               }
-               /*
-                * Add our lock to the blocked
-                * list and sleep until we're free.
-                */
-#ifdef LOCKF_DEBUG
-               if (lockf_debug & 4)
-                       lf_print("ufs_advlock: blocking on", block);
-#endif /* LOCKF_DEBUG */
-               /*
-                * Remember who blocked us (for deadlock detection)
-                */
-               lock->lf_next = block;
-               lf_addblock(block, lock);
-               if (error = tsleep((caddr_t *)lock, priority, lockstr, 0)) {
-                       free(lock, M_LOCKF);
-                       return (error);
-               }
-       }
-       /*
-        * No blocks!!  Add the lock.  Note that addlock will
-        * downgrade or upgrade any overlapping locks this
-        * process already owns.
-        */
-       lf_addlock(lock);
-#ifdef LOCKF_DEBUG
-       if (lockf_debug & 4) {
-               lf_print("ufs_advlock: got the lock", lock);
-               lf_printlist(lock);
-       }
-#endif /* LOCKF_DEBUG */
-       return (0);
-}
-
-/*
- * Remove a byte-range lock on an inode.
- */
-ufs_advunlock(lock)
-       struct lockf *lock;
-{
-       struct lockf *blocklist;
-
-       if (lock->lf_inode->i_lockf == (struct lockf *)0)
-               return (0);
-#ifdef LOCKF_DEBUG
-       if (lockf_debug & 4)
-               lf_print("ufs_advunlock", lock);
-#endif /* LOCKF_DEBUG */
-       /*
-        * Generally, find the lock (or an overlap to that lock)
-        * and remove it (or shrink it), then wakeup anyone we can.
-        */
-       blocklist = lf_remove(lock);
-#ifdef LOCKF_DEBUG
-       lf_printlist(lock);
-#endif /* LOCKF_DEBUG */
-       FREE(lock, M_LOCKF);
-       lf_wakelock(blocklist);
-       return (0);
-}
-
-/*
- * Return the blocking pid
- */
-ufs_advgetlock(lock, fl)
-       register struct lockf *lock;
-       register struct flock *fl;
-{
-       register struct lockf *block;
-       off_t start, end;
-
-#ifdef LOCKF_DEBUG
-       if (lockf_debug & 4)
-               lf_print("ufs_advgetlock", lock);
-#endif /* LOCKF_DEBUG */
-
-       if (block = lf_getblock(lock)) {
-               fl->l_type = block->lf_type;
-               fl->l_whence = SEEK_SET;
-               fl->l_start = block->lf_start;
-               if (block->lf_end == -1)
-                       fl->l_len = 0;
-               else
-                       fl->l_len = block->lf_end - block->lf_start + 1;
-               if (block->lf_flags & F_POSIX)
-                       fl->l_pid = ((struct proc *)(block->lf_id))->p_pid;
-               else
-                       fl->l_pid = -1;
-       }
-       FREE(lock, M_LOCKF);
-       return (0);
-}