Whamcloud - gitweb
LU-1042 obdfilter: initialize new object timestamp
authorAndreas Dilger <adilger@whamcloud.com>
Fri, 27 Jan 2012 21:12:06 +0000 (14:12 -0700)
committerOleg Drokin <green@whamcloud.com>
Wed, 15 Feb 2012 16:35:28 +0000 (11:35 -0500)
Initialize newly-created objects with a/m/ctime = 0, so that however
clients modify the timestamp it will be updated the first time.  The
fsfilt_ext3_setattr() code will special case ctime = 0 for new files
and reset them to the ext4 s_mkfs_time stored in the superblock.

In LU-221 (commit 414251797ed178eec5d431e1f5aa4a889d2b159f) the
timestamps were initialized to (INT_MIN + 24 * 3600) (1901-12-14),
but the use of unsigned on-disk timestamps caused these negative
numbers to be transformed into large positive numbers (debugfs
reports them to be "Tue Jan 19 20:14:08 2038").  Add a fix so that
files with this exact timestamp have the timestamp reset to 0.

Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Change-Id: I22f2cd443402c0c524bafaf37c80cad7b6d00c1e
Reviewed-on: http://review.whamcloud.com/2036
Reviewed-by: Johann Lombardi <johann@whamcloud.com>
Tested-by: Hudson
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/lustre_fsfilt.h
lustre/lvfs/fsfilt_ext3.c
lustre/obdfilter/filter.c

index 48b2bc0..ea7af30 100644 (file)
@@ -51,4 +51,6 @@
 #error Unsupported operating system.
 #endif
 
+#define LU221_BAD_TIME (0x80000000U + 24 * 3600)
+
 #endif
index 30eed7c..5fbed73 100644 (file)
@@ -581,6 +581,41 @@ static int fsfilt_ext3_setattr(struct dentry *dentry, void *handle,
         struct inode *inode = dentry->d_inode;
         int rc = 0;
 
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2,7,50,0)
+        /* Try to correct for a bug in 2.1.0 (LU-221) that caused negative
+         * timestamps to appear to be in the far future, due old timestamp
+         * being stored on disk as an unsigned value.  This fixes up any
+         * bad values held by the client before storing them on disk,
+         * and ensures any timestamp updates are correct.  LU-1042 */
+        if (unlikely(LTIME_S(inode->i_atime) == LU221_BAD_TIME &&
+                     !(iattr->ia_valid & ATTR_ATIME))) {
+                iattr->ia_valid |= ATTR_ATIME;
+                LTIME_S(iattr->ia_atime) = 0;
+        }
+        if (unlikely(LTIME_S(inode->i_mtime) == LU221_BAD_TIME &&
+                     !(iattr->ia_valid & ATTR_MTIME))) {
+                iattr->ia_valid |= ATTR_MTIME;
+                LTIME_S(iattr->ia_mtime) = 0;
+        }
+        if (unlikely((LTIME_S(inode->i_ctime) == LU221_BAD_TIME ||
+                      LTIME_S(inode->i_ctime) == 0) &&
+                     !(iattr->ia_valid & ATTR_CTIME))) {
+                iattr->ia_valid |= ATTR_CTIME;
+                LTIME_S(iattr->ia_ctime) = 0;
+        }
+#else
+#warning "remove old LU-221/LU-1042 workaround code"
+#endif
+
+        /* When initializating timestamps for new inodes, use the filesystem
+         * mkfs time for ctime to avoid e2fsck ibadness incorrectly thinking
+         * that this is potentially an invalid inode.  Files with an old ctime
+         * migrated to a newly-formatted OST with a newer s_mkfs_time will not
+         * hit this check, since it is only for ctime == 0.  LU-1010/LU-1042 */
+        if ((iattr->ia_valid & ATTR_CTIME) && LTIME_S(iattr->ia_ctime) == 0)
+                LTIME_S(iattr->ia_ctime) =
+                        EXT4_SB(inode->i_sb)->s_es->s_mkfs_time;
+
         /* Avoid marking the inode dirty on the superblock list unnecessarily.
          * We are already writing the inode to disk as part of this
          * transaction and want to avoid a lot of extra inode writeout
index f61d613..afbab0b 100644 (file)
@@ -3136,6 +3136,22 @@ struct dentry *__filter_oa2dentry(struct obd_device *obd, struct ost_id *ostid,
                 RETURN(ERR_PTR(-ENOENT));
         }
 
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2,7,50,0)
+        /* Try to correct for a bug in 2.1.0 (LU-221) that caused negative
+         * timestamps to appear to be in the far future, due old timestamp
+         * being stored on disk as an unsigned value.  This fixes up any
+         * bad values stored on disk before returning them to the client,
+         * and ensures any timestamp updates are correct.  LU-1042 */
+        if (unlikely(LTIME_S(dchild->d_inode->i_atime) == LU221_BAD_TIME))
+                LTIME_S(dchild->d_inode->i_atime) = 0;
+        if (unlikely(LTIME_S(dchild->d_inode->i_mtime) == LU221_BAD_TIME))
+                LTIME_S(dchild->d_inode->i_mtime) = 0;
+        if (unlikely(LTIME_S(dchild->d_inode->i_ctime) == LU221_BAD_TIME))
+                LTIME_S(dchild->d_inode->i_ctime) = 0;
+#else
+#warning "remove old LU-221/LU-1042 workaround code"
+#endif
+
         return dchild;
 }
 
