From: Andrew Perepechko Date: Sat, 26 Mar 2016 14:48:25 +0000 (+0300) Subject: LU-7925 llite: avoid clearing i_nlink for inodes in use X-Git-Tag: 2.8.52~9 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=e6b7abc567ee0a8085e440c91e102d4318575529 LU-7925 llite: avoid clearing i_nlink for inodes in use The patch removes find_cbdata callbacks and clear_nlink from dentry_iput path, since this piece of code makes a few races possible. The test case reproduces one of the possible races described in LU-7925: 1) two hard links are created for the same file 2) the test calls stat(2) for link #1 3) in the middle of 2) the test opens and closes link #2 4) in the middle of 2) the test drops the ldlm locks and forces dentry reclaim via vm.drop_caches=2 5) in the middle of 2) ll_d_iput() clears i_nlink for the inode 6) the initial stat(2) continues and copies the wrong i_nlink value into st_nlink Signed-off-by: Andrew Perepechko Seagate-bug-id: MRP-3271 Change-Id: I185bed4b875a4fbf66df835cf9161912a6ade415 Reviewed-on: http://review.whamcloud.com/19164 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Wally Wang Reviewed-by: Lai Siyao Reviewed-by: Oleg Drokin --- diff --git a/lustre/include/cl_object.h b/lustre/include/cl_object.h index 4de3d2e..ba1d5f3 100644 --- a/lustre/include/cl_object.h +++ b/lustre/include/cl_object.h @@ -390,12 +390,6 @@ struct cl_object_operations { int (*coo_getstripe)(const struct lu_env *env, struct cl_object *obj, struct lov_user_md __user *lum); /** - * Find whether there is any callback data (ldlm lock) attached upon - * the object. - */ - int (*coo_find_cbdata)(const struct lu_env *env, struct cl_object *obj, - ldlm_iterator_t iter, void *data); - /** * Get FIEMAP mapping from the object. */ int (*coo_fiemap)(const struct lu_env *env, struct cl_object *obj, @@ -2021,8 +2015,6 @@ int cl_object_prune (const struct lu_env *env, struct cl_object *obj); void cl_object_kill (const struct lu_env *env, struct cl_object *obj); int cl_object_getstripe(const struct lu_env *env, struct cl_object *obj, struct lov_user_md __user *lum); -int cl_object_find_cbdata(const struct lu_env *env, struct cl_object *obj, - ldlm_iterator_t iter, void *data); int cl_object_fiemap(const struct lu_env *env, struct cl_object *obj, struct ll_fiemap_info_key *fmkey, struct fiemap *fiemap, size_t *buflen); diff --git a/lustre/include/obd.h b/lustre/include/obd.h index e94cd49..7ed95ea 100644 --- a/lustre/include/obd.h +++ b/lustre/include/obd.h @@ -1072,9 +1072,6 @@ struct md_ops { int (*m_getstatus)(struct obd_export *, struct lu_fid *); int (*m_null_inode)(struct obd_export *, const struct lu_fid *); - int (*m_find_cbdata)(struct obd_export *, const struct lu_fid *, - ldlm_iterator_t, void *); - int (*m_getattr_name)(struct obd_export *, struct md_op_data *, struct ptlrpc_request **); diff --git a/lustre/include/obd_class.h b/lustre/include/obd_class.h index 9033e79..9e4b99d 100644 --- a/lustre/include/obd_class.h +++ b/lustre/include/obd_class.h @@ -1301,18 +1301,6 @@ static inline int md_null_inode(struct obd_export *exp, RETURN(rc); } -static inline int md_find_cbdata(struct obd_export *exp, - const struct lu_fid *fid, - ldlm_iterator_t it, void *data) -{ - int rc; - ENTRY; - EXP_CHECK_MD_OP(exp, find_cbdata); - EXP_MD_COUNTER_INCREMENT(exp, find_cbdata); - rc = MDP(exp->exp_obd, find_cbdata)(exp, fid, it, data); - RETURN(rc); -} - static inline int md_close(struct obd_export *exp, struct md_op_data *op_data, struct md_open_data *mod, struct ptlrpc_request **request) diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h index 042bc2f..76bd434 100644 --- a/lustre/include/obd_support.h +++ b/lustre/include/obd_support.h @@ -510,6 +510,7 @@ extern char obd_jobid_var[]; #define OBD_FAIL_MAKE_LOVEA_HOLE 0x1406 #define OBD_FAIL_LLITE_LOST_LAYOUT 0x1407 #define OBD_FAIL_LLITE_NO_CHECK_DEAD 0x1408 +#define OBD_FAIL_GETATTR_DELAY 0x1409 #define OBD_FAIL_FID_INDIR 0x1501 #define OBD_FAIL_FID_INLMA 0x1502 diff --git a/lustre/llite/dcache.c b/lustre/llite/dcache.c index 4ec4421..6bf6d66 100644 --- a/lustre/llite/dcache.c +++ b/lustre/llite/dcache.c @@ -125,43 +125,6 @@ static int ll_dcompare(struct dentry *parent, struct qstr *d_name, RETURN(0); } -static inline int return_if_equal(struct ldlm_lock *lock, void *data) -{ - return (ldlm_is_canceling(lock) && ldlm_is_discard_data(lock)) ? - LDLM_ITER_CONTINUE : LDLM_ITER_STOP; -} - -/* find any ldlm lock of the inode in mdc and lov - * return 0 not find - * 1 find one - * < 0 error */ -static int find_cbdata(struct inode *inode) -{ - struct lu_env *env; - __u16 refcheck; - struct ll_sb_info *sbi = ll_i2sbi(inode); - int rc = 0; - ENTRY; - - LASSERT(inode); - rc = md_find_cbdata(sbi->ll_md_exp, ll_inode2fid(inode), - return_if_equal, NULL); - if (rc != 0) - RETURN(rc); - - if (ll_i2info(inode)->lli_clob != NULL) { - env = cl_env_get(&refcheck); - if (IS_ERR(env)) - RETURN(PTR_ERR(env)); - - rc = cl_object_find_cbdata(env, ll_i2info(inode)->lli_clob, - return_if_equal, NULL); - cl_env_put(env, &refcheck); - } - - RETURN(rc); -} - /** * Called when last reference to a dentry is dropped and dcache wants to know * whether or not it should cache it: @@ -428,18 +391,9 @@ static int ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd) } #endif -static void ll_d_iput(struct dentry *de, struct inode *inode) -{ - LASSERT(inode); - if (!find_cbdata(inode)) - clear_nlink(inode); - iput(inode); -} - const struct dentry_operations ll_d_ops = { .d_revalidate = ll_revalidate_nd, .d_release = ll_release, .d_delete = ll_ddelete, - .d_iput = ll_d_iput, .d_compare = ll_dcompare, }; diff --git a/lustre/llite/file.c b/lustre/llite/file.c index d1819c6..d9aaebb 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -3371,6 +3371,8 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) if (res) return res; + OBD_FAIL_TIMEOUT(OBD_FAIL_GETATTR_DELAY, 30); + stat->dev = inode->i_sb->s_dev; if (ll_need_32bit_api(sbi)) stat->ino = cl_fid_build_ino(&lli->lli_fid, 1); diff --git a/lustre/lmv/lmv_obd.c b/lustre/lmv/lmv_obd.c index 78842b0..0198517 100644 --- a/lustre/lmv/lmv_obd.c +++ b/lustre/lmv/lmv_obd.c @@ -1614,50 +1614,6 @@ static int lmv_null_inode(struct obd_export *exp, const struct lu_fid *fid) RETURN(0); } -static int lmv_find_cbdata(struct obd_export *exp, const struct lu_fid *fid, - ldlm_iterator_t it, void *data) -{ - struct obd_device *obd = exp->exp_obd; - struct lmv_obd *lmv = &obd->u.lmv; - int i; - int tgt; - int rc; - ENTRY; - - rc = lmv_check_connect(obd); - if (rc) - RETURN(rc); - - CDEBUG(D_INODE, "CBDATA for "DFID"\n", PFID(fid)); - - /* - * With DNE every object can have two locks in different namespaces: - * lookup lock in space of MDT storing direntry and update/open lock in - * space of MDT storing inode. Try the MDT that the FID maps to first, - * since this can be easily found, and only try others if that fails. - */ - for (i = 0, tgt = lmv_find_target_index(lmv, fid); - i < lmv->desc.ld_tgt_count; - i++, tgt = (tgt + 1) % lmv->desc.ld_tgt_count) { - if (tgt < 0) { - CDEBUG(D_HA, "%s: "DFID" is inaccessible: rc = %d\n", - obd->obd_name, PFID(fid), tgt); - tgt = 0; - } - - if (lmv->tgts[tgt] == NULL || - lmv->tgts[tgt]->ltd_exp == NULL) - continue; - - rc = md_find_cbdata(lmv->tgts[tgt]->ltd_exp, fid, it, data); - if (rc) - RETURN(rc); - } - - RETURN(rc); -} - - static int lmv_close(struct obd_export *exp, struct md_op_data *op_data, struct md_open_data *mod, struct ptlrpc_request **request) { @@ -3369,7 +3325,6 @@ struct obd_ops lmv_obd_ops = { struct md_ops lmv_md_ops = { .m_getstatus = lmv_getstatus, .m_null_inode = lmv_null_inode, - .m_find_cbdata = lmv_find_cbdata, .m_close = lmv_close, .m_create = lmv_create, .m_enqueue = lmv_enqueue, diff --git a/lustre/lov/lov_object.c b/lustre/lov/lov_object.c index 85243d1..c1b12fe 100644 --- a/lustre/lov/lov_object.c +++ b/lustre/lov/lov_object.c @@ -80,8 +80,6 @@ struct lov_layout_operations { struct cl_object *obj, struct cl_io *io); int (*llo_getattr)(const struct lu_env *env, struct cl_object *obj, struct cl_attr *attr); - int (*llo_find_cbdata)(const struct lu_env *env, struct cl_object *obj, - ldlm_iterator_t iter, void *data); }; static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov); @@ -593,37 +591,6 @@ static int lov_attr_get_raid0(const struct lu_env *env, struct cl_object *obj, RETURN(result); } -static int lov_find_cbdata_empty(const struct lu_env *env, - struct cl_object *obj, ldlm_iterator_t iter, - void *data) -{ - return 0; -} - -static int lov_find_cbdata_raid0(const struct lu_env *env, - struct cl_object *obj, ldlm_iterator_t iter, - void *data) -{ - struct lov_object *lov = cl2lov(obj); - struct lov_layout_raid0 *r0 = lov_r0(lov); - struct cl_object *subobj; - int i; - int rc = 0; - - for (i = 0; i < r0->lo_nr; ++i) { - if (r0->lo_sub[i] == NULL) - continue; - - subobj = lovsub2cl(r0->lo_sub[i]); - - rc = cl_object_find_cbdata(env, subobj, iter, data); - if (rc != 0) - break; - } - - return rc; -} - const static struct lov_layout_operations lov_dispatch[] = { [LLT_EMPTY] = { .llo_init = lov_init_empty, @@ -635,7 +602,6 @@ const static struct lov_layout_operations lov_dispatch[] = { .llo_lock_init = lov_lock_init_empty, .llo_io_init = lov_io_init_empty, .llo_getattr = lov_attr_get_empty, - .llo_find_cbdata = lov_find_cbdata_empty }, [LLT_RAID0] = { .llo_init = lov_init_raid0, @@ -647,7 +613,6 @@ const static struct lov_layout_operations lov_dispatch[] = { .llo_lock_init = lov_lock_init_raid0, .llo_io_init = lov_io_init_raid0, .llo_getattr = lov_attr_get_raid0, - .llo_find_cbdata = lov_find_cbdata_raid0 }, [LLT_RELEASED] = { .llo_init = lov_init_released, @@ -659,7 +624,6 @@ const static struct lov_layout_operations lov_dispatch[] = { .llo_lock_init = lov_lock_init_empty, .llo_io_init = lov_io_init_released, .llo_getattr = lov_attr_get_empty, - .llo_find_cbdata = lov_find_cbdata_empty } }; @@ -1516,18 +1480,6 @@ static loff_t lov_object_maxbytes(struct cl_object *obj) return maxbytes; } -static int lov_object_find_cbdata(const struct lu_env *env, - struct cl_object *obj, ldlm_iterator_t iter, - void *data) -{ - int rc; - ENTRY; - - /* call cl_object_find_cbdata for sub obj */ - rc = LOV_2DISPATCH(cl2lov(obj), llo_find_cbdata, env, obj, iter, data); - RETURN(rc); -} - static const struct cl_object_operations lov_ops = { .coo_page_init = lov_page_init, .coo_lock_init = lov_lock_init, @@ -1538,7 +1490,6 @@ static const struct cl_object_operations lov_ops = { .coo_getstripe = lov_object_getstripe, .coo_layout_get = lov_object_layout_get, .coo_maxbytes = lov_object_maxbytes, - .coo_find_cbdata = lov_object_find_cbdata, .coo_fiemap = lov_object_fiemap, }; diff --git a/lustre/mdc/mdc_internal.h b/lustre/mdc/mdc_internal.h index 149da5e..552eb3f 100644 --- a/lustre/mdc/mdc_internal.h +++ b/lustre/mdc/mdc_internal.h @@ -73,9 +73,6 @@ int mdc_set_lock_data(struct obd_export *exp, int mdc_null_inode(struct obd_export *exp, const struct lu_fid *fid); -int mdc_find_cbdata(struct obd_export *exp, const struct lu_fid *fid, - ldlm_iterator_t it, void *data); - int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data, struct lookup_intent *it, diff --git a/lustre/mdc/mdc_locks.c b/lustre/mdc/mdc_locks.c index 88fffaa..593fb9d 100644 --- a/lustre/mdc/mdc_locks.c +++ b/lustre/mdc/mdc_locks.c @@ -192,28 +192,6 @@ int mdc_null_inode(struct obd_export *exp, RETURN(0); } -/* find any ldlm lock of the inode in mdc - * return 0 not find - * 1 find one - * < 0 error */ -int mdc_find_cbdata(struct obd_export *exp, - const struct lu_fid *fid, - ldlm_iterator_t it, void *data) -{ - struct ldlm_res_id res_id; - int rc = 0; - ENTRY; - - fid_build_reg_res_name((struct lu_fid*)fid, &res_id); - rc = ldlm_resource_iterate(class_exp2obd(exp)->obd_namespace, &res_id, - it, data); - if (rc == LDLM_ITER_STOP) - RETURN(1); - else if (rc == LDLM_ITER_CONTINUE) - RETURN(0); - RETURN(rc); -} - static inline void mdc_clear_replay_flag(struct ptlrpc_request *req, int rc) { /* Don't hold error requests for replay. */ diff --git a/lustre/mdc/mdc_request.c b/lustre/mdc/mdc_request.c index d002b02..090d6fa 100644 --- a/lustre/mdc/mdc_request.c +++ b/lustre/mdc/mdc_request.c @@ -2760,7 +2760,6 @@ static struct obd_ops mdc_obd_ops = { static struct md_ops mdc_md_ops = { .m_getstatus = mdc_getstatus, .m_null_inode = mdc_null_inode, - .m_find_cbdata = mdc_find_cbdata, .m_close = mdc_close, .m_create = mdc_create, .m_enqueue = mdc_enqueue, diff --git a/lustre/obdclass/cl_object.c b/lustre/obdclass/cl_object.c index d34b431..f006dd0 100644 --- a/lustre/obdclass/cl_object.c +++ b/lustre/obdclass/cl_object.c @@ -362,30 +362,6 @@ int cl_object_getstripe(const struct lu_env *env, struct cl_object *obj, EXPORT_SYMBOL(cl_object_getstripe); /** - * Find whether there is any callback data (ldlm lock) attached upon this - * object. - */ -int cl_object_find_cbdata(const struct lu_env *env, struct cl_object *obj, - ldlm_iterator_t iter, void *data) -{ - struct lu_object_header *top; - int result = 0; - ENTRY; - - top = obj->co_lu.lo_header; - list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_find_cbdata != NULL) { - result = obj->co_ops->coo_find_cbdata(env, obj, iter, - data); - if (result != 0) - break; - } - } - RETURN(result); -} -EXPORT_SYMBOL(cl_object_find_cbdata); - -/** * Get fiemap extents from file object. * * \param env [in] lustre environment diff --git a/lustre/obdclass/lprocfs_status.c b/lustre/obdclass/lprocfs_status.c index 0cae0eb..18f383b 100644 --- a/lustre/obdclass/lprocfs_status.c +++ b/lustre/obdclass/lprocfs_status.c @@ -1362,7 +1362,6 @@ void lprocfs_init_mps_stats(int num_private_stats, struct lprocfs_stats *stats) { LPROCFS_MD_OP_INIT(num_private_stats, stats, getstatus); LPROCFS_MD_OP_INIT(num_private_stats, stats, null_inode); - LPROCFS_MD_OP_INIT(num_private_stats, stats, find_cbdata); LPROCFS_MD_OP_INIT(num_private_stats, stats, close); LPROCFS_MD_OP_INIT(num_private_stats, stats, create); LPROCFS_MD_OP_INIT(num_private_stats, stats, enqueue); diff --git a/lustre/osc/osc_object.c b/lustre/osc/osc_object.c index c233d13..88261c0 100644 --- a/lustre/osc/osc_object.c +++ b/lustre/osc/osc_object.c @@ -221,31 +221,6 @@ static int osc_object_prune(const struct lu_env *env, struct cl_object *obj) osc_object_ast_clear, osc); return 0; } -/** - * Find any ldlm lock covers the osc object. - * \retval 0 not found - * \retval 1 find one - * \retval < 0 error - */ -static int osc_object_find_cbdata(const struct lu_env *env, - struct cl_object *obj, ldlm_iterator_t iter, - void *data) -{ - struct ldlm_res_id res_id; - struct obd_device *obd; - int rc = 0; - - ostid_build_res_name(&cl2osc(obj)->oo_oinfo->loi_oi, &res_id); - obd = obj->co_lu.lo_dev->ld_obd; - rc = ldlm_resource_iterate(obd->obd_namespace, &res_id, iter, data); - if (rc == LDLM_ITER_STOP) - return 1; - - if (rc == LDLM_ITER_CONTINUE) - return 0; - - return rc; -} static int osc_object_fiemap(const struct lu_env *env, struct cl_object *obj, struct ll_fiemap_info_key *fmkey, @@ -449,7 +424,6 @@ static const struct cl_object_operations osc_ops = { .coo_attr_update = osc_attr_update, .coo_glimpse = osc_object_glimpse, .coo_prune = osc_object_prune, - .coo_find_cbdata = osc_object_find_cbdata, .coo_fiemap = osc_object_fiemap, .coo_req_attr_set = osc_req_attr_set }; diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 9c1770b..21b7f1e 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -14538,6 +14538,35 @@ test_402() { } run_test 402 "Return ENOENT to lod_generate_and_set_lovea" +test_403() { + local file1=$DIR/$tfile.1 + local file2=$DIR/$tfile.2 + local tfile=$TMP/$tfile + + rm -f $file1 $file2 $tfile + + touch $file1 + ln $file1 $file2 + + # 30 sec OBD_TIMEOUT in ll_getattr() + # right before populating st_nlink + $LCTL set_param fail_loc=0x80001409 + stat -c %h $file1 > $tfile & + + # create an alias, drop all locks and reclaim the dentry + < $file2 + cancel_lru_locks mdc + cancel_lru_locks osc + sysctl -w vm.drop_caches=2 + + wait + + [ `cat $tfile` -gt 0 ] || error "wrong nlink count: `cat $tfile`" + + rm -f $tfile $file1 $file2 +} +run_test 403 "i_nlink should not drop to zero due to aliasing" + # # tests that do cleanup/setup should be run at the end #