Whamcloud - gitweb
LU-9846 obd: Add overstriping CONNECT flag
[fs/lustre-release.git] / lustre / llite / llite_lib.c
index 28acbb6..273af31 100644 (file)
@@ -109,6 +109,9 @@ static struct ll_sb_info *ll_init_sbi(void)
 #ifdef ENABLE_CHECKSUM
         sbi->ll_flags |= LL_SBI_CHECKSUM;
 #endif
+#ifdef ENABLE_FLOCK
+       sbi->ll_flags |= LL_SBI_FLOCK;
+#endif
 
 #ifdef HAVE_LRU_RESIZE_SUPPORT
         sbi->ll_flags |= LL_SBI_LRU_RESIZE;
@@ -139,6 +142,9 @@ static struct ll_sb_info *ll_init_sbi(void)
        INIT_LIST_HEAD(&sbi->ll_squash.rsi_nosquash_nids);
        init_rwsem(&sbi->ll_squash.rsi_sem);
 
+       /* Per-filesystem file heat */
+       sbi->ll_heat_decay_weight = SBI_DEFAULT_HEAT_DECAY_WEIGHT;
+       sbi->ll_heat_period_second = SBI_DEFAULT_HEAT_PERIOD_SECOND;
        RETURN(sbi);
 }
 
@@ -218,10 +224,12 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
                                  OBD_CONNECT_GRANT_PARAM |
                                  OBD_CONNECT_SHORTIO | OBD_CONNECT_FLAGS2;
 
-       data->ocd_connect_flags2 = OBD_CONNECT2_FLR |
+       data->ocd_connect_flags2 = OBD_CONNECT2_DIR_MIGRATE |
+                                  OBD_CONNECT2_SUM_STATFS |
+                                  OBD_CONNECT2_FLR |
                                   OBD_CONNECT2_LOCK_CONVERT |
-                                  OBD_CONNECT2_DIR_MIGRATE |
-                                  OBD_CONNECT2_SUM_STATFS;
+                                  OBD_CONNECT2_ARCHIVE_ID_ARRAY |
+                                  OBD_CONNECT2_LSOM;
 
 #ifdef HAVE_LRU_RESIZE_SUPPORT
         if (sbi->ll_flags & LL_SBI_LRU_RESIZE)
@@ -267,10 +275,14 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
 
        obd_connect_set_secctx(data);
 
+#if defined(CONFIG_SECURITY)
+       data->ocd_connect_flags2 |= OBD_CONNECT2_SELINUX_POLICY;
+#endif
+
        data->ocd_brw_size = MD_MAX_BRW_SIZE;
 
        err = obd_connect(NULL, &sbi->ll_md_exp, sbi->ll_md_obd,
-                         &sbi->ll_sb_uuid, data, NULL);
+                         &sbi->ll_sb_uuid, data, sbi->ll_cache);
         if (err == -EBUSY) {
                 LCONSOLE_ERROR_MSG(0x14f, "An MDT (md %s) is performing "
                                    "recovery, of which this client is not a "
@@ -296,7 +308,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
         * can make sure the client can be mounted as long as MDT0 is
         * avaible */
        err = obd_statfs(NULL, sbi->ll_md_exp, osfs,
-                       ktime_get_seconds() -OBD_STATFS_CACHE_SECONDS,
+                       ktime_get_seconds() - OBD_STATFS_CACHE_SECONDS,
                        OBD_STATFS_FOR_MDT0);
        if (err)
                GOTO(out_md_fid, err);
@@ -431,8 +443,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
 
        /* OBD_CONNECT_CKSUM should always be set, even if checksums are
         * disabled by default, because it can still be enabled on the
-        * fly via /proc. As a consequence, we still need to come to an
-        * agreement on the supported algorithms at connect time */
+        * fly via /sys. As a consequence, we still need to come to an
+        * agreement on the supported algorithms at connect time
+        */
        data->ocd_connect_flags |= OBD_CONNECT_CKSUM;
 
        if (OBD_FAIL_CHECK(OBD_FAIL_OSC_CKSUM_ADLER_ONLY))
@@ -457,7 +470,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
        data->ocd_brw_size = DT_MAX_BRW_SIZE;
 
        err = obd_connect(NULL, &sbi->ll_dt_exp, sbi->ll_dt_obd,
-                         &sbi->ll_sb_uuid, data, NULL);
+                         &sbi->ll_sb_uuid, data, sbi->ll_cache);
        if (err == -EBUSY) {
                LCONSOLE_ERROR_MSG(0x150, "An OST (dt %s) is performing "
                                   "recovery, of which this client is not a "
@@ -579,20 +592,12 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
        }
        cl_sb_init(sb);
 
-       err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CACHE_SET),
-                                KEY_CACHE_SET, sizeof(*sbi->ll_cache),
-                                sbi->ll_cache, NULL);
-       if (err) {
-               CERROR("%s: Set cache_set failed: rc = %d\n",
-                      sbi->ll_dt_exp->exp_obd->obd_name, err);
-               GOTO(out_root, err);
-       }
-
        sb->s_root = d_make_root(root);
        if (sb->s_root == NULL) {
-               CERROR("%s: can't make root dentry\n",
-                       ll_get_fsname(sb, NULL, 0));
-               GOTO(out_root, err = -ENOMEM);
+               err = -ENOMEM;
+               CERROR("%s: can't make root dentry: rc = %d\n",
+                      sbi->ll_fsname, err);
+               GOTO(out_root, err);
        }
 #ifdef HAVE_DCACHE_LOCK
        sb->s_root->d_op = &ll_d_ops;
