Whamcloud - gitweb
LU-3420 scrub: trigger OI scrub properly 15/6515/4
authorFan Yong <fan.yong@intel.com>
Fri, 24 May 2013 05:59:16 +0000 (13:59 +0800)
committerOleg Drokin <oleg.drokin@intel.com>
Thu, 27 Jun 2013 02:53:46 +0000 (02:53 +0000)
In osd_fid_lookup(), if the iget() cannot locate the backend inode
(return -ENOENT or -ESTALE) with the found ino#/gen in the OI file,
there may be three cases:

1) MDT file-level backup/restore caused the OI invalid.
2) Someone unlinked the object but NOT removed the OI mapping, such
   as mount target device as ldiskfs, and modify something directly.
3) Someone just removed the object between the osd_oi_lookup() and
   the iget(). It is normal.

Under such case we can lookup OI again to check whether related OI
mapping is still there or not. If not, it is 3rd case. Otherwise,
it is diffcult to distinguish the 2nd from the 1st case. Relatively
speaking, the 1st case is more common than the 2nd case, so trigger
OI scrub without further distinguish.

To reduce the 2nd case, the initial OI scrub will scan the local
objects set to remove those stale OI mappings, such as the entry
for "CATALOGS" after file-level backup/restore.

Another update is about mapping FID to inode for the object with
remote name entry. For example, dir1's name entry resides on the
MDT0. Its object resides on the MDT1. On the MDT1, do file-level
backup/resotre. And before the OI scrub finishing to rebuilt the
OI files on the MDT1, MDT0 send RPC to MDT1 to access dir1's obj
with dir1's FID. On the MDT1, the OI mapping for FID1 is invalid
yet. Under such case, we have two possible solutions:

a) The MDT1 returns -EINPROGRESS to the MDT0, and the MDT0 retry
   such RPC sometime later.

b) On the MDT1, There is the directory "/REMOTE_PARENT_DIR" hold
   all the objects which have remote name entries on other MDTs.
   The object name under the "/REMOTE_PARENT_DIR" is FID string.
   So when get invalid OI mapping, OSD can localte the inode via
   lookup the "/REMOTE_PARENT_DIR" with the given FID.

Compared the two solutions, a) will cause the MDT0 busy wait until
related OI mapping rebuilt. b) is relative better. And bacause the
MDT file-level backup/restore is rare case, it will not affect the
normal cases for FID to inode mapping.

In fact, from the OSD view, it does not know whether the object for
the given FID is referenced by some remote name entry or not, and
especially for DNE II, a multiple-linked object may have many name
entries reside on many MDTs.

To simplify the operation, OSD will not distinguish more, it just
lookup the "/REMOTE_PARENT_DIR". Usually, it only happened for the
RPC from other MDT during the OI scrub, or for the client side RPC
with FID only, such as FID to path, or from old connected client.

Test-Parameters: testlist=sanity-scrub
Signed-off-by: Fan Yong <fan.yong@intel.com>
Change-Id: I503bd1e2d5d5eb3976a46c385ae041d11d3b9c32
Reviewed-on: http://review.whamcloud.com/6515
Tested-by: Hudson
Reviewed-by: Alex Zhuravlev <alexey.zhuravlev@intel.com>
Reviewed-by: wangdi <di.wang@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Tested-by: Maloo <whamcloud.maloo@gmail.com>
lustre/osd-ldiskfs/osd_compat.c
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-ldiskfs/osd_internal.h
lustre/osd-ldiskfs/osd_scrub.c

index a38e057..2505868 100644 (file)
@@ -319,6 +319,39 @@ int osd_delete_from_remote_parent(const struct lu_env *env,
        RETURN(rc);
 }
 
