Whamcloud - gitweb
LU-13453 osd-ldiskfs: do not leak inode if OI insertion fails 35/38235/16
authorAlex Zhuravlev <bzzz@whamcloud.com>
Wed, 15 Apr 2020 14:54:07 +0000 (17:54 +0300)
committerOleg Drokin <green@whamcloud.com>
Fri, 26 Feb 2021 08:20:42 +0000 (08:20 +0000)
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 <bzzz@whamcloud.com>
Change-Id: I2a5db657c7dab54b8dc2c50bc29365d5ee754a2e
Reviewed-on: https://review.whamcloud.com/38235
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Mike Pershin <mpershin@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/include/obd_support.h
lustre/obdclass/scrub.c
lustre/osd-ldiskfs/osd_handler.c
lustre/tests/sanity-scrub.sh

index 7160e54..c79a62b 100644 (file)
@@ -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
 
index c9852a6..adcffa9 100644 (file)
@@ -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)
index 9a18ea8..e384806 100644 (file)
@@ -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
index 8c12490..97d3e36 100644 (file)
@@ -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}