@@ -620,7 +625,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
                                        sbi->ll_dt_obd->obd_type->typ_name);
                if (err < 0) {
                        CERROR("%s: could not register %s in llite: rc = %d\n",
-                              dt, ll_get_fsname(sb, NULL, 0), err);
+                              dt, sbi->ll_fsname, err);
                        err = 0;
                }
        }
@@ -631,7 +636,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
                                        sbi->ll_md_obd->obd_type->typ_name);
                if (err < 0) {
                        CERROR("%s: could not register %s in llite: rc = %d\n",
-                              md, ll_get_fsname(sb, NULL, 0), err);
+                              md, sbi->ll_fsname, err);
                        err = 0;
                }
        }
@@ -673,12 +678,16 @@ int ll_get_max_mdsize(struct ll_sb_info *sbi, int *lmmsize)
                RETURN(rc);
        }
 
+       CDEBUG(D_INFO, "max LOV ea size: %d\n", *lmmsize);
+
        size = sizeof(int);
        rc = obd_get_info(NULL, sbi->ll_md_exp, sizeof(KEY_MAX_EASIZE),
                          KEY_MAX_EASIZE, &size, lmmsize);
        if (rc)
                CERROR("Get max mdsize error rc %d\n", rc);
 
+       CDEBUG(D_INFO, "max LMV ea size: %d\n", *lmmsize);
+
        RETURN(rc);
 }
 
@@ -953,6 +962,7 @@ void ll_lli_init(struct ll_inode_info *lli)
                lli->lli_opendir_pid = 0;
                lli->lli_sa_enabled = 0;
                lli->lli_def_stripe_offset = -1;
+               init_rwsem(&lli->lli_lsm_sem);
        } else {
                mutex_init(&lli->lli_size_mutex);
                lli->lli_symlink_name = NULL;
@@ -963,6 +973,9 @@ void ll_lli_init(struct ll_inode_info *lli)
                INIT_LIST_HEAD(&lli->lli_agl_list);
                lli->lli_agl_index = 0;
                lli->lli_async_rc = 0;
+               spin_lock_init(&lli->lli_heat_lock);
+               obd_heat_clear(lli->lli_heat_instances, OBD_HEAT_COUNT);
+               lli->lli_heat_flags = 0;
        }
        mutex_init(&lli->lli_layout_mutex);
        memset(lli->lli_jobid, 0, sizeof(lli->lli_jobid));
@@ -1013,7 +1026,8 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
        char    *profilenm = get_profile_name(sb);
        struct config_llog_instance *cfg;
        /* %p for void* in printf needs 16+2 characters: 0xffffffffffffffff */
-       const int instlen = sizeof(cfg->cfg_instance) * 2 + 2;
+       const int instlen = 16 + 2;
+       unsigned long cfg_instance = ll_get_cfg_instance(sb);
        char name[MAX_STRING_SIZE];
        int md_len = 0;
        int dt_len = 0;
@@ -1022,40 +1036,55 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
        int err;
 
        ENTRY;
-       CDEBUG(D_VFSTRACE, "VFS Op: sb %p\n", sb);
+       /* for ASLR, to map between cfg_instance and hashed ptr */
+       CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n",
+              profilenm, cfg_instance, sb);
 
        try_module_get(THIS_MODULE);
 
        OBD_ALLOC_PTR(cfg);
        if (cfg == NULL)
-               GOTO(out_free, err = -ENOMEM);
+               GOTO(out_free_cfg, err = -ENOMEM);
 
        /* client additional sb info */
        lsi->lsi_llsbi = sbi = ll_init_sbi();
        if (!sbi)
-               GOTO(out_free, err = -ENOMEM);
+               GOTO(out_free_cfg, err = -ENOMEM);
 
        err = ll_options(lsi->lsi_lmd->lmd_opts, sbi);
        if (err)
-               GOTO(out_free, err);
+               GOTO(out_free_cfg, err);
 
-       err = super_setup_bdi_name(sb, "lustre-%p", sb);
+       err = super_setup_bdi_name(sb, "lustre-%016lx", cfg_instance);
        if (err)
-               GOTO(out_free, err);
+               GOTO(out_free_cfg, err);
 
 #ifndef HAVE_DCACHE_LOCK
        /* kernel >= 2.6.38 store dentry operations in sb->s_d_op. */
        sb->s_d_op = &ll_d_ops;
 #endif
        /* Get fsname */
-       len = strlen(lsi->lsi_lmd->lmd_profile);
-       ptr = strrchr(lsi->lsi_lmd->lmd_profile, '-');
+       len = strlen(profilenm);
+       ptr = strrchr(profilenm, '-');
        if (ptr && (strcmp(ptr, "-client") == 0))
                len -= 7;
 
+       if (len > LUSTRE_MAXFSNAME) {
+               if (unlikely(len >= MAX_STRING_SIZE))
+                       len = MAX_STRING_SIZE - 1;
+               strncpy(name, profilenm, len);
+               name[len] = '\0';
+               err = -ENAMETOOLONG;
+               CERROR("%s: fsname longer than %u characters: rc = %d\n",
+                      name, LUSTRE_MAXFSNAME, err);
+               GOTO(out_free_cfg, err);
+       }
+       strncpy(sbi->ll_fsname, profilenm, len);
+       sbi->ll_fsname[len] = '\0';
+
        /* Mount info */
