libafs: fs flushall for unix cm
[openafs.git] / src / afs / afs_pioctl.c
index d1af181..df194b5 100644 (file)
@@ -277,6 +277,7 @@ DECL_PIOCTL(PRemoveMount);
 DECL_PIOCTL(PGetCellStatus);
 DECL_PIOCTL(PSetCellStatus);
 DECL_PIOCTL(PFlushVolumeData);
+DECL_PIOCTL(PFlushAllVolumeData);
 DECL_PIOCTL(PGetVnodeXStatus);
 DECL_PIOCTL(PGetVnodeXStatus2);
 DECL_PIOCTL(PSetSysName);
@@ -420,6 +421,7 @@ static pioctlFunction CpioctlSw[] = {
     PBogus,                     /* 11 */
     PPrecache,                  /* 12 */
     PGetPAG,                    /* 13 */
+    PFlushAllVolumeData,        /* 14 */
 };
 
 static pioctlFunction OpioctlSw[]  = {
@@ -568,8 +570,7 @@ kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
            if (((uap->com >> 8) & 0xff) == 'V') {
                struct afs_ioctl *datap;
                AFS_GLOCK();
-               datap =
-                   (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
                code=copyin_afs_ioctl((char *)uap->arg, datap);
                if (code) {
                    osi_FreeSmallSpace(datap);
@@ -677,8 +678,7 @@ afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
            if (((uap->com >> 8) & 0xff) == 'V') {
                struct afs_ioctl *datap;
                AFS_GLOCK();
-               datap =
-                   (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+               datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
                code=copyin_afs_ioctl((char *)uap->arg, datap);
                if (code) {
                    osi_FreeSmallSpace(datap);
@@ -1241,7 +1241,13 @@ afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 #endif /* AFS_NEED_CLIENTCONTEXT */
     if (vp) {
 #ifdef AFS_LINUX22_ENV
+       /*
+        * Holding the global lock when calling dput can cause a deadlock
+        * when the kernel calls back into afs_dentry_iput
+        */
+       AFS_GUNLOCK();
        dput(dp);
+       AFS_GLOCK();
 #else
 #if defined(AFS_FBSD80_ENV)
     if (VOP_ISLOCKED(vp))
@@ -2149,7 +2155,7 @@ DECL_PIOCTL(PFlush)
     afs_BozonLock(&avc->pvnLock, avc); /* Since afs_TryToSmush will do a pvn_vptrunc */
 #endif
     ObtainWriteLock(&avc->lock, 225);
-    afs_ResetVCache(avc, *acred);
+    afs_ResetVCache(avc, *acred, 0);
     ReleaseWriteLock(&avc->lock);
 #ifdef AFS_BOZONLOCK_ENV
     afs_BozonUnlock(&avc->pvnLock, avc);
@@ -3438,46 +3444,27 @@ DECL_PIOCTL(PSetCellStatus)
     return 0;
 }
 
-/*!
- * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
- *
- * \ingroup pioctl
- *
- * \param[in] ain      not in use (args in avc)
- * \param[out] aout    not in use
- *
- * \retval EINVAL      Error if some of the standard args aren't set
- * \retval EIO         Error if the afs daemon hasn't started yet
- *
- * \post
- *     Flush all cached contents of a volume.  Exactly what stays and what
- *     goes depends on the platform.
- *
- * \notes
- *     Does not flush a file that a user has open and is using, because
- *     it will be re-created on next write.  Also purges the dnlc,
- *     because things are screwed up.
- */
-DECL_PIOCTL(PFlushVolumeData)
+static void
+FlushVolumeData(struct VenusFid *afid, afs_ucred_t * acred)
 {
     afs_int32 i;
     struct dcache *tdc;
     struct vcache *tvc;
     struct volume *tv;
-    afs_int32 cell, volume;
+    afs_int32 all = 0;
+    afs_int32 cell = 0;
+    afs_int32 volume = 0;
     struct afs_q *tq, *uq;
 #ifdef AFS_DARWIN80_ENV
     vnode_t vp;
 #endif
 
-    AFS_STATCNT(PFlushVolumeData);
-    if (!avc)
-       return EINVAL;
-    if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
-       return EIO;             /* Inappropriate ioctl for device */
-
-    volume = avc->f.fid.Fid.Volume;    /* who to zap */
-    cell = avc->f.fid.Cell;
+    if (!afid) {
+       all = 1;
+    } else {
+       volume = afid->Fid.Volume;      /* who to zap */
+       cell = afid->Cell;
+    }
 
     /*
      * Clear stat'd flag from all vnodes from this volume; this will
@@ -3485,11 +3472,11 @@ DECL_PIOCTL(PFlushVolumeData)
      */
  loop:
     ObtainReadLock(&afs_xvcache);
-    i = VCHashV(&avc->f.fid);
-    for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
+    for (i = (afid ? VCHashV(afid) : 0); i < VCSIZE; i = (afid ? VCSIZE : i+1)) {
+       for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
            uq = QPrev(tq);
            tvc = QTOVH(tq);
-           if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
+           if (all || (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell)) {
                if (tvc->f.states & CVInit) {
                    ReleaseReadLock(&afs_xvcache);
                    afs_osi_Sleep(&tvc->f.states);
@@ -3518,14 +3505,7 @@ DECL_PIOCTL(PFlushVolumeData)
                afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
 #endif
                ObtainWriteLock(&tvc->lock, 232);
-
-               ObtainWriteLock(&afs_xcbhash, 458);
-               afs_DequeueCallback(tvc);
-               tvc->f.states &= ~(CStatd | CDirty);
-               ReleaseWriteLock(&afs_xcbhash);
-               if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
-                   osi_dnlc_purgedp(tvc);
-               afs_TryToSmush(tvc, *acred, 1);
+               afs_ResetVCache(tvc, acred, 1);
                ReleaseWriteLock(&tvc->lock);
 #ifdef AFS_BOZONLOCK_ENV
                afs_BozonUnlock(&tvc->pvnLock, tvc);
@@ -3539,6 +3519,7 @@ DECL_PIOCTL(PFlushVolumeData)
                AFS_FAST_RELE(tvc);
            }
        }
+    }
     ReleaseReadLock(&afs_xvcache);
 
 
@@ -3552,13 +3533,15 @@ DECL_PIOCTL(PFlushVolumeData)
        }
        if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
            ReleaseReadLock(&tdc->tlock);
-           if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
-               if (!(afs_indexFlags[i] & IFDataMod)) {
+           if (all || (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell)) {
+               if (!(afs_indexFlags[i] & (IFDataMod | IFFree | IFDiscarded))) {
                    /* if the file is modified, but has a ref cnt of only 1,
                     * then someone probably has the file open and is writing
                     * into it. Better to skip flushing such a file, it will be
                     * brought back immediately on the next write anyway.
                     *
+                    * Skip if already freed.
+                    *
                     * If we *must* flush, then this code has to be rearranged
                     * to call afs_storeAllSegments() first */
                    afs_FlushDCache(tdc);
@@ -3574,7 +3557,7 @@ DECL_PIOCTL(PFlushVolumeData)
     ObtainReadLock(&afs_xvolume);
     for (i = 0; i < NVOLS; i++) {
        for (tv = afs_volumes[i]; tv; tv = tv->next) {
-           if (tv->volume == volume) {
+           if (all || tv->volume == volume) {
                afs_ResetVolumeInfo(tv);
                break;
            }
@@ -3585,9 +3568,70 @@ DECL_PIOCTL(PFlushVolumeData)
     /* probably, a user is doing this, probably, because things are screwed up.
      * maybe it's the dnlc's fault? */
     osi_dnlc_purge();
+}
+
+/*!
+ * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use (args in avc)
+ * \param[out] aout    not in use
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ *
+ * \post
+ *     Flush all cached contents of a volume.  Exactly what stays and what
+ *     goes depends on the platform.
+ *
+ * \notes
+ *     Does not flush a file that a user has open and is using, because
+ *     it will be re-created on next write.  Also purges the dnlc,
+ *     because things are screwed up.
+ */
+DECL_PIOCTL(PFlushVolumeData)
+{
+    AFS_STATCNT(PFlushVolumeData);
+    if (!avc)
+       return EINVAL;
+    if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
+       return EIO;             /* Inappropriate ioctl for device */
+
+    FlushVolumeData(&avc->f.fid, *acred);
     return 0;
 }
 
+/*!
+ * VIOC_FLUSHALL (14) - Flush whole volume's data for all volumes
+ *
+ * \ingroup pioctl
+ *
+ * \param[in] ain      not in use
+ * \param[out] aout    not in use
+ *
+ * \retval EINVAL      Error if some of the standard args aren't set
+ * \retval EIO         Error if the afs daemon hasn't started yet
+ *
+ * \post
+ *     Flush all cached contents.  Exactly what stays and what
+ *     goes depends on the platform.
+ *
+ * \notes
+ *     Does not flush a file that a user has open and is using, because
+ *     it will be re-created on next write.  Also purges the dnlc,
+ *     because things are screwed up.
+ */
+DECL_PIOCTL(PFlushAllVolumeData)
+{
+    AFS_STATCNT(PFlushAllVolumeData);
+
+    if (!afs_resourceinit_flag)        /* afs daemons haven't started yet */
+       return EIO;             /* Inappropriate ioctl for device */
+
+    FlushVolumeData(NULL, *acred);
+    return 0;
+}
 
 /*!
  * VIOCGETVCXSTATUS (41) - gets vnode x status
@@ -5094,7 +5138,12 @@ DECL_PIOCTL(PSetCachingThreshold)
        cache_bypass_threshold = threshold;
         afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
        /* TODO:  move to separate pioctl, or enhance pioctl */
-       cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
+       if (threshold == AFS_CACHE_BYPASS_DISABLED)
+           cache_bypass_strategy = NEVER_BYPASS_CACHE;
+       else if (!threshold)
+           cache_bypass_strategy = ALWAYS_BYPASS_CACHE;
+       else
+           cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
     }
 
     /* Return the current size threshold */
@@ -5181,7 +5230,7 @@ DECL_PIOCTL(PCallBackAddr)
        /* get a connection, even if host is down; bumps conn ref count */
        tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
        tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
-                         1 /*force */ , 1 /*create */ , SHARED_LOCK, &rxconn);
+                         1 /*force */ , 1 /*create */ , SHARED_LOCK, 0, &rxconn);
        afs_PutUser(tu, SHARED_LOCK);
        if (!tc)
            continue;
@@ -5324,7 +5373,15 @@ DECL_PIOCTL(PSetTokens2)
     }
 
     if (tokenSet.flags & AFSTOKEN_EX_SETPAG) {
+#if defined(AFS_LINUX26_ENV)
+       afs_ucred_t *old_cred = *acred;
+#endif
        if (_settok_setParentPag(acred) == 0) {
+#if defined(AFS_LINUX26_ENV)
+           /* setpag() may have changed our credentials */
+           *acred = crref();
+           crfree(old_cred);
+#endif
            afs_InitReq(&treq, *acred);
            areq = &treq;
        }