Whamcloud - gitweb
LU-7925 llite: avoid clearing i_nlink for inodes in use 64/19164/4
authorAndrew Perepechko <andrew.perepechko@seagate.com>
Sat, 26 Mar 2016 14:48:25 +0000 (17:48 +0300)
committerOleg Drokin <oleg.drokin@intel.com>
Mon, 11 Apr 2016 03:22:05 +0000 (03:22 +0000)
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 <andrew.perepechko@seagate.com>
Seagate-bug-id: MRP-3271
Change-Id: I185bed4b875a4fbf66df835cf9161912a6ade415
Reviewed-on: http://review.whamcloud.com/19164
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Wally Wang <wang@cray.com>
Reviewed-by: Lai Siyao <lai.siyao@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
15 files changed:
lustre/include/cl_object.h
lustre/include/obd.h
lustre/include/obd_class.h
lustre/include/obd_support.h
lustre/llite/dcache.c
lustre/llite/file.c
lustre/lmv/lmv_obd.c
lustre/lov/lov_object.c
lustre/mdc/mdc_internal.h
lustre/mdc/mdc_locks.c
lustre/mdc/mdc_request.c
lustre/obdclass/cl_object.c
lustre/obdclass/lprocfs_status.c
lustre/osc/osc_object.c
lustre/tests/sanity.sh

index 4de3d2e..ba1d5f3 100644 (file)
@@ -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);
index e94cd49..7ed95ea 100644 (file)
@@ -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 **);
 
index 9033e79..9e4b99d 100644 (file)
@@ -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)
index 042bc2f..76bd434 100644 (file)
@@ -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
index 4ec4421..6bf6d66 100644 (file)
@@ -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,
 };
index d1819c6..d9aaebb 100644 (file)
@@ -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);
index 78842b0..0198517 100644 (file)
@@ -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,
index 85243d1..c1b12fe 100644 (file)
@@ -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,
 };
 
index 149da5e..552eb3f 100644 (file)
@@ -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,
index 88fffaa..593fb9d 100644 (file)
@@ -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. */
index d002b02..090d6fa 100644 (file)
@@ -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,
index d34b431..f006dd0 100644 (file)
@@ -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
index 0cae0eb..18f383b 100644 (file)
@@ -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);
index c233d13..88261c0 100644 (file)
@@ -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
 };
index 9c1770b..21b7f1e 100755 (executable)
@@ -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
 #