-       snprintf(name, MAX_STRING_SIZE, "%.*s-%p", len,
-                lsi->lsi_lmd->lmd_profile, sb);
+       snprintf(name, MAX_STRING_SIZE, "%.*s-%016lx", len,
+                profilenm, cfg_instance);
 
        /* Call ll_debugfs_register_super() before lustre_process_log()
         * so that "llite.*.*" params can be processed correctly.
@@ -1063,21 +1092,21 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
        err = ll_debugfs_register_super(sb, name);
        if (err < 0) {
                CERROR("%s: could not register mountpoint in llite: rc = %d\n",
-                      ll_get_fsname(sb, NULL, 0), err);
+                      sbi->ll_fsname, err);
                err = 0;
        }
 
-       /* Generate a string unique to this super, in case some joker tries
-          to mount the same fs at two mount points.
-          Use the address of the super itself.*/
-       cfg->cfg_instance = sb;
+       /* The cfg_instance is a value unique to this super, in case some
+        * joker tries to mount the same fs at two mount points.
+        */
+       cfg->cfg_instance = cfg_instance;
        cfg->cfg_uuid = lsi->lsi_llsbi->ll_sb_uuid;
        cfg->cfg_callback = class_config_llog_handler;
        cfg->cfg_sub_clds = CONFIG_SUB_CLIENT;
        /* set up client obds */
        err = lustre_process_log(sb, profilenm, cfg);
        if (err < 0)
-               GOTO(out_proc, err);
+               GOTO(out_debugfs, err);
 
        /* Profile set with LCFG_MOUNTOPT so we can find our mdc and osc obds */
        lprof = class_get_profile(profilenm);
@@ -1085,7 +1114,7 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
                LCONSOLE_ERROR_MSG(0x156, "The client profile '%s' could not be"
                                   " read from the MGS.  Does that filesystem "
                                   "exist?\n", profilenm);
-               GOTO(out_proc, err = -EINVAL);
+               GOTO(out_debugfs, err = -EINVAL);
        }
        CDEBUG(D_CONFIG, "Found profile %s: mdc=%s osc=%s\n", profilenm,
               lprof->lp_md, lprof->lp_dt);
@@ -1093,34 +1122,38 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
        dt_len = strlen(lprof->lp_dt) + instlen + 2;
        OBD_ALLOC(dt, dt_len);
        if (!dt)
-               GOTO(out_proc, err = -ENOMEM);
-       snprintf(dt, dt_len - 1, "%s-%p", lprof->lp_dt, cfg->cfg_instance);
+               GOTO(out_profile, err = -ENOMEM);
+       snprintf(dt, dt_len - 1, "%s-%016lx", lprof->lp_dt, cfg_instance);
 
        md_len = strlen(lprof->lp_md) + instlen + 2;
        OBD_ALLOC(md, md_len);
        if (!md)
-               GOTO(out_proc, err = -ENOMEM);
-       snprintf(md, md_len - 1, "%s-%p", lprof->lp_md, cfg->cfg_instance);
+               GOTO(out_free_dt, err = -ENOMEM);
+       snprintf(md, md_len - 1, "%s-%016lx", lprof->lp_md, cfg_instance);
 
        /* connections, registrations, sb setup */
        err = client_common_fill_super(sb, md, dt, mnt);
        if (err < 0)
-               GOTO(out_proc, err);
+               GOTO(out_free_md, err);
 
        sbi->ll_client_common_fill_super_succeeded = 1;
 
-out_proc:
-       if (err < 0)
-               ll_debugfs_unregister_super(sb);
-out_free:
+out_free_md:
        if (md)
                OBD_FREE(md, md_len);
+out_free_dt:
        if (dt)
                OBD_FREE(dt, dt_len);
-       if (lprof != NULL)
+out_profile:
+       if (lprof)
                class_put_profile(lprof);
+out_debugfs:
+       if (err < 0)
+               ll_debugfs_unregister_super(sb);
+out_free_cfg:
        if (cfg)
                OBD_FREE_PTR(cfg);
+
        if (err)
                ll_put_super(sb);
        else if (sbi->ll_flags & LL_SBI_VERBOSE)
@@ -1131,23 +1164,26 @@ out_free:
 void ll_put_super(struct super_block *sb)
 {
        struct config_llog_instance cfg, params_cfg;
-        struct obd_device *obd;
-        struct lustre_sb_info *lsi = s2lsi(sb);
-        struct ll_sb_info *sbi = ll_s2sbi(sb);
-        char *profilenm = get_profile_name(sb);
+       struct obd_device *obd;
+       struct lustre_sb_info *lsi = s2lsi(sb);
+       struct ll_sb_info *sbi = ll_s2sbi(sb);
+       char *profilenm = get_profile_name(sb);
+       unsigned long cfg_instance = ll_get_cfg_instance(sb);
        long ccc_count;
        int next, force = 1, rc = 0;
-        ENTRY;
+       ENTRY;
 
        if (!sbi)
                GOTO(out_no_sbi, 0);
 
-        CDEBUG(D_VFSTRACE, "VFS Op: sb %p - %s\n", sb, profilenm);
+       /* Should replace instance_id with something better for ASLR */
+       CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n",
+              profilenm, cfg_instance, sb);
 
