linux-truncate-race-20090109
authorSimon Wilkinson <sxw@inf.ed.ac.uk>
Fri, 9 Jan 2009 15:09:14 +0000 (15:09 +0000)
committerDerrick Brashear <shadow@dementia.org>
Fri, 9 Jan 2009 15:09:14 +0000 (15:09 +0000)
LICENSE IPL10
FIXES 124094

avoid a race during truncation which trips an issue when fsx is run

acinclude.m4
src/afs/LINUX/osi_file.c
src/afs/LINUX/osi_vfs.hin
src/afs/LINUX/osi_vfsops.c
src/afs/LINUX/osi_vnodeops.c
src/afs/VNOPS/afs_vnop_attrs.c
src/cf/linux-test4.m4

index 7b3e659..6ee19bf 100644 (file)
@@ -905,6 +905,7 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*)
                 LINUX_REGISTER_SYSCTL_TABLE_NOFLAG
                 LINUX_SYSCTL_TABLE_CHECKING
                 LINUX_HAVE_IGET
+                LINUX_HAVE_I_SIZE_READ
                 LINUX_FS_STRUCT_NAMEIDATA_HAS_PATH
                 LINUX_EXPORTS_INIT_MM
                  LINUX_EXPORTS_SYS_CHDIR
index 31194f6..f138981 100644 (file)
@@ -95,7 +95,7 @@ osi_UFSOpen(afs_int32 ainode)
        osi_Panic("Can't open inode %d\n", ainode);
 #endif
     afile->filp = filp;
-    afile->size = FILE_INODE(filp)->i_size;
+    afile->size = i_size_read(FILE_INODE(filp)->i_size);
     AFS_GLOCK();
     afile->offset = 0;
     afile->proc = (int (*)())0;
@@ -150,7 +150,7 @@ osi_UFSOpen(afs_int32 ainode)
        code = filp->f_op->open(tip, filp);
     if (code)
        osi_Panic("Can't open inode %d\n", ainode);
-    afile->size = tip->i_size;
+    afile->size = i_size_read(tip);
     AFS_GLOCK();
     afile->offset = 0;
     afile->proc = (int (*)())0;
@@ -182,7 +182,7 @@ afs_osi_Stat(register struct osi_file *afile, register struct osi_stat *astat)
     register afs_int32 code;
     AFS_STATCNT(osi_Stat);
     MObtainWriteLock(&afs_xosi, 320);
-    astat->size = OSIFILE_INODE(afile)->i_size;
+    astat->size = i_size_read(OSIFILE_INODE(afile));
 #if defined(AFS_LINUX26_ENV)
     astat->mtime = OSIFILE_INODE(afile)->i_mtime.tv_sec;
     astat->atime = OSIFILE_INODE(afile)->i_atime.tv_sec;
@@ -272,7 +272,7 @@ osi_UFSTruncate(register struct osi_file *afile, afs_int32 asize)
     if (!code)
        truncate_inode_pages(&inode->i_data, asize);
 #else
-    inode->i_size = asize;
+    i_size_write(inode, asize);
     if (inode->i_sb->s_op && inode->i_sb->s_op->notify_change) {
        code = inode->i_sb->s_op->notify_change(&afile->dentry, &newattrs);
     }
index b94a2ca..bd6de53 100644 (file)
@@ -78,4 +78,9 @@ typedef struct vattr {
 
 #define VATTR_NULL(A) memset(A, 0, sizeof(struct vattr))
 
+#ifndef HAVE_LINUX_I_SIZE_READ
+#define i_size_read(X) ((X)->i_size)
+#define i_size_write(X,Y) (X)->i_size = Y
+#endif
+
 #endif /* OSI_VFS_H_ */
index 5cf5d55..4b609e0 100644 (file)
@@ -544,7 +544,7 @@ vattr2inode(struct inode *ip, struct vattr *vp)
     ip->i_mode = vp->va_mode;
     ip->i_uid = vp->va_uid;
     ip->i_gid = vp->va_gid;
-    ip->i_size = vp->va_size;
+    i_size_write(ip, vp->va_size);
 #if defined(AFS_LINUX26_ENV)
     ip->i_atime.tv_sec = vp->va_atime.tv_sec;
     ip->i_atime.tv_nsec = 0;
index 70f7098..c8f7a5e 100644 (file)
@@ -1918,7 +1918,7 @@ afs_linux_writepage_sync(struct inode *ip, struct page *pp,
 
     code = afs_write(vcp, &tuio, f_flags, credp, 0);
 
-    ip->i_size = vcp->m.Length;
+    i_size_write(ip, vcp->m.Length);
     ip->i_blocks = ((vcp->m.Length + 1023) >> 10) << 1;
 
     if (!code) {
@@ -1972,13 +1972,13 @@ afs_linux_writepage(struct page *pp)
 #endif
 
     inode = (struct inode *)mapping->host;
-    end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+    end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
 
     /* easy case */
     if (pp->index < end_index)
        goto do_it;
     /* things got complicated... */
-    offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
+    offset = i_size_read(inode) & (PAGE_CACHE_SIZE - 1);
     /* OK, are we completely out? */
     if (pp->index >= end_index + 1 || !offset)
        return -EIO;
@@ -2021,7 +2021,7 @@ afs_linux_updatepage(struct file *fp, struct page *pp, unsigned long offset,
 
     code = afs_write(vcp, &tuio, fp->f_flags, credp, 0);
 
-    ip->i_size = vcp->m.Length;
+    i_size_write(ip, vcp->m.Length);
     ip->i_blocks = ((vcp->m.Length + 1023) >> 10) << 1;
 
     if (!code) {
index 36606aa..58b9a00 100644 (file)
@@ -546,6 +546,13 @@ afs_setattr(OSI_VC_DECL(avc), register struct vattr *attrs,
        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)) {
index 6b24ce5..180083a 100644 (file)
@@ -825,6 +825,22 @@ AC_DEFUN([LINUX_GENERIC_FILE_AIO_READ], [
     AC_DEFINE([GENERIC_FILE_AIO_READ], 1, [define if your kernel has generic_file_aio_read()])
   fi])
 
+AC_DEFUN([LINUX_HAVE_I_SIZE_READ], [
+  AC_MSG_CHECKING([for linux i_size_read()])
+  AC_CACHE_VAL([ac_cv_linux_i_size_read], [
+    save_CPPFLAGS="$CPPFLAGS"
+    CPPFLAGS="$CPPFLAGS -Werror-implicit-function-declaration"
+    AC_TRY_KBUILD(
+[#include <linux/fs.h>],
+[i_size_read(NULL);],
+      ac_cv_linux_i_size_read=yes,
+      ac_cv_linux_i_size_read=no)
+    CPPFLAGS="$save_CPPFLAGS"])
+  AC_MSG_RESULT($ac_cv_linux_i_size_read)
+  if test "x$ac_cv_linux_i_size_read" = "xyes"; then
+    AC_DEFINE([HAVE_LINUX_I_SIZE_READ], 1, [define if your kernel has i_size_read()])
+  fi])
+
 AC_DEFUN([LINUX_FREEZER_H_EXISTS], [
   AC_MSG_CHECKING([for linux/freezer.h existance])
   AC_CACHE_VAL([ac_cv_linux_freezer_h_exists], [