+int osd_lookup_in_remote_parent(struct osd_thread_info *oti,
+                               struct osd_device *osd,
+                               const struct lu_fid *fid,
+                               struct osd_inode_id *id)
+{
+       struct osd_mdobj_map        *omm = osd->od_mdt_map;
+       char                        *name = oti->oti_name;
+       struct dentry               *parent;
+       struct dentry               *dentry;
+       struct ldiskfs_dir_entry_2 *de;
+       struct buffer_head         *bh;
+       int                         rc;
+       ENTRY;
+
+       parent = omm->omm_remote_parent;
+       sprintf(name, DFID_NOBRACE, PFID(fid));
+       dentry = osd_child_dentry_by_inode(oti->oti_env, parent->d_inode,
+                                          name, strlen(name));
+       mutex_lock(&parent->d_inode->i_mutex);
+       bh = osd_ldiskfs_find_entry(parent->d_inode, dentry, &de, NULL);
+       if (bh == NULL) {
+               rc = -ENOENT;
+       } else {
+               rc = 0;
+               osd_id_gen(id, le32_to_cpu(de->inode), OSD_OII_NOGEN);
+               brelse(bh);
+       }
+       mutex_unlock(&parent->d_inode->i_mutex);
+       if (rc == 0)
+               osd_add_oi_cache(oti, osd, id, fid);
+       RETURN(rc);
+}
+
 /*
  * directory structure on legacy OST:
  *
index 9943631..af533f9 100644 (file)
@@ -324,7 +324,10 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
        struct osd_scrub       *scrub;
        struct scrub_file      *sf;
        int                     result;
-       int                     verify = 0;
+       int                     saved  = 0;
+       bool                    verify = false;
+       bool                    in_oi  = false;
+       bool                    triggered = false;
        ENTRY;
 
        LINVRNT(osd_invariant(obj));
@@ -356,7 +359,7 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
        }
 
        if (sf->sf_flags & SF_INCONSISTENT)
-               verify = 1;
+               verify = true;
 
        /*
         * Objects are created as locking anchors or place holders for objects
@@ -382,19 +385,47 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
        if (result != 0)
                GOTO(out, result);
 
+       in_oi = true;
+
 iget:
-       if (verify == 0)
+       if (!verify)
                inode = osd_iget(info, dev, id);
        else
                inode = osd_iget_verify(info, dev, id, fid);
        if (IS_ERR(inode)) {
                result = PTR_ERR(inode);
                if (result == -ENOENT || result == -ESTALE) {
-                       fid_zero(&oic->oic_fid);
-                       result = 0;
+                       if (!in_oi) {
+                               fid_zero(&oic->oic_fid);
+                               GOTO(out, result = 0);
+                       }
+
+                       /* XXX: There are three possible cases:
+                        *      1. Backup/restore caused the OI invalid.
+                        *      2. Someone unlinked the object but NOT removed
+                        *         the OI mapping, such as mount target device
+                        *         as ldiskfs, and modify something directly.
+                        *      3. Someone just removed the object between the
+                        *         former oi_lookup and the iget. It is normal.
+                        *
+                        *      It is diffcult to distinguish the 2nd from the
+                        *      1st case. Relatively speaking, the 1st case is
+                        *      common than the 2nd case, trigger OI scrub. */
+                       result = osd_oi_lookup(info, dev, fid, id, true);
+                       if (result == 0)
+                               /* It is the case 1 or 2. */
+                               goto trigger;
+
+                       if (result == -ENOENT)
+                               /* It is the case 3. */
+                               result = 0;
                } else if (result == -EREMCHG) {
 
 trigger:
+                       if (unlikely(triggered))
+                               GOTO(out, result = saved);
+
+                       triggered = true;
                        if (thread_is_running(&scrub->os_thread)) {
                                result = -EINPROGRESS;
                        } else if (!dev->od_noscrub) {
@@ -408,6 +439,32 @@ trigger:
                                else
                                        result = -EREMCHG;
                        }
+
+                       /* We still have chance to get the valid inode: for the
+                        * object which is referenced by remote name entry, the
+                        * object on the local MDT will be linked under the dir
+                        * of "/REMOTE_PARENT_DIR" with its FID string as name.
+                        *
+                        * We do not know whether the object for the given FID
+                        * is referenced by some remote name entry or not, and
+                        * especially for DNE II, a multiple-linked object may
+                        * have many name entries reside on many MDTs.
+                        *
+                        * To simplify the operation, OSD will not distinguish
+                        * more, just lookup "/REMOTE_PARENT_DIR". Usually, it
+                        * only happened for the RPC from other MDT during the
+                        * OI scrub, or for the client side RPC with FID only,
+                        * such as FID to path, or from old connected client. */
+                       saved = result;
+                       result = osd_lookup_in_remote_parent(info, dev,
+                                                            fid, id);
+                       if (result == 0) {
+                               in_oi = false;
+                               verify = false;
+                               goto iget;
+                       }
+
+                       result = saved;
                }
 
                 GOTO(out, result);
@@ -3788,10 +3845,8 @@ static int osd_fail_fid_lookup(struct osd_thread_info *oti,
        return rc;
 }
 