-        cfg.cfg_instance = sb;
-        lustre_end_log(sb, profilenm, &cfg);
+       cfg.cfg_instance = cfg_instance;
+       lustre_end_log(sb, profilenm, &cfg);
 
-       params_cfg.cfg_instance = sb;
+       params_cfg.cfg_instance = cfg_instance;
        lustre_end_log(sb, PARAMS_FILENAME, &params_cfg);
 
         if (sbi->ll_md_exp) {
@@ -1168,7 +1204,6 @@ void ll_put_super(struct super_block *sb)
        if (force == 0 && rc != -EINTR)
                LASSERTF(ccc_count == 0, "count: %li\n", ccc_count);
 
-
         /* We need to set force before the lov_disconnect in
            lustre_common_put_super, since l_d cleans up osc's as well. */
         if (force) {
@@ -1265,7 +1300,7 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb,
        inode = iget_locked(sb, ino);
        if (inode == NULL) {
                CERROR("%s: failed get simple inode "DFID": rc = -ENOENT\n",
-                      ll_get_fsname(sb, NULL, 0), PFID(fid));
+                      sbi->ll_fsname, PFID(fid));
                RETURN(ERR_PTR(-ENOENT));
        }
 
@@ -1278,9 +1313,9 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb,
                LASSERTF(S_ISDIR(inode->i_mode), "Not slave inode "DFID"\n",
                         PFID(fid));
 
-               LTIME_S(inode->i_mtime) = 0;
-               LTIME_S(inode->i_atime) = 0;
-               LTIME_S(inode->i_ctime) = 0;
+               inode->i_mtime.tv_sec = 0;
+               inode->i_atime.tv_sec = 0;
+               inode->i_ctime.tv_sec = 0;
                inode->i_rdev = 0;
 
 #ifdef HAVE_BACKING_DEV_INFO
@@ -1308,9 +1343,15 @@ static int ll_init_lsm_md(struct inode *inode, struct lustre_md *md)
 {
        struct lu_fid *fid;
        struct lmv_stripe_md *lsm = md->lmv;
+       struct ll_inode_info *lli = ll_i2info(inode);
        int i;
 
        LASSERT(lsm != NULL);
+
+       CDEBUG(D_INODE, "%s: "DFID" set dir layout:\n",
+              ll_i2sbi(inode)->ll_fsname, PFID(&lli->lli_fid));
+       lsm_md_dump(D_INODE, lsm);
+
        /* XXX sigh, this lsm_root initialization should be in
         * LMV layer, but it needs ll_iget right now, so we
         * put this here right now. */
@@ -1327,10 +1368,16 @@ static int ll_init_lsm_md(struct inode *inode, struct lustre_md *md)
                        int rc = PTR_ERR(lsm->lsm_md_oinfo[i].lmo_root);
 
                        lsm->lsm_md_oinfo[i].lmo_root = NULL;
+                       while (i-- > 0) {
+                               iput(lsm->lsm_md_oinfo[i].lmo_root);
+                               lsm->lsm_md_oinfo[i].lmo_root = NULL;
+                       }
                        return rc;
                }
        }
 
+       lli->lli_lsm_md = lsm;
+
        return 0;
 }
 
