/*
* retrieve object from backend ext fs.
**/
-struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
- struct osd_inode_id *id)
+static struct inode *osd_iget2(struct osd_thread_info *info,
+ struct osd_device *dev, struct osd_inode_id *id,
+ int *err)
{
- int rc;
+ int rc = 0;
struct inode *inode = NULL;
/*
CDEBUG(D_INODE, "unmatched inode: ino = %u, oii_gen = %u, "
"i_generation = %u\n",
id->oii_ino, id->oii_gen, inode->i_generation);
- iput(inode);
- inode = ERR_PTR(-ESTALE);
+ rc = -ESTALE;
} else if (inode->i_nlink == 0) {
/*
* due to parallel readdir and unlink,
* we can have dead inode here.
*/
CDEBUG(D_INODE, "stale inode: ino = %u\n", id->oii_ino);
- iput(inode);
- inode = ERR_PTR(-ESTALE);
+ rc = -ESTALE;
} else if (is_bad_inode(inode)) {
CWARN("%s: bad inode: ino = %u: rc = %d\n",
osd_dev2name(dev), id->oii_ino, -ENOENT);
- iput(inode);
- inode = ERR_PTR(-ENOENT);
+ rc = -ENOENT;
} else if (osd_is_ea_inode(inode)) {
/*
* EA inode is internal ldiskfs object, should don't visible
* on osd
*/
CDEBUG(D_INODE, "EA inode: ino = %u\n", id->oii_ino);
- iput(inode);
- inode = ERR_PTR(-ENOENT);
+ rc = -ENOENT;
} else if ((rc = osd_attach_jinode(inode))) {
- iput(inode);
- inode = ERR_PTR(rc);
+ CDEBUG(D_INODE, "jbd: ino = %u rc = %d\n", id->oii_ino, rc);
} else {
ldiskfs_clear_inode_state(inode, LDISKFS_STATE_LUSTRE_DESTROY);
if (id->oii_gen == OSD_OII_NOGEN)
if (!(inode->i_flags & S_NOCMTIME))
inode->i_flags |= S_NOCMTIME;
}
+
+ *err = rc;
+
+ return inode;
+}
+
+struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
+ struct osd_inode_id *id)
+{
+ struct inode *inode;
+ int rc = 0;
+
+ inode = osd_iget2(info, dev, id, &rc);
+
+ if (rc) {
+ iput(inode);
+ inode = ERR_PTR(rc);
+ }
+
return inode;
}
*/
again:
- inode = osd_iget(info, dev, id);
- if (IS_ERR(inode)) {
- rc = PTR_ERR(inode);
+ inode = osd_iget2(info, dev, id, &rc);
+ if (rc) {
if (!trusted && (rc == -ENOENT || rc == -ESTALE))
goto check_oi;
break;
}
} else if (osd_id_eq(lid, lid2)) {
- if (converted)
- sf->sf_items_updated++;
+ /*
+ * OI records from request and current are the same
+ * checking inode generation at osd_iget()
+ */
+ if (!inode) {
+ inode = osd_iget(info, dev, lid);
+ if (IS_ERR(inode))
+ ops = DTO_INDEX_DELETE;
+ }
- GOTO(out, rc = 0);
+ if (converted && !IS_ERR(inode)) {
+ sf->sf_items_updated++;
+ GOTO(out, rc = 0);
+ }
} else {
if (!scrub->os_partial_scan) {
spin_lock(&scrub->os_lock);
} else if (oii) {
/* release fixed inconsistent item */
CDEBUG(D_LFSCK,
- "%s: inconsistent OI "DFID" -> %u/%u fixed\n",
+ "%s: inconsistent OI "DFID" -> %u/%u %s\n",
osd_dev2name(dev), PFID(fid), lid->oii_ino,
- lid->oii_gen);
+ lid->oii_gen, ops == DTO_INDEX_DELETE ?
+ "deleted" : "fixed");
spin_lock(&scrub->os_lock);
list_del_init(&oii->oii_list);
spin_unlock(&scrub->os_lock);
}
run_test 20 "Don't trigger OI scrub for irreparable oi repeatedly"
+test_21() {
+ [ $MDSCOUNT -lt 2 ] && skip "needs >= 2 MDTs"
+ [ "$mds1_FSTYPE" != "ldiskfs" ] && skip_env "ldiskfs only test"
+
+ local timeout
+ local td=$TMP/$tdir
+ local device=$(mdsdevname 1)
+
+ echo $device
+
+ timeout=$(do_facet mds2 "$LCTL get_param -n \
+ mdt.$FSNAME-MDT0001.recovery_time_hard")
+ for idx in $(seq $MDSCOUNT); do
+ stop mds${idx}
+ done
+
+ #test reproduce simple situation, when OI record exist
+ #and inode was reused/wrong. Scrub should handle it.
+ do_facet mds1 "mkdir -p $td && mount -t ldiskfs $device $td &&
+ rm -rf $td/update_log_dir/*; umount $td; rm -rf $td"
+
+ for idx in $(seq $MDSCOUNT); do
+ start mds${idx} $(mdsdevname $idx) $MDS_MOUNT_OPTS ||
+ error "mount mds$idx failed"
+ done
+
+ wait_recovery_complete mds2 $((timeout + TIMEOUT))
+
+}
+run_test 21 "don't hang MDS recovery when failed to get update log"
+
+
# restore MDS/OST size
MDSSIZE=${SAVED_MDSSIZE}
OSTSIZE=${SAVED_OSTSIZE}