-static int osd_add_oi_cache(struct osd_thread_info *info,
-                           struct osd_device *osd,
-                           struct osd_inode_id *id,
-                           struct lu_fid *fid)
+int osd_add_oi_cache(struct osd_thread_info *info, struct osd_device *osd,
+                    struct osd_inode_id *id, const struct lu_fid *fid)
 {
        CDEBUG(D_INODE, "add "DFID" %u:%u to info %p\n", PFID(fid),
               id->oii_ino, id->oii_gen, info);
index 2062ccb..2ee8cc5 100644 (file)
@@ -628,6 +628,8 @@ int osd_ea_fid_set(struct osd_thread_info *info, struct inode *inode,
                   const struct lu_fid *fid, __u64 flags);
 int osd_get_lma(struct osd_thread_info *info, struct inode *inode,
                struct dentry *dentry, struct lustre_mdt_attrs *lma);
+int osd_add_oi_cache(struct osd_thread_info *info, struct osd_device *osd,
+                    struct osd_inode_id *id, const struct lu_fid *fid);
 
 int osd_obj_map_init(const struct lu_env *env, struct osd_device *osd);
 void osd_obj_map_fini(struct osd_device *dev);
@@ -665,6 +667,10 @@ int osd_delete_from_remote_parent(const struct lu_env *env,
                                  struct osd_thandle *oh);
 int osd_add_to_remote_parent(const struct lu_env *env, struct osd_device *osd,
                             struct osd_object *obj, struct osd_thandle *oh);
+int osd_lookup_in_remote_parent(struct osd_thread_info *oti,
+                               struct osd_device *osd,
+                               const struct lu_fid *fid,
+                               struct osd_inode_id *id);
 
 /* osd_quota_fmt.c */
 int walk_tree_dqentry(const struct lu_env *env, struct osd_object *obj,
index a6248e4..e312378 100644 (file)
@@ -100,7 +100,8 @@ static int osd_scrub_refresh_mapping(struct osd_thread_info *info,
        ENTRY;
 
        fid_cpu_to_be(oi_fid, fid);
-       osd_id_pack(oi_id, id);
+       if (id != NULL)
+               osd_id_pack(oi_id, id);
        jh = ldiskfs_journal_start_sb(osd_sb(dev),
                                      osd_dto_credits_noquota[ops]);
        if (IS_ERR(jh)) {
@@ -1521,11 +1522,12 @@ osd_ios_OBJECTS_scan(struct osd_thread_info *info, struct osd_device *dev,
 static int osd_initial_OI_scrub(struct osd_thread_info *info,
                                struct osd_device *dev)
 {
-       struct osd_ios_item *item    = NULL;
-       scandir_t            scandir = osd_ios_general_scan;
-       filldir_t            filldir = osd_ios_root_fill;
-       struct dentry       *dentry  = osd_sb(dev)->s_root;
-       int                  rc;
+       struct osd_ios_item     *item    = NULL;
+       scandir_t                scandir = osd_ios_general_scan;
+       filldir_t                filldir = osd_ios_root_fill;
+       struct dentry           *dentry  = osd_sb(dev)->s_root;
+       const struct osd_lf_map *map     = osd_lf_maps;
+       int                      rc;
        ENTRY;
 
        while (1) {
@@ -1559,7 +1561,32 @@ static int osd_initial_OI_scrub(struct osd_thread_info *info,
                OBD_FREE_PTR(item);
        }
 
-       RETURN(rc);
+       if (rc != 0)
+               RETURN(rc);
+
+       /* There maybe the case that the object has been removed, but its OI
+        * mapping is still in the OI file, such as the "CATALOGS" after MDT
+        * file-level backup/restore. So here cleanup the stale OI mappings. */
+       while (map->olm_name != NULL) {
+               struct dentry *child;
+
+               if (fid_is_zero(&map->olm_fid)) {
+                       map++;
+                       continue;
+               }
+
+               child = osd_ios_lookup_one_len(map->olm_name,
+                                              osd_sb(dev)->s_root,
+                                              strlen(map->olm_name));
+               if (!IS_ERR(child))
+                       dput(child);
+               else if (PTR_ERR(child) == -ENOENT)
+                       osd_scrub_refresh_mapping(info, dev, &map->olm_fid,
+                                                 NULL, DTO_INDEX_DELETE);
+               map++;
+       }
+
+       RETURN(0);
 }
 
 char *osd_lf_fid2name(const struct lu_fid *fid)