@@ -1338,7 +1385,8 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
 {
        struct ll_inode_info *lli = ll_i2info(inode);
        struct lmv_stripe_md *lsm = md->lmv;
-       int     rc;
+       int rc = 0;
+
        ENTRY;
 
        LASSERT(S_ISDIR(inode->i_mode));
@@ -1352,75 +1400,65 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
        if (!lsm)
                RETURN(0);
 
-       /* Compare the old and new stripe information */
+       /*
+        * normally dir layout doesn't change, only take read lock to check
+        * that to avoid blocking other MD operations.
+        */
+       if (lli->lli_lsm_md)
+               down_read(&lli->lli_lsm_sem);
+       else
+               down_write(&lli->lli_lsm_sem);
+
+       /*
+        * if dir layout mismatch, check whether version is increased, which
+        * means layout is changed, this happens in dir migration and lfsck.
+        */
        if (lli->lli_lsm_md && !lsm_md_eq(lli->lli_lsm_md, lsm)) {
-               struct lmv_stripe_md *old_lsm = lli->lli_lsm_md;
-               int idx;
-               bool layout_changed = lsm->lsm_md_layout_version >
-                                     old_lsm->lsm_md_layout_version;
-
-               int mask = layout_changed ? D_INODE : D_ERROR;
-
-               CDEBUG(mask,
-                       "%s: inode@%p "DFID" lmv layout %s magic %#x/%#x "
-                       "stripe count %d/%d master_mdt %d/%d "
-                       "hash_type %#x/%#x version %d/%d migrate offset %d/%d "
-                       "migrate hash %#x/%#x pool %s/%s\n",
-                      ll_get_fsname(inode->i_sb, NULL, 0), inode,
-                      PFID(&lli->lli_fid),
-                      layout_changed ? "changed" : "mismatch",
-                      lsm->lsm_md_magic, old_lsm->lsm_md_magic,
-                      lsm->lsm_md_stripe_count,
-                      old_lsm->lsm_md_stripe_count,
-                      lsm->lsm_md_master_mdt_index,
-                      old_lsm->lsm_md_master_mdt_index,
-                      lsm->lsm_md_hash_type, old_lsm->lsm_md_hash_type,
-                      lsm->lsm_md_layout_version,
-                      old_lsm->lsm_md_layout_version,
-                      lsm->lsm_md_migrate_offset,
-                      old_lsm->lsm_md_migrate_offset,
-                      lsm->lsm_md_migrate_hash,
-                      old_lsm->lsm_md_migrate_hash,
-                      lsm->lsm_md_pool_name,
-                      old_lsm->lsm_md_pool_name);
-
-               for (idx = 0; idx < old_lsm->lsm_md_stripe_count; idx++)
-                       CDEBUG(mask, "old stripe[%d] "DFID"\n",
-                              idx, PFID(&old_lsm->lsm_md_oinfo[idx].lmo_fid));
-
-               for (idx = 0; idx < lsm->lsm_md_stripe_count; idx++)
-                       CDEBUG(mask, "new stripe[%d] "DFID"\n",
-                              idx, PFID(&lsm->lsm_md_oinfo[idx].lmo_fid));
-
-               if (!layout_changed)
-                       RETURN(-EINVAL);
+               if (lsm->lsm_md_layout_version <=
+                   lli->lli_lsm_md->lsm_md_layout_version) {
+                       CERROR("%s: "DFID" dir layout mismatch:\n",
+                              ll_i2sbi(inode)->ll_fsname,
+                              PFID(&lli->lli_fid));
+                       lsm_md_dump(D_ERROR, lli->lli_lsm_md);
+                       lsm_md_dump(D_ERROR, lsm);
+                       GOTO(unlock, rc = -EINVAL);
+               }
 
+               /* layout changed, switch to write lock */
+               up_read(&lli->lli_lsm_sem);
+               down_write(&lli->lli_lsm_sem);
                ll_dir_clear_lsm_md(inode);
        }
 
-       /* set the directory layout */
+       /* set directory layout */
        if (!lli->lli_lsm_md) {
                struct cl_attr  *attr;
 
                rc = ll_init_lsm_md(inode, md);
+               up_write(&lli->lli_lsm_sem);
                if (rc != 0)
                        RETURN(rc);
 
                /* set md->lmv to NULL, so the following free lustre_md
                 * will not free this lsm */
                md->lmv = NULL;
-               lli->lli_lsm_md = lsm;
+
+               /*
+                * md_merge_attr() may take long, since lsm is already set,
+                * switch to read lock.
+                */
+               down_read(&lli->lli_lsm_sem);
 
                OBD_ALLOC_PTR(attr);
                if (attr == NULL)
-                       RETURN(-ENOMEM);
+                       GOTO(unlock, rc = -ENOMEM);
 
                /* validate the lsm */
                rc = md_merge_attr(ll_i2mdexp(inode), lsm, attr,
                                   ll_md_blocking_ast);
                if (rc != 0) {
                        OBD_FREE_PTR(attr);
-                       RETURN(rc);
+                       GOTO(unlock, rc);
                }
 
                if (md->body->mbo_valid & OBD_MD_FLNLINK)
@@ -1435,49 +1473,11 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
                        md->body->mbo_mtime = attr->cat_mtime;
 
                OBD_FREE_PTR(attr);
-
-               CDEBUG(D_INODE, "Set lsm %p magic %x to "DFID"\n", lsm,
-                      lsm->lsm_md_magic, PFID(ll_inode2fid(inode)));
-               RETURN(0);
        }
+unlock:
+       up_read(&lli->lli_lsm_sem);
 
-       /* Compare the old and new stripe information */
-       if (!lsm_md_eq(lli->lli_lsm_md, lsm)) {
-               struct lmv_stripe_md    *old_lsm = lli->lli_lsm_md;
-               int                     idx;
-
-               CERROR("%s: inode "DFID"(%p)'s lmv layout mismatch (%p)/(%p)"
-                      "magic:0x%x/0x%x stripe count: %d/%d master_mdt: %d/%d"
-                      "hash_type:0x%x/0x%x layout: 0x%x/0x%x pool:%s/%s\n",
-                      ll_get_fsname(inode->i_sb, NULL, 0), PFID(&lli->lli_fid),
-                      inode, lsm, old_lsm,
-                      lsm->lsm_md_magic, old_lsm->lsm_md_magic,
-                      lsm->lsm_md_stripe_count,
-                      old_lsm->lsm_md_stripe_count,
-                      lsm->lsm_md_master_mdt_index,
-                      old_lsm->lsm_md_master_mdt_index,
-                      lsm->lsm_md_hash_type, old_lsm->lsm_md_hash_type,
-                      lsm->lsm_md_layout_version,
-                      old_lsm->lsm_md_layout_version,
-                      lsm->lsm_md_pool_name,
-                      old_lsm->lsm_md_pool_name);
-
-               for (idx = 0; idx < old_lsm->lsm_md_stripe_count; idx++) {
-                       CERROR("%s: sub FIDs in old lsm idx %d, old: "DFID"\n",
-                              ll_get_fsname(inode->i_sb, NULL, 0), idx,
-                              PFID(&old_lsm->lsm_md_oinfo[idx].lmo_fid));
-               }
-
-               for (idx = 0; idx < lsm->lsm_md_stripe_count; idx++) {
-                       CERROR("%s: sub FIDs in new lsm idx %d, new: "DFID"\n",
-                              ll_get_fsname(inode->i_sb, NULL, 0), idx,
-                              PFID(&lsm->lsm_md_oinfo[idx].lmo_fid));
-               }
-
-               RETURN(-EIO);
-       }
-
-       RETURN(0);
+       RETURN(rc);
 }
 
 void ll_clear_inode(struct inode *inode)
