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:
*
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));
}
if (sf->sf_flags & SF_INCONSISTENT)
- verify = 1;
+ verify = true;
/*
* Objects are created as locking anchors or place holders for objects
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) {
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);
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);
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);
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,
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)) {
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) {
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)