linux-truncate-race-20090109
[openafs.git] / src / afs / VNOPS / afs_vnop_attrs.c
index c181233..58b9a00 100644 (file)
@@ -40,6 +40,7 @@ extern struct vcache *afs_globalVp;
 extern struct vfs *afs_globalVFS;
 #endif
 
+
 /* copy out attributes from cache entry */
 int
 afs_CopyOutAttrs(register struct vcache *avc, register struct vattr *attrs)
@@ -105,14 +106,17 @@ afs_CopyOutAttrs(register struct vcache *avc, register struct vattr *attrs)
        /* The mount point's vnode. */
        if (tvp) {
            attrs->va_nodeid =
-               tvp->mtpoint.Fid.Vnode + (tvp->mtpoint.Fid.Volume << 16);
+             afs_calc_inum (tvp->mtpoint.Fid.Volume,
+                             tvp->mtpoint.Fid.Vnode);
            if (FidCmp(&afs_rootFid, &avc->fid) && !attrs->va_nodeid)
                attrs->va_nodeid = 2;
            afs_PutVolume(tvp, READ_LOCK);
        } else
            attrs->va_nodeid = 2;
     } else
-       attrs->va_nodeid = avc->fid.Fid.Vnode + (avc->fid.Fid.Volume << 16);
+       attrs->va_nodeid = 
+             afs_calc_inum (avc->fid.Fid.Volume,
+                             avc->fid.Fid.Vnode);
     attrs->va_nodeid &= 0x7fffffff;    /* Saber C hates negative inode #s! */
     attrs->va_nlink = fakedir ? 100 : avc->m.LinkCount;
     attrs->va_size = fakedir ? 4096 : avc->m.Length;
@@ -144,9 +148,9 @@ afs_CopyOutAttrs(register struct vcache *avc, register struct vattr *attrs)
     attrs->va_flags = 0;
 #endif
 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
-    attrs->va_blksize = PAGESIZE;      /* XXX Was 8192 XXX */
+    attrs->va_blksize = AFS_BLKSIZE;   /* XXX Was 8192 XXX */
 #else
-    attrs->va_blocksize = PAGESIZE;    /* XXX Was 8192 XXX */
+    attrs->va_blocksize = AFS_BLKSIZE; /* XXX Was 8192 XXX */
 #endif
     attrs->va_rdev = 1;
 #if defined(AFS_HPUX110_ENV)
@@ -158,20 +162,20 @@ afs_CopyOutAttrs(register struct vcache *avc, register struct vattr *attrs)
      * Below return 0 (and not 1) blocks if the file is zero length. This conforms
      * better with the other filesystems that do return 0.      
      */
-#ifdef AFS_HPUX_ENV
-    attrs->va_blocks = (attrs->va_size ? ((attrs->va_size + 1023) >> 10) : 0);
-#elif defined(AFS_SGI_ENV)
-    attrs->va_blocks = BTOBB(attrs->va_size);
-#elif defined(AFS_XBSD_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
+#if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
     attrs->va_bytes = (attrs->va_size ? (attrs->va_size + 1023) : 1024);
 #ifdef va_bytes_rsv
     attrs->va_bytes_rsv = -1;
 #endif
-#else
-    attrs->va_blocks =
-       (attrs->va_size ? ((attrs->va_size + 1023) >> 10) << 1 : 0);
+#elif defined(AFS_HPUX_ENV)
+    attrs->va_blocks = (attrs->va_size ? ((attrs->va_size + 1023)>>10) : 0);
+#elif defined(AFS_SGI_ENV)
+    attrs->va_blocks = BTOBB(attrs->va_size);
+#elif defined(AFS_SUN5_ENV)
+    attrs->va_nblocks = (attrs->va_size ? ((attrs->va_size + 1023)>>10)<<1:0);
+#else /* everything else */
+    attrs->va_blocks = (attrs->va_size ? ((attrs->va_size + 1023)>>10)<<1:0);
 #endif
-
     return 0;
 }
 