@@ -1520,7 +1520,6 @@ void ll_clear_inode(struct inode *inode)
 #ifdef CONFIG_FS_POSIX_ACL
        forget_all_cached_acls(inode);
        if (lli->lli_posix_acl) {
-               LASSERT(atomic_read(&lli->lli_posix_acl->a_refcount) == 1);
                posix_acl_release(lli->lli_posix_acl);
                lli->lli_posix_acl = NULL;
        }
@@ -1625,7 +1624,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
 
        CDEBUG(D_VFSTRACE, "%s: setattr inode "DFID"(%p) from %llu to %llu, "
               "valid %x, hsm_import %d\n",
-              ll_get_fsname(inode->i_sb, NULL, 0), PFID(&lli->lli_fid),
+              ll_i2sbi(inode)->ll_fsname, PFID(&lli->lli_fid),
               inode, i_size_read(inode), attr->ia_size, attr->ia_valid,
               hsm_import);
 
@@ -1673,9 +1672,9 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr,
         }
 
         if (attr->ia_valid & (ATTR_MTIME | ATTR_CTIME))
-               CDEBUG(D_INODE, "setting mtime %lu, ctime %lu, now = %llu\n",
-                       LTIME_S(attr->ia_mtime), LTIME_S(attr->ia_ctime),
-                      (s64)ktime_get_real_seconds());
+               CDEBUG(D_INODE, "setting mtime %lld, ctime %lld, now = %lld\n",
+                      (s64)attr->ia_mtime.tv_sec, (s64)attr->ia_ctime.tv_sec,
+                      ktime_get_real_seconds());
 
        if (S_ISREG(inode->i_mode)) {
                if (attr->ia_valid & ATTR_SIZE)
@@ -1817,57 +1816,54 @@ int ll_setattr(struct dentry *de, struct iattr *attr)
 int ll_statfs_internal(struct ll_sb_info *sbi, struct obd_statfs *osfs,
                       u32 flags)
 {
-       struct obd_statfs obd_osfs;
+       struct obd_statfs obd_osfs = { 0 };
        time64_t max_age;
        int rc;
 
        ENTRY;
        max_age = ktime_get_seconds() - OBD_STATFS_CACHE_SECONDS;
 
-        rc = obd_statfs(NULL, sbi->ll_md_exp, osfs, max_age, flags);
-        if (rc) {
-                CERROR("md_statfs fails: rc = %d\n", rc);
-                RETURN(rc);
-        }
+       rc = obd_statfs(NULL, sbi->ll_md_exp, osfs, max_age, flags);
+       if (rc)
+               RETURN(rc);
 
        osfs->os_type = LL_SUPER_MAGIC;
 
        CDEBUG(D_SUPER, "MDC blocks %llu/%llu objects %llu/%llu\n",
-               osfs->os_bavail, osfs->os_blocks, osfs->os_ffree,osfs->os_files);
+             osfs->os_bavail, osfs->os_blocks, osfs->os_ffree, osfs->os_files);
 
        if (osfs->os_state & OS_STATE_SUM)
                GOTO(out, rc);
 
-        if (sbi->ll_flags & LL_SBI_LAZYSTATFS)
-                flags |= OBD_STATFS_NODELAY;
+       if (sbi->ll_flags & LL_SBI_LAZYSTATFS)
+               flags |= OBD_STATFS_NODELAY;
 
        rc = obd_statfs(NULL, sbi->ll_dt_exp, &obd_osfs, max_age, flags);
-        if (rc) {
-                CERROR("obd_statfs fails: rc = %d\n", rc);
-                RETURN(rc);
-        }
+       if (rc) /* Possibly a filesystem with no OSTs.  Report MDT totals. */
+               GOTO(out, rc = 0);
 
        CDEBUG(D_SUPER, "OSC blocks %llu/%llu objects %llu/%llu\n",
-               obd_osfs.os_bavail, obd_osfs.os_blocks, obd_osfs.os_ffree,
-               obd_osfs.os_files);
-
-        osfs->os_bsize = obd_osfs.os_bsize;
-        osfs->os_blocks = obd_osfs.os_blocks;
-        osfs->os_bfree = obd_osfs.os_bfree;
-        osfs->os_bavail = obd_osfs.os_bavail;
-
-        /* If we don't have as many objects free on the OST as inodes
-         * on the MDS, we reduce the total number of inodes to
-         * compensate, so that the "inodes in use" number is correct.
-         */
-        if (obd_osfs.os_ffree < osfs->os_ffree) {
-                osfs->os_files = (osfs->os_files - osfs->os_ffree) +
-                        obd_osfs.os_ffree;
-                osfs->os_ffree = obd_osfs.os_ffree;
-        }
+              obd_osfs.os_bavail, obd_osfs.os_blocks, obd_osfs.os_ffree,
+              obd_osfs.os_files);
+
+       osfs->os_bsize = obd_osfs.os_bsize;
+       osfs->os_blocks = obd_osfs.os_blocks;
+       osfs->os_bfree = obd_osfs.os_bfree;
+       osfs->os_bavail = obd_osfs.os_bavail;
+
+       /* If we have _some_ OSTs, but don't have as many free objects on the
+        * OSTs as inodes on the MDTs, reduce the reported number of inodes
+        * to compensate, so that the "inodes in use" number is correct.
+        * This should be kept in sync with lod_statfs() behaviour.
+        */
+       if (obd_osfs.os_files && obd_osfs.os_ffree < osfs->os_ffree) {
+               osfs->os_files = (osfs->os_files - osfs->os_ffree) +
+                                obd_osfs.os_ffree;
+               osfs->os_ffree = obd_osfs.os_ffree;
+       }
 
 out:
-        RETURN(rc);
+       RETURN(rc);
 }
 int ll_statfs(struct dentry *de, struct kstatfs *sfs)
 {
@@ -1968,24 +1964,25 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md)
        inode->i_generation = cl_fid_build_gen(&body->mbo_fid1);
 
        if (body->mbo_valid & OBD_MD_FLATIME) {
-               if (body->mbo_atime > LTIME_S(inode->i_atime))
-                       LTIME_S(inode->i_atime) = body->mbo_atime;
+               if (body->mbo_atime > inode->i_atime.tv_sec)
+                       inode->i_atime.tv_sec = body->mbo_atime;
                lli->lli_atime = body->mbo_atime;
        }
 
        if (body->mbo_valid & OBD_MD_FLMTIME) {
-               if (body->mbo_mtime > LTIME_S(inode->i_mtime)) {
-                       CDEBUG(D_INODE, "setting ino %lu mtime from %lu "
-                              "to %llu\n", inode->i_ino,
-                              LTIME_S(inode->i_mtime), body->mbo_mtime);
-                       LTIME_S(inode->i_mtime) = body->mbo_mtime;
+               if (body->mbo_mtime > inode->i_mtime.tv_sec) {
+                       CDEBUG(D_INODE,
+                              "setting ino %lu mtime from %lld to %llu\n",
+                              inode->i_ino, (s64)inode->i_mtime.tv_sec,
+                              body->mbo_mtime);
+                       inode->i_mtime.tv_sec = body->mbo_mtime;
                }
                lli->lli_mtime = body->mbo_mtime;
        }
 
        if (body->mbo_valid & OBD_MD_FLCTIME) {
-               if (body->mbo_ctime > LTIME_S(inode->i_ctime))
-                       LTIME_S(inode->i_ctime) = body->mbo_ctime;
+               if (body->mbo_ctime > inode->i_ctime.tv_sec)
+                       inode->i_ctime.tv_sec = body->mbo_ctime;
                lli->lli_ctime = body->mbo_ctime;
        }
 
@@ -2071,11 +2068,12 @@ int ll_read_inode2(struct inode *inode, void *opaque)
         /* Core attributes from the MDS first.  This is a new inode, and
          * the VFS doesn't zero times in the core inode so we have to do
          * it ourselves.  They will be overwritten by either MDS or OST
-         * attributes - we just need to make sure they aren't newer. */
-        LTIME_S(inode->i_mtime) = 0;
-        LTIME_S(inode->i_atime) = 0;
-        LTIME_S(inode->i_ctime) = 0;
-        inode->i_rdev = 0;
+        * attributes - we just need to make sure they aren't newer.
+        */
+       inode->i_mtime.tv_sec = 0;
+       inode->i_atime.tv_sec = 0;
+       inode->i_ctime.tv_sec = 0;
+       inode->i_rdev = 0;
        rc = ll_update_inode(inode, md);
        if (rc != 0)
                RETURN(rc);
@@ -2114,6 +2112,8 @@ int ll_read_inode2(struct inode *inode, void *opaque)
 void ll_delete_inode(struct inode *inode)
 {
        struct ll_inode_info *lli = ll_i2info(inode);
+       struct address_space *mapping = &inode->i_data;
+       unsigned long nrpages;
        ENTRY;
 
        if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL)
@@ -2121,11 +2121,26 @@ void ll_delete_inode(struct inode *inode)
                 * otherwise we may lose data while umount */
                cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, CL_FSYNC_LOCAL, 1);
 
-       truncate_inode_pages_final(&inode->i_data);
+       truncate_inode_pages_final(mapping);
 
-       LASSERTF(inode->i_data.nrpages == 0, "inode="DFID"(%p) nrpages=%lu, "
+       /* Workaround for LU-118: Note nrpages may not be totally updated when
+        * truncate_inode_pages() returns, as there can be a page in the process
+        * of deletion (inside __delete_from_page_cache()) in the specified
+        * range. Thus mapping->nrpages can be non-zero when this function
+        * returns even after truncation of the whole mapping.  Only do this if
+        * npages isn't already zero.
+        */
+       nrpages = mapping->nrpages;
+       if (nrpages) {
+               spin_lock_irq(&mapping->tree_lock);
+               nrpages = mapping->nrpages;
+               spin_unlock_irq(&mapping->tree_lock);
+       } /* Workaround end */
+
+       LASSERTF(nrpages == 0, "%s: inode="DFID"(%p) nrpages=%lu, "
                 "see https://jira.whamcloud.com/browse/LU-118\n",
-                PFID(ll_inode2fid(inode)), inode, inode->i_data.nrpages);
+                ll_i2sbi(inode)->ll_fsname,
+                PFID(ll_inode2fid(inode)), inode, nrpages);
 
 #ifdef HAVE_SBOPS_EVICT_INODE
        ll_clear_inode(inode);