@@ -3942,23 +3958,23 @@ static int filter_precreate(struct obd_device *obd, struct obdo *oa,
                 rc = ll_vfs_create(dparent->d_inode, dchild,
                                    S_IFREG |  S_ISUID | S_ISGID | 0666, NULL);
                 if (rc) {
-                        CERROR("create failed rc = %d\n", rc);
+                        CWARN("%s: create failed: rc = %d\n", obd->obd_name,rc);
                         if (rc == -ENOSPC) {
                                 os_ffree = filter_calc_free_inodes(obd);
-                                if (os_ffree == -1) 
+                                if (os_ffree == -1)
                                         GOTO(cleanup, rc);
 
                                 if (obd->obd_osfs.os_bavail <
                                     (obd->obd_osfs.os_blocks >> 10)) {
-                                        if (oa->o_valid & OBD_MD_FLFLAGS)
+                                        if (oa->o_valid & OBD_MD_FLFLAGS) {
                                                 oa->o_flags |= OBD_FL_NOSPC_BLK;
-                                        else {
+                                        else {
                                                 oa->o_valid |= OBD_MD_FLFLAGS;
                                                 oa->o_flags = OBD_FL_NOSPC_BLK;
                                         }
 
-                                        CERROR("%s: free inode "LPU64"\n",
-                                               obd->obd_name, os_ffree);
+                                        CWARN("%s: free inode "LPU64"\n",
+                                              obd->obd_name, os_ffree);
                                 }
                         }
                         GOTO(cleanup, rc);
@@ -3969,25 +3985,27 @@ static int filter_precreate(struct obd_device *obd, struct obdo *oa,
                                        dchild->d_inode->i_ino);
 
 set_last_id:
-                /* Set a/c/m time to a insane large negative value at creation
-                 * time so that any timestamp arriving from the client will
-                 * always be newer and update the inode.
-                 * See LU-221 for details */
+                /* Initialize a/c/m time so any client timestamp will always
+                 * be newer and update the inode. ctime = 0 is also handled
+                 * specially in fsfilt_ext3_setattr(). See LU-221, LU-1042 */
                 iattr.ia_valid = ATTR_ATIME | ATTR_MTIME | ATTR_CTIME;
-                LTIME_S(iattr.ia_atime) = INT_MIN + 24 * 3600;
-                LTIME_S(iattr.ia_mtime) = INT_MIN + 24 * 3600;
-                LTIME_S(iattr.ia_ctime) = INT_MIN + 24 * 3600;
+                LTIME_S(iattr.ia_atime) = 0;
+                LTIME_S(iattr.ia_mtime) = 0;
+                LTIME_S(iattr.ia_ctime) = 0;
                 err = fsfilt_setattr(obd, dchild, handle, &iattr, 0);
-                if (err)
-                        CERROR("unable to initialize a/c/m time of newly"
-                               "created inode\n");
+                 if (err)
+                        CWARN("%s: unable to initialize a/c/m time of newly "
+                              "created object %.*s: rc = %d\n",
+                              obd->obd_name, dchild->d_name.len,
+                              dchild->d_name.name, err);
 
                 if (!recreate_obj) {
                         filter_set_last_id(filter, next_id, group);
                         err = filter_update_last_objid(obd, group, 0);
                         if (err)
-                                CERROR("unable to write lastobjid "
-                                       "but file created\n");
+                                CERROR("%s: unable to write lastobjid "
+                                       "but file created: rc = %d\n",
+                                       obd->obd_name, err);
                 }
 
         cleanup: