Whamcloud - gitweb
LU-13453 osd-ldiskfs: do not leak inode if OI insertion fails
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_handler.c
index 8337dd2..e384806 100644 (file)
@@ -39,6 +39,7 @@
 
 #define DEBUG_SUBSYSTEM S_OSD
 
+#include <linux/fs_struct.h>
 #include <linux/kallsyms.h>
 #include <linux/module.h>
 #include <linux/user_namespace.h>
@@ -284,6 +285,76 @@ osd_idc_find_or_init(const struct lu_env *env, struct osd_device *osd,
        return idc;
 }
 
+static void osd_idc_dump_lma(const struct lu_env *env,
+                               struct osd_device *osd,
+                               unsigned long ino,
+                               bool check_in_oi)
+{
+       struct osd_thread_info *info = osd_oti_get(env);
+       struct lustre_ost_attrs *loa = &info->oti_ost_attrs;
+       const struct lu_fid *fid;
+       struct osd_inode_id lid;
+       struct inode *inode;
+       int rc;
+
+       inode = osd_ldiskfs_iget(osd_sb(osd), ino);
+       if (IS_ERR(inode)) {
+               CERROR("%s: can't get inode %lu: rc = %d\n",
+                      osd->od_svname, ino, (int)PTR_ERR(inode));
+               return;
+       }
+       if (is_bad_inode(inode)) {
+               CERROR("%s: bad inode %lu\n", osd->od_svname, ino);
+               goto put;
+       }
+       rc = osd_get_lma(info, inode, &info->oti_obj_dentry, loa);
+       if (rc) {
+               CERROR("%s: can't get LMA for %lu: rc = %d\n",
+                      osd->od_svname, ino, rc);
+               goto put;
+       }
+       fid = &loa->loa_lma.lma_self_fid;
+       LCONSOLE(D_INFO, "%s: "DFID" in inode %lu/%u\n", osd->od_svname,
+                     PFID(fid), ino, (unsigned)inode->i_generation);
+       if (!check_in_oi)
+               goto put;
+       rc = osd_oi_lookup(osd_oti_get(env), osd, fid, &lid, 0);
+       if (rc) {
+               CERROR("%s: can't lookup "DFID": rc = %d\n",
+                      osd->od_svname, PFID(fid), rc);
+               goto put;
+       }
+       LCONSOLE(D_INFO, "%s: "DFID" maps to %u/%u\n", osd->od_svname,
+                     PFID(fid), lid.oii_ino, lid.oii_gen);
+put:
+       iput(inode);
+}
+
+static void osd_idc_dump_debug(const struct lu_env *env,
+                               struct osd_device *osd,
+                               const struct lu_fid *fid,
+                               unsigned long ino1,
+                               unsigned long ino2)
+{
+       struct osd_inode_id lid;
+
+       int rc;
+
+       rc = osd_oi_lookup(osd_oti_get(env), osd, fid, &lid, 0);
+       if (!rc) {
+               LCONSOLE(D_INFO, "%s: "DFID" maps to %u/%u\n",
+                       osd->od_svname, PFID(fid), lid.oii_ino, lid.oii_gen);
+               osd_idc_dump_lma(env, osd, lid.oii_ino, false);
+       } else {
+               CERROR("%s: can't lookup "DFID": rc = %d\n",
+                      osd->od_svname, PFID(fid), rc);
+       }
+       if (ino1)
+               osd_idc_dump_lma(env, osd, ino1, true);
+       if (ino2)
+               osd_idc_dump_lma(env, osd, ino2, true);
+}
+
 /*
  * lookup mapping for given FID and fill it from the given object.
  * the object is lolcal by definition.
@@ -301,7 +372,12 @@ static int osd_idc_find_and_init(const struct lu_env *env,
                if (obj->oo_inode == NULL)
                        return 0;
                if (idc->oic_lid.oii_ino != obj->oo_inode->i_ino) {
-                       LASSERT(idc->oic_lid.oii_ino == 0);
+                       if (idc->oic_lid.oii_ino) {
+                               osd_idc_dump_debug(env, osd, fid,
+                                                  idc->oic_lid.oii_ino,
+                                                  obj->oo_inode->i_ino);
+                               return -EINVAL;
+                       }
                        idc->oic_lid.oii_ino = obj->oo_inode->i_ino;
                        idc->oic_lid.oii_gen = obj->oo_inode->i_generation;
                }
@@ -391,12 +467,11 @@ int osd_get_lma(struct osd_thread_info *info, struct inode *inode,
                lustre_loa_swab(loa, true);
                /* Check LMA compatibility */
                if (lma->lma_incompat & ~LMA_INCOMPAT_SUPP) {
-                       CWARN("%s: unsupported incompat LMA feature(s) %#x "
-                             "for fid = "DFID", ino = %lu\n",
+                       rc = -EOPNOTSUPP;
+                       CWARN("%s: unsupported incompat LMA feature(s) %#x for fid = "DFID", ino = %lu: rc = %d\n",
                              osd_ino2name(inode),
                              lma->lma_incompat & ~LMA_INCOMPAT_SUPP,
-                             PFID(&lma->lma_self_fid), inode->i_ino);
-                       rc = -EOPNOTSUPP;
+                             PFID(&lma->lma_self_fid), inode->i_ino, rc);
                }
        } else if (rc == 0) {
                rc = -ENODATA;
@@ -441,10 +516,11 @@ struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
                iput(inode);
                inode = ERR_PTR(-ESTALE);
        } else if (is_bad_inode(inode)) {
-               CWARN("%s: bad inode: ino = %u\n",
-                     osd_dev2name(dev), id->oii_ino);
+               rc = -ENOENT;
+               CWARN("%s: bad inode: ino = %u: rc = %d\n",
+                     osd_dev2name(dev), id->oii_ino, rc);
                iput(inode);
-               inode = ERR_PTR(-ENOENT);
+               inode = ERR_PTR(rc);
        } else if ((rc = osd_attach_jinode(inode))) {
                iput(inode);
                inode = ERR_PTR(rc);
@@ -477,6 +553,7 @@ int osd_ldiskfs_add_entry(struct osd_thread_info *info, struct osd_device *osd,
                struct lustre_ost_attrs *loa = &info->oti_ost_attrs;
                struct inode *parent = child->d_parent->d_inode;
                struct lu_fid *fid = NULL;
+               char fidstr[FID_LEN + 1] = "unknown";
 
                rc2 = osd_get_lma(info, parent, child->d_parent, loa);
                if (!rc2) {
@@ -493,19 +570,18 @@ int osd_ldiskfs_add_entry(struct osd_thread_info *info, struct osd_device *osd,
                }
 
                if (fid != NULL)
-                       /* below message is checked in sanity.sh test_129 */
-                       CWARN("%s: directory (inode: %lu, FID: "DFID") %s maximum entry limit\n",
-                             osd_name(osd), parent->i_ino, PFID(fid),
-                             rc == -ENOSPC ? "has reached" : "is approaching");
-               else
-                       /* below message is checked in sanity.sh test_129 */
-                       CWARN("%s: directory (inode: %lu, FID: unknown) %s maximum entry limit\n",
-                             osd_name(osd), parent->i_ino,
-                             rc == -ENOSPC ? "has reached" : "is approaching");
+                       snprintf(fidstr, sizeof(fidstr), DFID, PFID(fid));
+
+               /* below message is checked in sanity.sh test_129 */
+               if (rc == -ENOSPC) {
+                       CWARN("%s: directory (inode: %lu, FID: %s) has reached max size limit\n",
+                             osd_name(osd), parent->i_ino, fidstr);
+               } else {
+                       rc = 0; /* ignore such error now */
+                       CWARN("%s: directory (inode: %lu, FID: %s) is approaching max size limit\n",
+                             osd_name(osd), parent->i_ino, fidstr);
+               }
 
-               /* ignore such error now */
-               if (rc == -ENOBUFS)
-                       rc = 0;
        }
 
        return rc;
@@ -956,8 +1032,7 @@ static int osd_check_lmv(struct osd_thread_info *oti, struct osd_device *dev,
 {
        struct lu_buf *buf = &oti->oti_big_buf;
        struct dentry *dentry = &oti->oti_obj_dentry;
-       struct file *filp = &oti->oti_file;
-       const struct file_operations *fops;
+       struct file *filp;
        struct lmv_mds_md_v1 *lmv1;
        struct osd_check_lmv_buf oclb = {
                .ctx.actor = osd_stripe_dir_filldir,
@@ -1002,18 +1077,7 @@ again:
        if (le32_to_cpu(lmv1->lmv_magic) != LMV_MAGIC_V1)
                GOTO(out, rc = 0);
 
-       fops = inode->i_fop;
-       dentry->d_inode = inode;
-       dentry->d_sb = inode->i_sb;
-       filp->f_pos = 0;
-       filp->f_path.dentry = dentry;
-       filp->f_flags |= O_NOATIME;
-       filp->f_mode = FMODE_64BITHASH | FMODE_NONOTIFY;
-       filp->f_mapping = inode->i_mapping;
-       filp->f_op = fops;
-       filp->private_data = NULL;
-       filp->f_cred = current_cred();
-       filp->f_inode = inode;
+       filp = osd_quasi_file(oti->oti_env, inode);
        rc = osd_security_file_alloc(filp);
        if (rc)
                goto out;
@@ -1023,13 +1087,13 @@ again:
                rc = iterate_dir(filp, &oclb.ctx);
        } while (rc >= 0 && oclb.oclb_items > 0 && !oclb.oclb_found &&
                 filp->f_pos != LDISKFS_HTREE_EOF_64BIT);
-       fops->release(inode, filp);
+       inode->i_fop->release(inode, filp);
 
 out:
        if (rc < 0)
-               CDEBUG(D_LFSCK, "%s: fail to check LMV EA, inode = %lu/%u,"
-                      DFID": rc = %d\n", osd_ino2name(inode),
-                      inode->i_ino, inode->i_generation,
+               CDEBUG(D_LFSCK,
+                      "%s: cannot check LMV, ino = %lu/%u "DFID": rc = %d\n",
+                      osd_ino2name(inode), inode->i_ino, inode->i_generation,
                       PFID(&oic->oic_fid), rc);
        else
                rc = 0;
@@ -1178,17 +1242,19 @@ trigger:
                }
        }
 
-       if (thread_is_running(&scrub->os_thread)) {
+       if (scrub->os_running) {
                if (scrub->os_partial_scan && !scrub->os_in_join)
                        goto join;
 
-               if (IS_ERR_OR_NULL(inode) || result)
+               osd_add_oi_cache(info, dev, id, fid);
+               if (IS_ERR_OR_NULL(inode) || result) {
+                       osd_oii_insert(dev, oic, result == -ENOENT);
                        GOTO(out, result = -EINPROGRESS);
+               }
 
                LASSERT(remote);
                LASSERT(obj->oo_inode == inode);
 
-               osd_add_oi_cache(info, dev, id, fid);
                osd_oii_insert(dev, oic, true);
                goto found;
        }
@@ -1211,13 +1277,15 @@ join:
        if (rc1 && rc1 != -EALREADY)
                GOTO(out, result = -EREMCHG);
 
-       if (IS_ERR_OR_NULL(inode) || result)
+       osd_add_oi_cache(info, dev, id, fid);
+       if (IS_ERR_OR_NULL(inode) || result) {
+               osd_oii_insert(dev, oic, result == -ENOENT);
                GOTO(out, result = -EINPROGRESS);
+       }
 
        LASSERT(remote);
        LASSERT(obj->oo_inode == inode);
 
-       osd_add_oi_cache(info, dev, id, fid);
        osd_oii_insert(dev, oic, true);
        goto found;
 
@@ -1436,6 +1504,7 @@ static int osd_object_init(const struct lu_env *env, struct lu_object *l,
                        result = 0;
                }
        }
+       obj->oo_dirent_count = LU_DIRENT_COUNT_UNSET;
 
        LINVRNT(osd_invariant(obj));
        return result;
@@ -1589,11 +1658,8 @@ static void osd_object_free(const struct lu_env *env, struct lu_object *l)
                ldiskfs_htree_lock_head_free(obj->oo_hl_head);
        /* obj doesn't contain an lu_object_header, so we don't need call_rcu */
        OBD_FREE_PTR(obj);
-       if (unlikely(h)) {
-               lu_object_header_fini(h);
-               OBD_FREE_PRE(h, sizeof(*h), "kfreed");
-               kfree_rcu(h, loh_rcu);
-       }
+       if (unlikely(h))
+               lu_object_header_free(h);
 }
 
 /*
@@ -1615,16 +1681,6 @@ static void osd_index_fini(struct osd_object *o)
        }
 }
 
-/*
- * Concurrency: no concurrent access is possible that late in object
- * life-cycle (for all existing callers, that is. New callers have to provide
- * their own locking.)
- */
-static int osd_inode_unlinked(const struct inode *inode)
-{
-       return inode->i_nlink == 0;
-}
-
 enum {
        OSD_TXN_OI_DELETE_CREDITS    = 20,
        OSD_TXN_INODE_DELETE_CREDITS = 20
@@ -1711,9 +1767,10 @@ static int osd_param_is_not_sane(const struct osd_device *dev,
 static void osd_trans_commit_cb(struct super_block *sb,
                                struct ldiskfs_journal_cb_entry *jcb, int error)
 {
-       struct osd_thandle *oh = container_of0(jcb, struct osd_thandle, ot_jcb);
+       struct osd_thandle *oh = container_of(jcb, struct osd_thandle, ot_jcb);
        struct thandle *th = &oh->ot_super;
        struct lu_device *lud = &th->th_dev->dd_lu_dev;
+       struct osd_device *osd = osd_dev(lud);
        struct dt_txn_commit_cb *dcb, *tmp;
 
        LASSERT(oh->ot_handle == NULL);
@@ -1733,7 +1790,8 @@ static void osd_trans_commit_cb(struct super_block *sb,
        }
 
        lu_ref_del_at(&lud->ld_reference, &oh->ot_dev_link, "osd-tx", th);
-       lu_device_put(lud);
+       if (atomic_dec_and_test(&osd->od_commit_cb_in_flight))
+               wake_up(&osd->od_commit_cb_done);
        th->th_dev = NULL;
 
        OBD_FREE_PTR(oh);
@@ -1774,6 +1832,7 @@ static struct thandle *osd_trans_create(const struct lu_env *env,
        th->th_dev = d;
        th->th_result = 0;
        oh->ot_credits = 0;
+       oh->oh_declared_ext = 0;
        INIT_LIST_HEAD(&oh->ot_commit_dcb_list);
        INIT_LIST_HEAD(&oh->ot_stop_dcb_list);
        INIT_LIST_HEAD(&oh->ot_trunc_locks);
@@ -1796,7 +1855,7 @@ void osd_trans_dump_creds(const struct lu_env *env, struct thandle *th)
        struct osd_thread_info *oti = osd_oti_get(env);
        struct osd_thandle *oh;
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh != NULL);
 
        CWARN("  create: %u/%u/%u, destroy: %u/%u/%u\n",
@@ -1855,7 +1914,7 @@ static int osd_trans_start(const struct lu_env *env, struct dt_device *d,
 
        LASSERT(current->journal_info == NULL);
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh != NULL);
        LASSERT(oh->ot_handle == NULL);
 
@@ -1916,7 +1975,7 @@ static int osd_trans_start(const struct lu_env *env, struct dt_device *d,
                oh->ot_handle = jh;
                LASSERT(oti->oti_txns == 0);
 
-               lu_device_get(&d->dd_lu_dev);
+               atomic_inc(&dev->od_commit_cb_in_flight);
                lu_ref_add_at(&d->dd_lu_dev.ld_reference, &oh->ot_dev_link,
                              "osd-tx", th);
                oti->oti_txns++;
@@ -1984,7 +2043,7 @@ static int osd_trans_stop(const struct lu_env *env, struct dt_device *dt,
 
        ENTRY;
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       oh = container_of(th, struct osd_thandle, ot_super);
 
        remove_agents = oh->ot_remove_agents;
 
@@ -2033,7 +2092,7 @@ static int osd_trans_stop(const struct lu_env *env, struct dt_device *dt,
                OBD_FREE_PTR(oh);
        }
 
-       osd_trunc_unlock_all(&truncates);
+       osd_trunc_unlock_all(env, &truncates);
 
        /* inform the quota slave device that the transaction is stopping */
        qsd_op_end(env, qsd, qtrans);
@@ -2057,6 +2116,7 @@ static int osd_trans_stop(const struct lu_env *env, struct dt_device *dt,
        if (unlikely(remove_agents != 0))
                osd_process_scheduled_agent_removals(env, osd);
 
+       LASSERT(oti->oti_ins_cache_depth > 0);
        oti->oti_ins_cache_depth--;
        /* reset OI cache for safety */
        if (oti->oti_ins_cache_depth == 0)
@@ -2069,8 +2129,8 @@ static int osd_trans_stop(const struct lu_env *env, struct dt_device *dt,
 
 static int osd_trans_cb_add(struct thandle *th, struct dt_txn_commit_cb *dcb)
 {
-       struct osd_thandle *oh = container_of0(th, struct osd_thandle,
-                                              ot_super);
+       struct osd_thandle *oh = container_of(th, struct osd_thandle,
+                                             ot_super);
 
        LASSERT(dcb->dcb_magic == TRANS_COMMIT_CB_MAGIC);
        LASSERT(&dcb->dcb_func != NULL);
@@ -2109,6 +2169,9 @@ static void osd_object_delete(const struct lu_env *env, struct lu_object *l)
        if (!inode)
                return;
 
+       if (osd_has_index(obj) &&  obj->oo_dt.do_index_ops == &osd_index_iam_ops)
+               ldiskfs_set_inode_flag(inode, LDISKFS_INODE_JOURNAL_DATA);
+
        uid = i_uid_read(inode);
        gid = i_gid_read(inode);
        projid = i_projid_read(inode);
@@ -2206,9 +2269,9 @@ int osd_statfs(const struct lu_env *env, struct dt_device *d,
 
        statfs_pack(sfs, ksfs);
        if (unlikely(sb->s_flags & SB_RDONLY))
-               sfs->os_state |= OS_STATE_READONLY;
+               sfs->os_state |= OS_STATFS_READONLY;
 
-       sfs->os_state |= osd->od_nonrotational ? OS_STATE_NONROT : 0;
+       sfs->os_state |= osd->od_nonrotational ? OS_STATFS_NONROT : 0;
 
        if (ldiskfs_has_feature_extents(sb))
                sfs->os_maxbytes = sb->s_maxbytes;
@@ -2370,6 +2433,8 @@ static void osd_conf_get(const struct lu_env *env,
                               d->od_svname, name);
                }
        }
+
+       param->ddp_has_lseek_data_hole = true;
 }
 
 static struct super_block *osd_mnt_sb_get(const struct dt_device *d)
@@ -2620,10 +2685,71 @@ static void osd_inode_getattr(const struct lu_env *env,
                attr->la_flags |= LUSTRE_PROJINHERIT_FL;
 }
 
+static int osd_dirent_count(const struct lu_env *env, struct dt_object *dt,
+                           u64 *count)
+{
+       struct osd_object *obj = osd_dt_obj(dt);
+       const struct dt_it_ops *iops;
+       struct dt_it *it;
+       int rc;
+
+       ENTRY;
+
+       LASSERT(S_ISDIR(obj->oo_inode->i_mode));
+       LASSERT(fid_is_namespace_visible(lu_object_fid(&obj->oo_dt.do_lu)));
+
+       if (obj->oo_dirent_count != LU_DIRENT_COUNT_UNSET) {
+               *count = obj->oo_dirent_count;
+               RETURN(0);
+       }
+
+       /* directory not initialized yet */
+       if (!dt->do_index_ops) {
+               *count = 0;
+               RETURN(0);
+       }
+
+       iops = &dt->do_index_ops->dio_it;
+       it = iops->init(env, dt, LUDA_64BITHASH);
+       if (IS_ERR(it))
+               RETURN(PTR_ERR(it));
+
+       rc = iops->load(env, it, 0);
+       if (rc < 0) {
+               if (rc == -ENODATA) {
+                       rc = 0;
+                       *count = 0;
+               }
+               GOTO(out, rc);
+       }
+       if (rc > 0)
+               rc = iops->next(env, it);
+
+       for (*count = 0; rc == 0 || rc == -ESTALE; rc = iops->next(env, it)) {
+               if (rc == -ESTALE)
+                       continue;
+
+               if (iops->key_size(env, it) == 0)
+                       continue;
+
+               (*count)++;
+       }
+       if (rc == 1) {
+               obj->oo_dirent_count = *count;
+               rc = 0;
+       }
+out:
+       iops->put(env, it);
+       iops->fini(env, it);
+
+       RETURN(rc);
+}
+
 static int osd_attr_get(const struct lu_env *env, struct dt_object *dt,
                        struct lu_attr *attr)
 {
        struct osd_object *obj = osd_dt_obj(dt);
+       int rc = 0;
 
        if (unlikely(!dt_object_exists(dt)))
                return -ENOENT;
@@ -2639,9 +2765,17 @@ static int osd_attr_get(const struct lu_env *env, struct dt_object *dt,
                attr->la_valid |= LA_FLAGS;
                attr->la_flags |= LUSTRE_ORPHAN_FL;
        }
+       if (obj->oo_lma_flags & LUSTRE_ENCRYPT_FL) {
+               attr->la_valid |= LA_FLAGS;
+               attr->la_flags |= LUSTRE_ENCRYPT_FL;
+       }
        spin_unlock(&obj->oo_guard);
 
-       return 0;
+       if (S_ISDIR(obj->oo_inode->i_mode) &&
+           fid_is_namespace_visible(lu_object_fid(&dt->do_lu)))
+               rc = osd_dirent_count(env, dt, &attr->la_dirent_count);
+
+       return rc;
 }
 
 static int osd_declare_attr_qid(const struct lu_env *env,
@@ -2724,7 +2858,7 @@ static int osd_declare_attr_set(const struct lu_env *env,
        obj = osd_dt_obj(dt);
        LASSERT(osd_invariant(obj));
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        osd_trans_declare_op(env, oh, OSD_OT_ATTR_SET,
@@ -2751,9 +2885,9 @@ static int osd_declare_attr_set(const struct lu_env *env,
                bool ignore_edquot = !(attr->la_flags & LUSTRE_SET_SYNC_FL);
 
                if (!ignore_edquot)
-                       CDEBUG(D_QUOTA, "%s: enforce quota on UID %u, GID %u"
-                              "(the quota space is %lld)\n",
-                              obj->oo_inode->i_sb->s_id, attr->la_uid,
+                       CDEBUG(D_QUOTA,
+                              "%s: enforce quota on UID %u, GID %u (quota space is %lld)\n",
+                              osd_ino2name(obj->oo_inode), attr->la_uid,
                               attr->la_gid, bspace);
 
                /* USERQUOTA */
@@ -2839,6 +2973,13 @@ static int osd_inode_setattr(const struct lu_env *env,
                /* always keep S_NOCMTIME */
                inode->i_flags = ll_ext_to_inode_flags(attr->la_flags) |
                                 S_NOCMTIME;
+#if defined(S_ENCRYPTED)
+               /* Always remove S_ENCRYPTED, because ldiskfs must not be
+                * aware of encryption status. It is just stored into LMA
+                * so that it can be forwared to client side.
+                */
+               inode->i_flags &= ~S_ENCRYPTED;
+#endif
                /*
                 * Ext4 did not transfer inherit flags from
                 * @inode->i_flags to raw inode i_flags when writing
@@ -2853,7 +2994,8 @@ static int osd_inode_setattr(const struct lu_env *env,
 }
 
 #ifdef HAVE_PROJECT_QUOTA
-static int osd_transfer_project(struct inode *inode, __u32 projid)
+static int osd_transfer_project(struct inode *inode, __u32 projid,
+                               struct thandle *handle)
 {
        struct super_block *sb = inode->i_sb;
        struct ldiskfs_inode_info *ei = LDISKFS_I(inode);
@@ -2885,9 +3027,18 @@ static int osd_transfer_project(struct inode *inode, __u32 projid)
 
        raw_inode = ldiskfs_raw_inode(&iloc);
        if (!LDISKFS_FITS_IN_INODE(raw_inode, ei, i_projid)) {
-               err = -EOVERFLOW;
-               brelse(iloc.bh);
-               return err;
+               struct osd_thandle *oh = container_of(handle,
+                                                     struct osd_thandle,
+                                                     ot_super);
+               /**
+                * try to expand inode size automatically.
+                */
+               ldiskfs_mark_inode_dirty(oh->ot_handle, inode);
+               if (!LDISKFS_FITS_IN_INODE(raw_inode, ei, i_projid)) {
+                       err = -EOVERFLOW;
+                       brelse(iloc.bh);
+                       return err;
+               }
        }
        brelse(iloc.bh);
 
@@ -2904,7 +3055,8 @@ static int osd_transfer_project(struct inode *inode, __u32 projid)
 }
 #endif
 
-static int osd_quota_transfer(struct inode *inode, const struct lu_attr *attr)
+static int osd_quota_transfer(struct inode *inode, const struct lu_attr *attr,
+                             struct thandle *handle)
 {
        int rc;
 
@@ -2928,9 +3080,8 @@ static int osd_quota_transfer(struct inode *inode, const struct lu_attr *attr)
 
                rc = dquot_transfer(inode, &iattr);
                if (rc) {
-                       CERROR("%s: quota transfer failed: rc = %d. Is quota "
-                              "enforcement enabled on the ldiskfs "
-                              "filesystem?\n", inode->i_sb->s_id, rc);
+                       CERROR("%s: quota transfer failed. Is quota enforcement enabled on the ldiskfs filesystem? rc = %d\n",
+                              osd_ino2name(inode), rc);
                        return rc;
                }
        }
@@ -2939,14 +3090,13 @@ static int osd_quota_transfer(struct inode *inode, const struct lu_attr *attr)
        if (attr->la_valid & LA_PROJID &&
            attr->la_projid != i_projid_read(inode)) {
 #ifdef HAVE_PROJECT_QUOTA
-               rc = osd_transfer_project(inode, attr->la_projid);
+               rc = osd_transfer_project(inode, attr->la_projid, handle);
 #else
                rc = -ENOTSUPP;
 #endif
                if (rc) {
-                       CERROR("%s: quota transfer failed: rc = %d. Is project "
-                              "enforcement enabled on the ldiskfs "
-                              "filesystem?\n", inode->i_sb->s_id, rc);
+                       CERROR("%s: quota transfer failed. Is project enforcement enabled on the ldiskfs filesystem? rc = %d\n",
+                              osd_ino2name(inode), rc);
                        return rc;
                }
        }
@@ -2990,7 +3140,7 @@ static int osd_attr_set(const struct lu_env *env,
                if (unlikely(ipd == NULL))
                        RETURN(-ENOMEM);
 
-               oh = container_of0(handle, struct osd_thandle, ot_super);
+               oh = container_of(handle, struct osd_thandle, ot_super);
                rc = iam_update(oh->ot_handle, bag,
                                (const struct iam_key *)fid1,
                                (const struct iam_rec *)id, ipd);
@@ -3000,7 +3150,7 @@ static int osd_attr_set(const struct lu_env *env,
 
        inode = obj->oo_inode;
 
-       rc = osd_quota_transfer(inode, attr);
+       rc = osd_quota_transfer(inode, attr, handle);
        if (rc)
                return rc;
 
@@ -3140,6 +3290,8 @@ static int osd_mkdir(struct osd_thread_info *info, struct osd_object *obj,
 
        oth = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oth->ot_handle->h_transaction != NULL);
+       if (fid_is_namespace_visible(lu_object_fid(&obj->oo_dt.do_lu)))
+               obj->oo_dirent_count = 0;
        result = osd_mkfile(info, obj, mode, hint, th, attr);
 
        return result;
@@ -3286,7 +3438,8 @@ static void osd_ah_init(const struct lu_env *env, struct dt_allocation_hint *ah,
 }
 
 static void osd_attr_init(struct osd_thread_info *info, struct osd_object *obj,
-                         struct lu_attr *attr, struct dt_object_format *dof)
+                         struct lu_attr *attr, struct dt_object_format *dof,
+                         struct thandle *handle)
 {
        struct inode *inode = obj->oo_inode;
        __u64 valid = attr->la_valid;
@@ -3303,7 +3456,7 @@ static void osd_attr_init(struct osd_thread_info *info, struct osd_object *obj,
        if ((valid & LA_MTIME) && (attr->la_mtime == inode->i_mtime.tv_sec))
                attr->la_valid &= ~LA_MTIME;
 
-       result = osd_quota_transfer(inode, attr);
+       result = osd_quota_transfer(inode, attr, handle);
        if (result)
                return;
 
@@ -3354,7 +3507,7 @@ static int __osd_create(struct osd_thread_info *info, struct osd_object *obj,
        }
 
        if (likely(result == 0)) {
-               osd_attr_init(info, obj, attr, dof);
+               osd_attr_init(info, obj, attr, dof, th);
                osd_object_init0(obj);
        }
 
@@ -3382,7 +3535,10 @@ static int __osd_oi_insert(const struct lu_env *env, struct osd_object *obj,
 
        LASSERT(obj->oo_inode != NULL);
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       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);
 
@@ -3448,7 +3604,7 @@ static int osd_declare_create(const struct lu_env *env, struct dt_object *dt,
 
        LASSERT(handle != NULL);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        /*
@@ -3506,7 +3662,7 @@ static int osd_declare_destroy(const struct lu_env *env, struct dt_object *dt,
        if (inode == NULL)
                RETURN(-ENOENT);
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        osd_trans_declare_op(env, oh, OSD_OT_DESTROY,
@@ -3557,7 +3713,7 @@ static int osd_destroy(const struct lu_env *env, struct dt_object *dt,
 
        ENTRY;
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle);
        LASSERT(inode);
        LASSERT(!lu_object_is_dying(dt->do_lu.lo_header));
@@ -3573,8 +3729,10 @@ static int osd_destroy(const struct lu_env *env, struct dt_object *dt,
        }
 
        if (S_ISDIR(inode->i_mode)) {
-               LASSERT(osd_inode_unlinked(inode) || inode->i_nlink == 1 ||
-                       inode->i_nlink == 2);
+               if (inode->i_nlink > 2)
+                       CERROR("%s: directory "DFID" ino %lu link count is %u at unlink. run e2fsck to repair\n",
+                              osd_name(osd), PFID(fid), inode->i_ino,
+                              inode->i_nlink);
 
                spin_lock(&obj->oo_guard);
                clear_nlink(inode);
@@ -3738,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);
 
@@ -3778,6 +3939,7 @@ static struct inode *osd_create_local_agent_inode(const struct lu_env *env,
        struct osd_thread_info *info = osd_oti_get(env);
        struct inode *local;
        struct osd_thandle *oh;
+       uid_t own[2] = {0, 0};
        int rc;
 
        ENTRY;
@@ -3786,8 +3948,7 @@ static struct inode *osd_create_local_agent_inode(const struct lu_env *env,
        oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle->h_transaction != NULL);
 
-       local = ldiskfs_create_inode(oh->ot_handle, pobj->oo_inode, type,
-                                    NULL);
+       local = ldiskfs_create_inode(oh->ot_handle, pobj->oo_inode, type, own);
        if (IS_ERR(local)) {
                CERROR("%s: create local error %d\n", osd_name(osd),
                       (int)PTR_ERR(local));
@@ -3819,11 +3980,10 @@ static struct inode *osd_create_local_agent_inode(const struct lu_env *env,
 #ifdef HAVE_PROJECT_QUOTA
        if (LDISKFS_I(pobj->oo_inode)->i_flags & LUSTRE_PROJINHERIT_FL &&
            i_projid_read(pobj->oo_inode) != 0) {
-               rc = osd_transfer_project(local, 0);
+               rc = osd_transfer_project(local, 0, th);
                if (rc) {
-                       CERROR("%s: quota transfer failed: rc = %d. Is project "
-                              "quota enforcement enabled on the ldiskfs "
-                              "filesystem?\n", local->i_sb->s_id, rc);
+                       CERROR("%s: quota transfer failed:. Is project quota enforcement enabled on the ldiskfs filesystem? rc = %d\n",
+                              osd_ino2name(local), rc);
                        RETURN(ERR_PTR(rc));
                }
        }
@@ -3987,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
@@ -4012,19 +4185,21 @@ static int osd_declare_ref_add(const struct lu_env *env, struct dt_object *dt,
                               struct thandle *handle)
 {
        struct osd_thandle *oh;
+       int rc;
 
        /* it's possible that object doesn't exist yet */
        LASSERT(handle != NULL);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        osd_trans_declare_op(env, oh, OSD_OT_REF_ADD,
                             osd_dto_credits_noquota[DTO_ATTR_SET_BASE]);
 
-       osd_idc_find_and_init(env, osd_dev(dt->do_lu.lo_dev), osd_dt_obj(dt));
+       rc = osd_idc_find_and_init(env, osd_dev(dt->do_lu.lo_dev),
+                                  osd_dt_obj(dt));
 
-       return 0;
+       return rc;
 }
 
 /*
@@ -4046,7 +4221,7 @@ static int osd_ref_add(const struct lu_env *env, struct dt_object *dt,
        LASSERT(osd_is_write_locked(env, obj));
        LASSERT(th != NULL);
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle != NULL);
 
        osd_trans_exec_op(env, th, OSD_OT_REF_ADD);
@@ -4094,7 +4269,7 @@ static int osd_declare_ref_del(const struct lu_env *env, struct dt_object *dt,
        LASSERT(!dt_object_remote(dt));
        LASSERT(handle != NULL);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        osd_trans_declare_op(env, oh, OSD_OT_REF_DEL,
@@ -4122,7 +4297,10 @@ static int osd_ref_del(const struct lu_env *env, struct dt_object *dt,
        LASSERT(osd_is_write_locked(env, obj));
        LASSERT(th != NULL);
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       if (OBD_FAIL_CHECK(OBD_FAIL_OSD_REF_DEL))
+               return -EIO;
+
+       oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle != NULL);
 
        osd_trans_exec_op(env, th, OSD_OT_REF_DEL);
@@ -4273,7 +4451,7 @@ static int osd_declare_xattr_set(const struct lu_env *env,
 
        LASSERT(handle != NULL);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        if (strcmp(name, XATTR_NAME_LMA) == 0) {
@@ -4492,7 +4670,7 @@ static int osd_xattr_handle_linkea(const struct lu_env *env,
 
        ENTRY;
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle != NULL);
 
        rc = linkea_init_with_rec(&ldata);
@@ -4661,7 +4839,7 @@ static int osd_declare_xattr_del(const struct lu_env *env,
        LASSERT(!dt_object_remote(dt));
        LASSERT(handle != NULL);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        osd_trans_declare_op(env, oh, OSD_OT_XATTR_SET,
@@ -4736,20 +4914,11 @@ static int osd_object_sync(const struct lu_env *env, struct dt_object *dt,
 {
        struct osd_object *obj = osd_dt_obj(dt);
        struct inode *inode = obj->oo_inode;
-       struct osd_thread_info *info = osd_oti_get(env);
-       struct dentry *dentry = &info->oti_obj_dentry;
-       struct file *file = &info->oti_file;
+       struct file *file = osd_quasi_file(env, inode);
        int rc;
 
        ENTRY;
 
-       dentry->d_inode = inode;
-       dentry->d_sb = inode->i_sb;
-       file->f_path.dentry = dentry;
-       file->f_mapping = inode->i_mapping;
-       file->f_op = inode->i_fop;
-       file->f_inode = inode;
-
        rc = vfs_fsync_range(file, start, end, 0);
 
        RETURN(rc);
@@ -4962,7 +5131,7 @@ static int osd_index_declare_iam_delete(const struct lu_env *env,
 {
        struct osd_thandle *oh;
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        /* Recycle  may cause additional three blocks to be changed. */
@@ -5010,7 +5179,7 @@ static int osd_index_iam_delete(const struct lu_env *env, struct dt_object *dt,
        if (unlikely(ipd == NULL))
                RETURN(-ENOMEM);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle != NULL);
        LASSERT(oh->ot_handle->h_transaction != NULL);
 
@@ -5041,7 +5210,7 @@ static int osd_index_declare_ea_delete(const struct lu_env *env,
        LASSERT(!dt_object_remote(dt));
        LASSERT(handle != NULL);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        credits = osd_dto_credits_noquota[DTO_INDEX_DELETE];
@@ -5203,11 +5372,21 @@ static int osd_index_ea_delete(const struct lu_env *env, struct dt_object *dt,
        } else {
                rc = PTR_ERR(bh);
        }
+
+       if (!rc && fid_is_namespace_visible(lu_object_fid(&dt->do_lu)) &&
+           obj->oo_dirent_count != LU_DIRENT_COUNT_UNSET) {
+               /* NB, dirent count may not be accurate, because it's counted
+                * without lock.
+                */
+               if (obj->oo_dirent_count)
+                       obj->oo_dirent_count--;
+               else
+                       obj->oo_dirent_count = LU_DIRENT_COUNT_UNSET;
+       }
        if (hlock != NULL)
                ldiskfs_htree_unlock(hlock);
        else
                up_write(&obj->oo_ext_idx_sem);
-
        GOTO(out, rc);
 out:
        LASSERT(osd_invariant(obj));
@@ -5294,7 +5473,7 @@ static int osd_index_declare_iam_insert(const struct lu_env *env,
 
        LASSERT(handle != NULL);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        osd_trans_declare_op(env, oh, OSD_OT_INSERT,
@@ -5344,7 +5523,7 @@ static int osd_index_iam_insert(const struct lu_env *env, struct dt_object *dt,
        if (unlikely(ipd == NULL))
                RETURN(-ENOMEM);
 
-       oh = container_of0(th, struct osd_thandle, ot_super);
+       oh = container_of(th, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle != NULL);
        LASSERT(oh->ot_handle->h_transaction != NULL);
        if (S_ISDIR(obj->oo_inode->i_mode)) {
@@ -5542,6 +5721,10 @@ static int osd_ea_add_rec(const struct lu_env *env, struct osd_object *pobj,
                                              hlock, th);
                }
        }
+       if (!rc && fid_is_namespace_visible(lu_object_fid(&pobj->oo_dt.do_lu))
+           && pobj->oo_dirent_count != LU_DIRENT_COUNT_UNSET)
+               pobj->oo_dirent_count++;
+
        if (hlock != NULL)
                ldiskfs_htree_unlock(hlock);
        else
@@ -5567,8 +5750,7 @@ osd_consistency_check(struct osd_thread_info *oti, struct osd_device *dev,
        if (!fid_is_norm(fid) && !fid_is_igif(fid))
                RETURN(0);
 
-       if (thread_is_running(&scrub->os_thread) &&
-           scrub->os_pos_current > id->oii_ino)
+       if (scrub->os_running && scrub->os_pos_current > id->oii_ino)
                RETURN(0);
 
        if (dev->od_auto_scrub_interval == AS_NEVER ||
@@ -5609,7 +5791,7 @@ again:
        insert = false;
 
 trigger:
-       if (thread_is_running(&scrub->os_thread)) {
+       if (scrub->os_running) {
                if (inode == NULL) {
                        inode = osd_iget(oti, dev, id);
                        /* The inode has been removed (by race maybe). */
@@ -5642,8 +5824,7 @@ trigger:
                rc = osd_scrub_start(oti->oti_env, dev, SS_AUTO_PARTIAL |
                                     SS_CLEAR_DRYRUN | SS_CLEAR_FAILOUT);
                CDEBUG(D_LFSCK | D_CONSOLE | D_WARNING,
-                      "%s: trigger partial OI scrub for RPC inconsistency "
-                      "checking FID "DFID": rc = %d\n",
+                      "%s: trigger partial OI scrub for RPC inconsistency checking FID "DFID": rc = %d\n",
                       osd_dev2name(dev), PFID(fid), rc);
                if (rc == 0 || rc == -EALREADY)
                        goto again;
@@ -5935,7 +6116,7 @@ static int osd_index_declare_ea_insert(const struct lu_env *env,
        LASSERT(fid != NULL);
        LASSERT(rec1->rec_type != 0);
 
-       oh = container_of0(handle, struct osd_thandle, ot_super);
+       oh = container_of(handle, struct osd_thandle, ot_super);
        LASSERT(oh->ot_handle == NULL);
 
        credits = osd_dto_credits_noquota[DTO_INDEX_INSERT];
@@ -6095,6 +6276,7 @@ static int osd_index_ea_insert(const struct lu_env *env, struct dt_object *dt,
                iput(child_inode);
        LASSERT(osd_invariant(obj));
        osd_trans_exec_check(env, th, OSD_OT_INSERT);
+
        RETURN(rc);
 }
 
@@ -6602,18 +6784,13 @@ static int osd_ldiskfs_it_fill(const struct lu_env *env,
        filp->f_cred = current_cred();
        rc = osd_security_file_alloc(filp);
        if (rc)
-               RETURN(rc);
+               GOTO(unlock, rc);
 
        filp->f_flags |= O_NOATIME;
        filp->f_mode |= FMODE_NONOTIFY;
        rc = iterate_dir(filp, &buf.ctx);
        if (rc)
-               RETURN(rc);
-
-       if (hlock != NULL)
-               ldiskfs_htree_unlock(hlock);
-       else
-               up_read(&obj->oo_ext_idx_sem);
+               GOTO(unlock, rc);
 
        if (it->oie_rd_dirent == 0) {
                /*
@@ -6627,6 +6804,11 @@ static int osd_ldiskfs_it_fill(const struct lu_env *env,
                it->oie_dirent = it->oie_buf;
                it->oie_it_dirent = 1;
        }
+unlock:
+       if (hlock != NULL)
+               ldiskfs_htree_unlock(hlock);
+       else
+               up_read(&obj->oo_ext_idx_sem);
 
        RETURN(rc);
 }
@@ -6775,11 +6957,10 @@ osd_dirent_reinsert(const struct lu_env *env, struct osd_device *dev,
         * That means we lose it!
         */
        if (rc != 0)
-               CDEBUG(D_LFSCK, "%s: fail to reinsert the dirent, "
-                      "dir = %lu/%u, name = %.*s, "DFID": rc = %d\n",
-                      osd_ino2name(inode),
-                      dir->i_ino, dir->i_generation, namelen,
-                      dentry->d_name.name, PFID(fid), rc);
+               CDEBUG(D_LFSCK,
+                      "%s: fail to reinsert the dirent, dir = %lu/%u, name = %.*s, "DFID": rc = %d\n",
+                      osd_ino2name(inode), dir->i_ino, dir->i_generation,
+                      namelen, dentry->d_name.name, PFID(fid), rc);
 
        RETURN(rc);
 }
@@ -7190,8 +7371,6 @@ static inline int osd_it_ea_rec(const struct lu_env *env,
 
                                rc = osd_ea_fid_get(env, obj, ino, fid, id);
                        }
-               } else {
-                       osd_id_gen(id, ino, OSD_OII_NOGEN);
                }
        }
 
@@ -7201,15 +7380,6 @@ static inline int osd_it_ea_rec(const struct lu_env *env,
                           it->oie_dirent->oied_namelen,
                           it->oie_dirent->oied_type, attr);
 
-       if (rc < 0)
-               RETURN(rc);
-
-       if (osd_remote_fid(env, dev, fid))
-               RETURN(0);
-
-       if (likely(!(attr & (LUDA_IGNORE | LUDA_UNKNOWN)) && rc == 0))
-               osd_add_oi_cache(oti, dev, id, fid);
-
        RETURN(rc > 0 ? 0 : rc);
 }
 
@@ -7375,7 +7545,8 @@ static void osd_key_fini(const struct lu_context *ctx,
                                __free_page(page);
                        }
                }
-               OBD_FREE_PTR_ARRAY(info->oti_dio_pages, PTLRPC_MAX_BRW_PAGES);
+               OBD_FREE_PTR_ARRAY_LARGE(info->oti_dio_pages,
+                                        PTLRPC_MAX_BRW_PAGES);
        }
 
        if (info->oti_inode != NULL)
@@ -7503,6 +7674,8 @@ static void osd_umount(const struct lu_env *env, struct osd_device *o)
        if (o->od_mnt != NULL) {
                shrink_dcache_sb(osd_sb(o));
                osd_sync(env, &o->od_dt_dev);
+               wait_event(o->od_commit_cb_done,
+                         !atomic_read(&o->od_commit_cb_in_flight));
 
                mntput(o->od_mnt);
                o->od_mnt = NULL;
@@ -7707,6 +7880,8 @@ static struct lu_device *osd_device_fini(const struct lu_env *env,
        osd_procfs_fini(o);
        if (o->od_oi_table != NULL)
                osd_oi_fini(osd_oti_get(env), o);
+       if (o->od_extent_bytes_percpu)
+               free_percpu(o->od_extent_bytes_percpu);
        osd_obj_map_fini(o);
        osd_umount(env, o);
 
@@ -7740,6 +7915,7 @@ static int osd_device_init0(const struct lu_env *env,
        spin_lock_init(&o->od_lock);
        o->od_index_backup_policy = LIBP_NONE;
        o->od_t10_type = 0;
+       init_waitqueue_head(&o->od_commit_cb_done);
 
        o->od_read_cache = 1;
        o->od_writethrough_cache = 1;
@@ -7747,6 +7923,8 @@ static int osd_device_init0(const struct lu_env *env,
        o->od_readcache_max_iosize = OSD_READCACHE_MAX_IO_MB << 20;
        o->od_writethrough_max_iosize = OSD_WRITECACHE_MAX_IO_MB << 20;
        o->od_auto_scrub_interval = AS_DEFAULT;
+       /* default fallocate to unwritten extents: LU-14326/LU-14333 */
+       o->od_fallocate_zero_blocks = 0;
 
        cplen = strlcpy(o->od_svname, lustre_cfg_string(cfg, 4),
                        sizeof(o->od_svname));
@@ -7829,6 +8007,12 @@ static int osd_device_init0(const struct lu_env *env,
                GOTO(out_procfs, rc);
        }
 
+       o->od_extent_bytes_percpu = alloc_percpu(unsigned int);
+       if (!o->od_extent_bytes_percpu) {
+               rc = -ENOMEM;
+               GOTO(out_procfs, rc);
+       }
+
        RETURN(0);
 
 out_procfs:
@@ -7884,10 +8068,8 @@ static struct lu_device *osd_device_free(const struct lu_env *env,
        /* XXX: make osd top device in order to release reference */
        d->ld_site->ls_top_dev = d;
        lu_site_purge(env, d->ld_site, -1);
-       if (!cfs_hash_is_empty(d->ld_site->ls_obj_hash)) {
-               LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_ERROR, NULL);
-               lu_site_print(env, d->ld_site, &msgdata, lu_cdebug_printer);
-       }
+       lu_site_print(env, d->ld_site, &d->ld_site->ls_obj_hash.nelems,
+                     D_ERROR, lu_cdebug_printer);
        lu_site_fini(&o->od_site);
        dt_device_fini(&o->od_dt_dev);
        OBD_FREE_PTR(o);
@@ -8059,10 +8241,18 @@ static int osd_prepare(const struct lu_env *env, struct lu_device *pdev,
        RETURN(result);
 }
 
-static int osd_fid_alloc(const struct lu_env *env, struct obd_export *exp,
-                        struct lu_fid *fid, struct md_op_data *op_data)
+/**
+ * Implementation of lu_device_operations::ldo_fid_alloc() for OSD
+ *
+ * Allocate FID.
+ *
+ * see include/lu_object.h for the details.
+ */
+static int osd_fid_alloc(const struct lu_env *env, struct lu_device *d,
+                        struct lu_fid *fid, struct lu_object *parent,
+                        const struct lu_name *name)
 {
-       struct osd_device *osd = osd_dev(exp->exp_obd->obd_lu_dev);
+       struct osd_device *osd = osd_dev(d);
 
        return seq_client_alloc_fid(env, osd->od_cl_seq, fid);
 }
@@ -8081,6 +8271,7 @@ const struct lu_device_operations osd_lu_ops = {
        .ldo_process_config    = osd_process_config,
        .ldo_recovery_complete = osd_recovery_complete,
        .ldo_prepare           = osd_prepare,
+       .ldo_fid_alloc         = osd_fid_alloc,
 };
 
 static const struct lu_device_type_operations osd_device_type_ops = {
@@ -8119,7 +8310,6 @@ static const struct obd_ops osd_obd_device_ops = {
        .o_owner = THIS_MODULE,
        .o_connect      = osd_obd_connect,
        .o_disconnect   = osd_obd_disconnect,
-       .o_fid_alloc    = osd_fid_alloc,
        .o_health_check = osd_health_check,
 };