@@ -2353,8 +2368,7 @@ void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req)
        OBD_ALLOC_PTR(op_data);
        if (op_data == NULL) {
                CWARN("%s: cannot allocate op_data to release open handle for "
-                     DFID"\n",
-                     ll_get_fsname(sb, NULL, 0), PFID(&body->mbo_fid1));
+                     DFID"\n", ll_s2sbi(sb)->ll_fsname, PFID(&body->mbo_fid1));
 
                RETURN_EXIT;
        }
@@ -2397,7 +2411,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
                 */
                if (!fid_is_sane(&md.body->mbo_fid1)) {
                        CERROR("%s: Fid is insane "DFID"\n",
-                               ll_get_fsname(sb, NULL, 0),
+                               sbi->ll_fsname,
                                PFID(&md.body->mbo_fid1));
                        GOTO(out, rc = -EINVAL);
                }
@@ -2502,6 +2516,23 @@ out_statfs:
        return rc;
 }
 
+/*
+ * this is normally called in ll_fini_md_op_data(), but sometimes it needs to
+ * be called early to avoid deadlock.
+ */
+void ll_unlock_md_op_lsm(struct md_op_data *op_data)
+{
+       if (op_data->op_mea2_sem) {
+               up_read(op_data->op_mea2_sem);
+               op_data->op_mea2_sem = NULL;
+       }
+
+       if (op_data->op_mea1_sem) {
+               up_read(op_data->op_mea1_sem);
+               op_data->op_mea1_sem = NULL;
+       }
+}
+
 /* this function prepares md_op_data hint for passing it down to MD stack. */
 struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
                                      struct inode *i1, struct inode *i2,
@@ -2531,7 +2562,10 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
        ll_i2gids(op_data->op_suppgids, i1, i2);
        op_data->op_fid1 = *ll_inode2fid(i1);
        op_data->op_default_stripe_offset = -1;
+
        if (S_ISDIR(i1->i_mode)) {
+               down_read(&ll_i2info(i1)->lli_lsm_sem);
+               op_data->op_mea1_sem = &ll_i2info(i1)->lli_lsm_sem;
                op_data->op_mea1 = ll_i2info(i1)->lli_lsm_md;
                if (opc == LUSTRE_OPC_MKDIR)
                        op_data->op_default_stripe_offset =
@@ -2540,8 +2574,14 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
 
        if (i2) {
                op_data->op_fid2 = *ll_inode2fid(i2);
-               if (S_ISDIR(i2->i_mode))
+               if (S_ISDIR(i2->i_mode)) {
+                       if (i2 != i1) {
+                               down_read(&ll_i2info(i2)->lli_lsm_sem);
+                               op_data->op_mea2_sem =
+                                               &ll_i2info(i2)->lli_lsm_sem;
+                       }
                        op_data->op_mea2 = ll_i2info(i2)->lli_lsm_md;
+               }
        } else {
                fid_zero(&op_data->op_fid2);
        }
@@ -2571,6 +2611,7 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data,
 
 void ll_finish_md_op_data(struct md_op_data *op_data)
 {
+       ll_unlock_md_op_lsm(op_data);
        security_release_secctx(op_data->op_file_secctx,
                                op_data->op_file_secctx_size);
         OBD_FREE_PTR(op_data);
@@ -2642,39 +2683,6 @@ int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg)
        RETURN(0);
 }
 
-/**
- * Get lustre file system name by \a sbi. If \a buf is provided(non-NULL), the
- * fsname will be returned in this buffer; otherwise, a static buffer will be
- * used to store the fsname and returned to caller.
- */
-char *ll_get_fsname(struct super_block *sb, char *buf, int buflen)
-{
-       static char fsname_static[MTI_NAME_MAXLEN];
-       struct lustre_sb_info *lsi = s2lsi(sb);
-       char *ptr;
-       int len;
-
-       if (buf == NULL) {
-               /* this means the caller wants to use static buffer
-                * and it doesn't care about race. Usually this is
-                * in error reporting path */
-               buf = fsname_static;
-               buflen = sizeof(fsname_static);
-       }
-
-       len = strlen(lsi->lsi_lmd->lmd_profile);
-       ptr = strrchr(lsi->lsi_lmd->lmd_profile, '-');
-       if (ptr && (strcmp(ptr, "-client") == 0))
-               len -= 7;
-
-       if (unlikely(len >= buflen))
-               len = buflen - 1;
-       strncpy(buf, lsi->lsi_lmd->lmd_profile, len);
-       buf[len] = '\0';
-
-       return buf;
-}
-
 static char* ll_d_path(struct dentry *dentry, char *buf, int bufsize)
 {
        char *path = NULL;
@@ -2705,7 +2713,7 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret)
 
        CDEBUG(D_WARNING,
               "%s: dirty page discard: %s/fid: "DFID"/%s may get corrupted "
-              "(rc %d)\n", ll_get_fsname(page->mapping->host->i_sb, NULL, 0),
+              "(rc %d)\n", ll_i2sbi(inode)->ll_fsname,
               s2lsi(page->mapping->host->i_sb)->lsi_lmd->lmd_dev,
               PFID(ll_inode2fid(inode)),
               (path && !IS_ERR(path)) ? path : "", ioret);