From: Alex Zhuravlev Date: Wed, 15 Apr 2020 14:54:07 +0000 (+0300) Subject: LU-13453 osd-ldiskfs: do not leak inode if OI insertion fails X-Git-Tag: 2.14.51~176 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=e45e8a92a2ecab742b3680716a55aaa1d9827057;p=fs%2Flustre-release.git LU-13453 osd-ldiskfs: do not leak inode if OI insertion fails osd_create() should destroy just created inode if OI insertion fails. also fixes lustre_index_restore() to drop nlink for object to be removed. the patch adds two tests: - ENOSPC on OI insertion - ENOSPC on .. insertion, i.e. directory block allocation Signed-off-by: Alex Zhuravlev Change-Id: I2a5db657c7dab54b8dc2c50bc29365d5ee754a2e Reviewed-on: https://review.whamcloud.com/38235 Reviewed-by: Andreas Dilger Reviewed-by: Mike Pershin Tested-by: jenkins Tested-by: Maloo --- diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h index 7160e54..c79a62b 100644 --- a/lustre/include/obd_support.h +++ b/lustre/include/obd_support.h @@ -276,6 +276,8 @@ extern char obd_jobid_var[]; #define OBD_FAIL_OSD_TXN_START 0x19a #define OBD_FAIL_OSD_DUPLICATE_MAP 0x19b #define OBD_FAIL_OSD_REF_DEL 0x19c +#define OBD_FAIL_OSD_OI_ENOSPC 0x19d +#define OBD_FAIL_OSD_DOTDOT_ENOSPC 0x19e #define OBD_FAIL_OFD_SET_OID 0x1e0 diff --git a/lustre/obdclass/scrub.c b/lustre/obdclass/scrub.c index c9852a6..adcffa9 100644 --- a/lustre/obdclass/scrub.c +++ b/lustre/obdclass/scrub.c @@ -1062,6 +1062,10 @@ int lustre_index_restore(const struct lu_env *env, struct dt_device *dev, if (rc) GOTO(stop, rc); + rc = dt_declare_ref_del(env, tgt_obj, th); + if (rc) + GOTO(stop, rc); + rc = dt_declare_destroy(env, tgt_obj, th); if (rc) GOTO(stop, rc); @@ -1075,7 +1079,12 @@ int lustre_index_restore(const struct lu_env *env, struct dt_device *dev, GOTO(stop, rc); dt_write_lock(env, tgt_obj, 0); - rc = dt_destroy(env, tgt_obj, th); + rc = dt_ref_del(env, tgt_obj, th); + if (rc == 0) { + if (S_ISDIR(tgt_obj->do_lu.lo_header->loh_attr)) + dt_ref_del(env, tgt_obj, th); + rc = dt_destroy(env, tgt_obj, th); + } dt_write_unlock(env, tgt_obj); dt_trans_stop(env, dev, th); if (rc) diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index 9a18ea8..e384806 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -3535,6 +3535,9 @@ static int __osd_oi_insert(const struct lu_env *env, struct osd_object *obj, LASSERT(obj->oo_inode != NULL); + if (CFS_FAIL_CHECK(OBD_FAIL_OSD_OI_ENOSPC)) + return -ENOSPC; + oh = container_of(th, struct osd_thandle, ot_super); LASSERT(oh->ot_handle); osd_trans_exec_op(env, th, OSD_OT_INSERT); @@ -3893,6 +3896,9 @@ static int osd_add_dot_dotdot_internal(struct osd_thread_info *info, __u32 saved_nlink = dir->i_nlink; int rc; + if (OBD_FAIL_CHECK(OBD_FAIL_OSD_DOTDOT_ENOSPC)) + return -ENOSPC; + dot_dot_ldp = (struct ldiskfs_dentry_param *)info->oti_ldp2; osd_get_ldiskfs_dirent_param(dot_dot_ldp, dot_dot_fid); @@ -4141,8 +4147,21 @@ static int osd_create(const struct lu_env *env, struct dt_object *dt, obj->oo_dt.do_body_ops = &osd_body_ops; } - if (!result && !CFS_FAIL_CHECK(OBD_FAIL_OSD_NO_OI_ENTRY)) + if (!result && !CFS_FAIL_CHECK(OBD_FAIL_OSD_NO_OI_ENTRY)) { + struct inode *inode = obj->oo_inode; + result = __osd_oi_insert(env, obj, fid, th); + if (result && inode) { + spin_lock(&obj->oo_guard); + clear_nlink(inode); + spin_unlock(&obj->oo_guard); + osd_dirty_inode(inode, I_DIRTY_DATASYNC); + ldiskfs_set_inode_state(inode, + LDISKFS_STATE_LUSTRE_DESTROY); + iput(inode); + obj->oo_inode = NULL; + } + } /* * a small optimization - dt_insert() isn't usually applied diff --git a/lustre/tests/sanity-scrub.sh b/lustre/tests/sanity-scrub.sh index 8c12490..97d3e36 100644 --- a/lustre/tests/sanity-scrub.sh +++ b/lustre/tests/sanity-scrub.sh @@ -1272,6 +1272,37 @@ test_16() { } run_test 16 "Initial OI scrub can rebuild crashed index objects" +test_17a() { + [ "$mds1_FSTYPE" != "ldiskfs" ] && skip_env "ldiskfs only test" + +#define OBD_FAIL_OSD_OI_ENOSPC 0x19d + do_facet mds1 $LCTL set_param fail_loc=0x8000019d + mkdir $DIR/$tdir && error "mkdir should fail" + stop mds1 + local devname=$(mdsdevname 1) + + stack_trap "start mds1 $devname $MDS_MOUNT_OPTS" EXIT + FSCK_MAX_ERR=0 run_e2fsck $(facet_active_host mds1) $devname -n || + error "e2fsck returned $?" +} +run_test 17a "ENOSPC on OI insert shouldn't leak inodes" + +test_17b() { + [ "$mds1_FSTYPE" != "ldiskfs" ] && skip_env "ldiskfs only test" + +#define OBD_FAIL_OSD_DOTDOT_ENOSPC 0x19e + do_facet mds1 $LCTL set_param fail_loc=0x8000019e + mkdir $DIR/$tdir && error "mkdir should fail" + stop mds1 + local devname=$(mdsdevname 1) + + stack_trap "start mds1 $devname $MDS_MOUNT_OPTS" EXIT + FSCK_MAX_ERR=0 run_e2fsck $(facet_active_host mds1) $devname -n || + error "e2fsck returned $?" +} +run_test 17b "ENOSPC on .. insertion shouldn't leak inodes" + + # restore MDS/OST size MDSSIZE=${SAVED_MDSSIZE} OSTSIZE=${SAVED_OSTSIZE}