@@ -188,7 +192,6 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, struct AFS_UCRED *acred)
 {
     afs_int32 code;
     struct vrequest treq;
-    extern struct unixuser *afs_FindUser();
     struct unixuser *au;
     int inited = 0;
     OSI_VC_CONVERT(avc);
@@ -227,6 +230,8 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, struct AFS_UCRED *acred)
     }
 #endif
 
+    AFS_DISCON_LOCK();
+
 #ifdef AFS_BOZONLOCK_ENV
     afs_BozonLock(&avc->pvnLock, avc);
 #endif
@@ -325,6 +330,9 @@ afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, struct AFS_UCRED *acred)
            }
        }
     }
+
+    AFS_DISCON_UNLOCK();
+
     if (!code)
        return 0;
     code = afs_CheckCode(code, &treq, 14);
@@ -344,7 +352,7 @@ afs_VAttrToAS(register struct vcache *avc, register struct vattr *av,
 #elif  defined(AFS_AIX_ENV)
 /* Boy, was this machine dependent bogosity hard to swallow????.... */
     if (av->va_mode != -1) {
-#elif  defined(AFS_LINUX22_ENV)
+#elif  defined(AFS_LINUX22_ENV) || defined(UKERNEL)
     if (av->va_mask & ATTR_MODE) {
 #elif  defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (av->va_mask & AT_MODE) {
@@ -363,7 +371,7 @@ afs_VAttrToAS(register struct vcache *avc, register struct vattr *av,
     }
 #if     defined(AFS_DARWIN80_ENV)
     if (VATTR_IS_ACTIVE(av, va_gid)) {
-#elif defined(AFS_LINUX22_ENV)
+#elif defined(AFS_LINUX22_ENV) || defined(UKERNEL)
     if (av->va_mask & ATTR_GID) {
 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (av->va_mask & AT_GID) {
@@ -383,7 +391,7 @@ afs_VAttrToAS(register struct vcache *avc, register struct vattr *av,
     }
 #if     defined(AFS_DARWIN80_ENV)
     if (VATTR_IS_ACTIVE(av, va_uid)) {
-#elif defined(AFS_LINUX22_ENV)
+#elif defined(AFS_LINUX22_ENV) || defined(UKERNEL)
     if (av->va_mask & ATTR_UID) {
 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (av->va_mask & AT_UID) {
@@ -403,7 +411,7 @@ afs_VAttrToAS(register struct vcache *avc, register struct vattr *av,
     }
 #if     defined(AFS_DARWIN80_ENV)
     if (VATTR_IS_ACTIVE(av, va_modify_time)) {
-#elif  defined(AFS_LINUX22_ENV)
+#elif  defined(AFS_LINUX22_ENV) || defined(UKERNEL)
     if (av->va_mask & ATTR_MTIME) {
 #elif  defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (av->va_mask & AT_MTIME) {
@@ -460,6 +468,8 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
     if ((code = afs_InitReq(&treq, acred)))
        return code;
 
+    AFS_DISCON_LOCK();
+
     afs_InitFakeStat(&fakestate);
     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
     if (code)
@@ -482,7 +492,7 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
      */
 #if    defined(AFS_DARWIN80_ENV)
     if (VATTR_IS_ACTIVE(attrs, va_data_size)) {
-#elif  defined(AFS_LINUX22_ENV)
+#elif  defined(AFS_LINUX22_ENV) || defined(UKERNEL)
     if (attrs->va_mask & ATTR_SIZE) {
 #elif  defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (attrs->va_mask & AT_SIZE) {
@@ -499,6 +509,11 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
        }
     }
 
+    if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
+        code = ENETDOWN;
+        goto done;
+    }
+
     afs_VAttrToAS(avc, attrs, &astat); /* interpret request */
     code = 0;
 #ifdef AFS_BOZONLOCK_ENV
@@ -515,31 +530,47 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
 #endif
 #if    defined(AFS_DARWIN80_ENV)
     if (VATTR_IS_ACTIVE(attrs, va_data_size)) {
-#elif  defined(AFS_LINUX22_ENV)
+#elif  defined(AFS_LINUX22_ENV) || defined(UKERNEL)
     if (attrs->va_mask & ATTR_SIZE) {
 #elif  defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (attrs->va_mask & AT_SIZE) {
 #elif  defined(AFS_OSF_ENV) || defined(AFS_XBSD_ENV)
     if (attrs->va_size != VNOVAL) {
-#else
+#elif  defined(AFS_AIX41_ENV)
     if (attrs->va_size != -1) {
+#else
+    if (attrs->va_size != ~0) {
 #endif
        afs_size_t tsize = attrs->va_size;
        ObtainWriteLock(&avc->lock, 128);
        avc->states |= CDirty;
+
        code = afs_TruncateAllSegments(avc, tsize, &treq, acred);
+#ifdef AFS_LINUX_26_ENV
+       /* We must update the Linux kernel's idea of file size as soon as
+        * possible, to avoid racing with delayed writepages delivered by
+        * pdflush */
+       if (code == 0) 
+           i_size_write(AFSTOV(avc), tsize);
+#endif
        /* if date not explicitly set by this call, set it ourselves, since we
         * changed the data */
        if (!(astat.Mask & AFS_SETMODTIME)) {
            astat.Mask |= AFS_SETMODTIME;
            astat.ClientModTime = osi_Time();
        }
+
        if (code == 0) {
            if (((avc->execsOrWriters <= 0) && (avc->states & CCreating) == 0)
                || (avc->execsOrWriters == 1 && AFS_NFSXLATORREQ(acred))) {
-               code = afs_StoreAllSegments(avc, &treq, AFS_ASYNC);
-               if (!code)
-                   avc->states &= ~CDirty;
+
+               /* Store files now if not disconnected. */
+               /* XXX: AFS_IS_DISCON_RW handled. */
+               if (!AFS_IS_DISCONNECTED) {
+                       code = afs_StoreAllSegments(avc, &treq, AFS_ASYNC);
+                       if (!code)
+                               avc->states &= ~CDirty;
+               }
            }
        } else
            avc->states &= ~CDirty;
@@ -548,20 +579,33 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
        hzero(avc->flushDV);
        osi_FlushText(avc);     /* do this after releasing all locks */
     }
-    if (code == 0) {
-       ObtainSharedLock(&avc->lock, 16);       /* lock entry */
-       code = afs_WriteVCache(avc, &astat, &treq);     /* send request */
-       ReleaseSharedLock(&avc->lock);  /* release lock */
-    }
-    if (code) {
-       ObtainWriteLock(&afs_xcbhash, 487);
-       afs_DequeueCallback(avc);
-       avc->states &= ~CStatd;
-       ReleaseWriteLock(&afs_xcbhash);
-       if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
-           osi_dnlc_purgedp(avc);
-       /* error?  erase any changes we made to vcache entry */
-    }
+    
+    if (!AFS_IS_DISCONNECTED) {
+        if (code == 0) {
+           ObtainSharedLock(&avc->lock, 16);   /* lock entry */
+           code = afs_WriteVCache(avc, &astat, &treq); /* send request */
+           ReleaseSharedLock(&avc->lock);      /* release lock */
+        }
+        if (code) {
+           ObtainWriteLock(&afs_xcbhash, 487);
+           afs_DequeueCallback(avc);
+           avc->states &= ~CStatd;
+           ReleaseWriteLock(&afs_xcbhash);
+           if (avc->fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
+               osi_dnlc_purgedp(avc);
+           /* error?  erase any changes we made to vcache entry */
+        }
+
+#if defined(AFS_DISCON_ENV)
+    } else {
+
+       ObtainSharedLock(&avc->lock, 712);
+       /* Write changes locally. */
+       code = afs_WriteVCacheDiscon(avc, &astat, attrs);
+       ReleaseSharedLock(&avc->lock);
+#endif
+    }          /* if (!AFS_IS_DISCONNECTED) */
+
 #if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
     if (AFS_NFSXLATORREQ(acred)) {
        avc->execsOrWriters--;
@@ -575,6 +619,8 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
 #endif
   done:
     afs_PutFakeStat(&fakestate);
+
+    AFS_DISCON_UNLOCK();
     code = afs_CheckCode(code, &treq, 15);
     return code;
 }