os_partial_scan:1,
os_in_join:1,
os_running:1, /* scrub thread is running */
- os_full_scrub:1;
+ os_full_scrub:1,
+ os_has_ml_file:1;
};
#define INDEX_BACKUP_MAGIC_V1 0x1E41F208
struct dt_object *child,
const char *name, const char *name2,
__u16 type, bool update, bool dec);
-int lfsck_verify_linkea(const struct lu_env *env, struct dt_object *obj,
- const struct lu_name *cname, const struct lu_fid *pfid);
+int lfsck_verify_linkea(const struct lu_env *env, struct lfsck_instance *lfsck,
+ struct dt_object *obj, const struct lu_name *cname,
+ const struct lu_fid *pfid);
int lfsck_links_get_first(const struct lu_env *env, struct dt_object *obj,
char *name, struct lu_fid *pfid);
int lfsck_update_name_entry(const struct lu_env *env,
if (atomic_dec_and_test(&lso->lso_ref))
OBD_FREE_PTR(lso);
}
+
+static inline struct thandle*
+lfsck_trans_create(const struct lu_env *env, struct dt_device *dev,
+ struct lfsck_instance *lfsck)
+{
+ if (lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN) {
+ CERROR("%s: transaction is being created in DRYRUN mode!\n",
+ lfsck_lfsck2name(lfsck));
+
+ dump_stack();
+ return ERR_PTR(-EINVAL);
+ }
+
+ return dt_trans_create(env, dev);
+}
#endif /* _LFSCK_INTERNAL_H */
memset(dof, 0, sizeof(*dof));
dof->dof_type = dt_mode_to_dft(S_IFREG);
- th = dt_trans_create(env, dt);
+ th = lfsck_trans_create(env, dt, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
continue;
}
- th = dt_trans_create(env, dt);
+ th = lfsck_trans_create(env, dt, lfsck);
if (IS_ERR(th)) {
rc1 = PTR_ERR(th);
CDEBUG(D_LFSCK, "%s: layout LFSCK failed to store "
mutex_lock(&com->lc_sub_trace_objs[idx].lsto_mutex);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
mutex_lock(&com->lc_sub_trace_objs[idx].lsto_mutex);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
}
static int __lfsck_layout_update_pfid(const struct lu_env *env,
+ struct lfsck_component *com,
struct dt_object *child,
const struct lu_fid *pfid,
const struct ost_layout *ol, __u32 offset,
ff->ff_range = cpu_to_le32(range);
lfsck_buf_init(&buf, ff, sizeof(*ff));
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(handle))
RETURN(PTR_ERR(handle));
if (IS_ERR(child))
RETURN(PTR_ERR(child));
- rc = __lfsck_layout_update_pfid(env, child,
+ rc = __lfsck_layout_update_pfid(env, com, child,
lu_object_fid(&parent->do_lu),
&rec->lor_layout, ea_off,
rec->lor_layout_version,
GOTO(unlock, rc);
/* The 1st transaction. */
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
th = NULL;
/* The 2nd transaction. */
- rc = __lfsck_layout_update_pfid(env, cobj, pfid,
+ rc = __lfsck_layout_update_pfid(env, com, cobj, pfid,
&rec->lor_layout, ea_off,
rec->lor_layout_version,
rec->lor_range);
if (la->la_ctime != 0)
GOTO(unlock, rc = -ETXTBSY);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
if (lfsck_is_dryrun(com->lc_lfsck))
GOTO(unlock, rc = 0);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
}
if (!(bk->lb_param & LPF_DRYRUN)) {
- handle = dt_trans_create(env, dt);
+ handle = lfsck_trans_create(env, dt, lfsck);
if (IS_ERR(handle))
GOTO(unlock_layout, rc = PTR_ERR(handle));
GOTO(unlock1, rc);
buf = lfsck_buf_get(env, ff, sizeof(struct filter_fid));
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(unlock1, rc = PTR_ERR(handle));
buf = lfsck_buf_get(env, ff, sizeof(*ff));
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(handle))
GOTO(unlock1, rc = PTR_ERR(handle));
memset(dof, 0, sizeof(*dof));
dev = lfsck_obj2dev(child);
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(log, rc = PTR_ERR(handle));
if (IS_ERR(parent))
GOTO(log, rc = PTR_ERR(parent));
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(log, rc = PTR_ERR(handle));
tla->la_uid = pla->la_uid;
tla->la_gid = pla->la_gid;
tla->la_valid = LA_UID | LA_GID;
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(handle))
GOTO(log, rc = PTR_ERR(handle));
lfsck_is_dead_obj(obj)))
GOTO(unlock, rc = 0);
- rc = __lfsck_layout_update_pfid(env, obj, &lrl->lrl_ff_client.ff_parent,
+ rc = __lfsck_layout_update_pfid(env, com, obj,
+ &lrl->lrl_ff_client.ff_parent,
&lrl->lrl_ff_client.ff_layout,
lrl->lrl_ff_client.ff_layout_version,
lrl->lrl_ff_client.ff_range,
if (rc != 0)
GOTO(out, rc);
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(out, rc = PTR_ERR(handle));
}
static void lfsck_layout_destroy_orphan(const struct lu_env *env,
+ struct lfsck_instance *lfsck,
struct dt_object *obj)
{
struct dt_device *dev = lfsck_obj2dev(obj);
int rc;
ENTRY;
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
RETURN_EXIT;
* OST-object there. Destroy it now! */
if (unlikely(!(la->la_mode & S_ISUID))) {
dt_read_unlock(env, obj);
- lfsck_layout_destroy_orphan(env, obj);
+ lfsck_layout_destroy_orphan(env, lfsck, obj);
lfsck_object_put(env, obj);
pos++;
goto again1;
if (rc != 0)
RETURN(rc);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
if (rc != 0)
RETURN(rc);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
RETURN(PTR_ERR(th));
/* Transaction I: locally */
dev = lfsck_obj2dev(child);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
RETURN(PTR_ERR(th));
/* Transaction II: remotely */
dev = lfsck_obj2dev(parent);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
RETURN(PTR_ERR(th));
}
cname = lfsck_name_get_const(env, name, strlen(name));
- rc = lfsck_verify_linkea(env, child, cname, &LU_LPF_FID);
+ rc = lfsck_verify_linkea(env, lfsck, child, cname, &LU_LPF_FID);
if (rc == 0)
rc = lfsck_update_lpf_entry(env, lfsck, parent, child,
name, type);
}
cname = lfsck_name_get_const(env, name, strlen(name));
- rc = lfsck_verify_linkea(env, child2, cname, &LU_LPF_FID);
+ rc = lfsck_verify_linkea(env, lfsck, child2, cname,
+ &LU_LPF_FID);
GOTO(put, rc);
}
cname = lfsck_name_get_const(env, dotlustre,
strlen(dotlustre));
- rc = lfsck_verify_linkea(env, obj, cname,
+ rc = lfsck_verify_linkea(env, lfsck, obj, cname,
&lfsck->li_global_root_fid);
if (rc != 0)
GOTO(out, rc);
cname = lfsck_name_get_const(env, lostfound,
strlen(lostfound));
- rc = lfsck_verify_linkea(env, obj, cname, pfid);
+ rc = lfsck_verify_linkea(env, lfsck, obj, cname, pfid);
if (rc != 0)
GOTO(out, rc);
GOTO(log, rc);
}
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
LASSERT(dt_object_remote(obj) == 0);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
lfsck_buf_init(&linkea_buf, ldata2.ld_buf->lb_buf,
ldata2.ld_leh->leh_len);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
ENTRY;
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
RETURN(PTR_ERR(th));
ENTRY;
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
RETURN(PTR_ERR(th));
if (unlikely(!dt_try_as_dir(env, parent)))
GOTO(unlock, rc = -ENOTDIR);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
if (rc != 0)
GOTO(unlock1, rc);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock1, rc = PTR_ERR(th));
}
again:
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock1, rc = PTR_ERR(th));
if (lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
GOTO(log, rc = 1);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
int rc = 0;
ENTRY;
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
if (rc != 0)
GOTO(log, rc);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock1, rc = PTR_ERR(th));
lfsck_buf_init(&linkea_buf, ldata.ld_buf->lb_buf,
ldata.ld_leh->leh_len);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
if (rc != 0)
GOTO(log, rc);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
if (rc != 0)
GOTO(log, rc);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
if (rc)
GOTO(out, rc);
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(unlock, rc = PTR_ERR(handle));
* the MDT-object without stripes (dof->dof_reg.striped = 0). related
* OST-objects will be created when write open. */
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock_child, rc = PTR_ERR(th));
if (rc != 0)
GOTO(out, rc);
- handle = dt_trans_create(env, dev);
+ handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(out, rc = PTR_ERR(handle));
GOTO(out, rc);
}
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(out, rc = PTR_ERR(th));
* \retval 0 for success
* \retval negative error number on failure
*/
-int lfsck_verify_linkea(const struct lu_env *env, struct dt_object *obj,
- const struct lu_name *cname, const struct lu_fid *pfid)
+int lfsck_verify_linkea(const struct lu_env *env, struct lfsck_instance *lfsck,
+ struct dt_object *obj, const struct lu_name *cname,
+ const struct lu_fid *pfid)
{
struct dt_device *dev = lfsck_obj2dev(obj);
struct linkea_data ldata = { NULL };
lfsck_buf_init(&linkea_buf, ldata.ld_buf->lb_buf,
ldata.ld_leh->leh_len);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
RETURN(PTR_ERR(th));
if (rc != 0)
RETURN(rc);
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
int rc = 0;
ENTRY;
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
GOTO(log, rc);
}
- th = dt_trans_create(env, dev);
+ th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
return rc;
}
-static int osd_obj_del_entry(struct osd_thread_info *info,
- struct osd_device *osd,
- struct dentry *dird, char *name,
- handle_t *th)
+int osd_obj_del_entry(struct osd_thread_info *info, struct osd_device *osd,
+ struct dentry *dird, char *name, int namelen,
+ handle_t *th)
{
struct ldiskfs_dir_entry_2 *de;
struct buffer_head *bh;
child = &info->oti_child_dentry;
child->d_name.hash = 0;
child->d_name.name = name;
- child->d_name.len = strlen(name);
+ child->d_name.len = namelen;
child->d_parent = dird;
child->d_inode = NULL;
fid_seq_is_idif(seq) ? 0 : seq);
}
-static inline void osd_oid_name(char *name, size_t name_size,
- const struct lu_fid *fid, u64 id)
-{
- snprintf(name, name_size,
- (fid_seq_is_rsvd(fid_seq(fid)) ||
- fid_seq_is_mdt0(fid_seq(fid)) ||
- fid_seq_is_idif(fid_seq(fid))) ? "%llu" : "%llx", id);
-}
-
/* external locking is required */
static int osd_seq_load_locked(struct osd_thread_info *info,
struct osd_device *osd,
RETURN(rc);
}
-static struct osd_obj_seq *osd_seq_load(struct osd_thread_info *info,
- struct osd_device *osd, u64 seq)
+struct osd_obj_seq *osd_seq_load(struct osd_thread_info *info,
+ struct osd_device *osd, u64 seq)
{
struct osd_obj_map *map;
struct osd_obj_seq *osd_seq;
LASSERT(d);
osd_oid_name(name, sizeof(name), fid, ostid_id(ostid));
- rc = osd_obj_del_entry(info, osd, d, name, th);
+ rc = osd_obj_del_entry(info, osd, d, name, strlen(name), th);
cleanup:
RETURN(rc);
}
}
};
-
-/**
- * Creates or initializes iterator context.
- *
- * \retval struct osd_it_ea, iterator structure on success
- *
- */
-static struct dt_it *osd_it_ea_init(const struct lu_env *env,
- struct dt_object *dt,
- __u32 attr)
+struct osd_it_ea *osd_it_dir_init(const struct lu_env *env,
+ struct inode *inode, __u32 attr)
{
- struct osd_object *obj = osd_dt_obj(dt);
struct osd_thread_info *info = osd_oti_get(env);
struct osd_it_ea *oie;
struct file *file;
- struct lu_object *lo = &dt->do_lu;
struct dentry *obj_dentry;
ENTRY;
- if (!dt_object_exists(dt) || obj->oo_destroyed)
- RETURN(ERR_PTR(-ENOENT));
-
OBD_SLAB_ALLOC_PTR_GFP(oie, osd_itea_cachep, GFP_NOFS);
if (oie == NULL)
RETURN(ERR_PTR(-ENOMEM));
obj_dentry = &oie->oie_dentry;
- obj_dentry->d_inode = obj->oo_inode;
- obj_dentry->d_sb = osd_sb(osd_obj2dev(obj));
+ obj_dentry->d_inode = inode;
+ obj_dentry->d_sb = inode->i_sb;
obj_dentry->d_name.hash = 0;
oie->oie_rd_dirent = 0;
if (oie->oie_buf == NULL)
RETURN(ERR_PTR(-ENOMEM));
}
- oie->oie_obj = obj;
+ oie->oie_obj = NULL;
file = &oie->oie_file;
else
file->f_mode = FMODE_32BITHASH;
file->f_path.dentry = obj_dentry;
- file->f_mapping = obj->oo_inode->i_mapping;
- file->f_op = obj->oo_inode->i_fop;
- file->f_inode = obj->oo_inode;
+ file->f_mapping = inode->i_mapping;
+ file->f_op = inode->i_fop;
+ file->f_inode = inode;
+
+ RETURN(oie);
+}
+/**
+ * Creates or initializes iterator context.
+ *
+ * \retval struct osd_it_ea, iterator structure on success
+ *
+ */
+static struct dt_it *osd_it_ea_init(const struct lu_env *env,
+ struct dt_object *dt,
+ __u32 attr)
+{
+ struct osd_object *obj = osd_dt_obj(dt);
+ struct lu_object *lo = &dt->do_lu;
+ struct osd_it_ea *oie;
+
+ ENTRY;
+
+ if (!dt_object_exists(dt) || obj->oo_destroyed)
+ RETURN(ERR_PTR(-ENOENT));
+
+ oie = osd_it_dir_init(env, obj->oo_inode, attr);
+ if (IS_ERR(oie))
+ RETURN((struct dt_it *)oie);
+
+ oie->oie_obj = obj;
lu_object_get(lo);
RETURN((struct dt_it *)oie);
}
+void osd_it_dir_fini(const struct lu_env *env, struct osd_it_ea *oie,
+ struct inode *inode)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+
+ ENTRY;
+ oie->oie_file.f_op->release(inode, &oie->oie_file);
+ if (unlikely(oie->oie_buf != info->oti_it_ea_buf))
+ OBD_FREE(oie->oie_buf, OSD_IT_EA_BUFSIZE);
+ else
+ info->oti_it_ea_buf_used = 0;
+ OBD_SLAB_FREE_PTR(oie, osd_itea_cachep);
+ EXIT;
+}
+
/**
* Destroy or finishes iterator context.
*
*/
static void osd_it_ea_fini(const struct lu_env *env, struct dt_it *di)
{
- struct osd_thread_info *info = osd_oti_get(env);
struct osd_it_ea *oie = (struct osd_it_ea *)di;
struct osd_object *obj = oie->oie_obj;
struct inode *inode = obj->oo_inode;
ENTRY;
- oie->oie_file.f_op->release(inode, &oie->oie_file);
+ osd_it_dir_fini(env, (struct osd_it_ea *)di, inode);
osd_object_put(env, obj);
- if (unlikely(oie->oie_buf != info->oti_it_ea_buf))
- OBD_FREE(oie->oie_buf, OSD_IT_EA_BUFSIZE);
- else
- info->oti_it_ea_buf_used = 0;
- OBD_SLAB_FREE_PTR(oie, osd_itea_cachep);
EXIT;
}
/* "." is just the object itself. */
if (namelen == 1 && name[0] == '.') {
- *fid = obj->oo_dt.do_lu.lo_header->loh_fid;
+ if (obj != NULL)
+ *fid = obj->oo_dt.do_lu.lo_header->loh_fid;
} else if (d_type & LDISKFS_DIRENT_LUFID) {
rec = (struct osd_fid_pack *)(name + namelen + 1);
if (osd_fid_unpack(fid, rec) != 0)
d_type &= ~LDISKFS_DIRENT_LUFID;
/* NOT export local root. */
- if (unlikely(osd_sb(osd_obj2dev(obj))->s_root->d_inode->i_ino == ino)) {
+ if (obj != NULL &&
+ unlikely(osd_sb(osd_obj2dev(obj))->s_root->d_inode->i_ino == ino)) {
ino = obj->oo_inode->i_ino;
*fid = obj->oo_dt.do_lu.lo_header->loh_fid;
}
* \retval -ve on error
* \retval +1 reach the end of entry
*/
-static int osd_ldiskfs_it_fill(const struct lu_env *env,
- const struct dt_it *di)
+int osd_ldiskfs_it_fill(const struct lu_env *env, const struct dt_it *di)
{
struct osd_it_ea *it = (struct osd_it_ea *)di;
struct osd_object *obj = it->oie_obj;
- struct inode *inode = obj->oo_inode;
struct htree_lock *hlock = NULL;
struct file *filp = &it->oie_file;
int rc = 0;
it->oie_dirent = it->oie_buf;
it->oie_rd_dirent = 0;
- if (obj->oo_hl_head != NULL) {
- hlock = osd_oti_get(env)->oti_hlock;
- ldiskfs_htree_lock(hlock, obj->oo_hl_head,
- inode, LDISKFS_HLOCK_READDIR);
- } else {
- down_read(&obj->oo_ext_idx_sem);
+ if (obj) {
+ if (obj->oo_hl_head != NULL) {
+ hlock = osd_oti_get(env)->oti_hlock;
+ ldiskfs_htree_lock(hlock, obj->oo_hl_head,
+ obj->oo_inode,
+ LDISKFS_HLOCK_READDIR);
+ } else {
+ down_read(&obj->oo_ext_idx_sem);
+ }
}
filp->f_cred = current_cred();
it->oie_it_dirent = 1;
}
unlock:
- if (hlock != NULL)
- ldiskfs_htree_unlock(hlock);
- else
- up_read(&obj->oo_ext_idx_sem);
+ if (obj) {
+ if (hlock != NULL)
+ ldiskfs_htree_unlock(hlock);
+ else
+ up_read(&obj->oo_ext_idx_sem);
+ }
RETURN(rc);
}
struct page **oti_dio_pages;
int oti_dio_pages_used;
+
+ struct osd_it_ea_dirent *oti_seq_dirent;
+ struct osd_it_ea_dirent *oti_dir_dirent;
};
extern int ldiskfs_pdo;
return ll_vfs_setxattr(dentry, inode, name, buf, buflen, fl);
}
+static inline char *osd_oid_name(char *name, size_t name_size,
+ const struct lu_fid *fid, u64 id)
+{
+ snprintf(name, name_size,
+ (fid_seq_is_rsvd(fid_seq(fid)) ||
+ fid_seq_is_mdt0(fid_seq(fid)) ||
+ fid_seq_is_idif(fid_seq(fid))) ? "%llu" : "%llx", id);
+
+ return name;
+}
+
#ifdef CONFIG_PROC_FS
/* osd_lproc.c */
extern struct lprocfs_vars lprocfs_osd_obd_vars[];
struct osd_inode_id *id, struct lu_fid *fid);
int osd_ea_fid_set(struct osd_thread_info *info, struct inode *inode,
const struct lu_fid *fid, __u32 compat, __u32 incompat);
+struct osd_obj_seq *osd_seq_load(struct osd_thread_info *info,
+ struct osd_device *osd, u64 seq);
int osd_get_lma(struct osd_thread_info *info, struct inode *inode,
struct dentry *dentry, struct lustre_ost_attrs *loa);
void osd_add_oi_cache(struct osd_thread_info *info, struct osd_device *osd,
struct osd_inode_id *id, const struct lu_fid *fid);
int osd_get_idif(struct osd_thread_info *info, struct inode *inode,
struct dentry *dentry, struct lu_fid *fid);
+struct osd_it_ea *osd_it_dir_init(const struct lu_env *env, struct inode *inode,
+ __u32 attr);
+void osd_it_dir_fini(const struct lu_env *env, struct osd_it_ea *oie,
+ struct inode *inode);
+int osd_ldiskfs_it_fill(const struct lu_env *env, const struct dt_it *di);
int osd_obj_map_init(const struct lu_env *env, struct osd_device *osd);
void osd_obj_map_fini(struct osd_device *dev);
int osd_obj_spec_update(struct osd_thread_info *info, struct osd_device *osd,
const struct lu_fid *fid, const struct osd_inode_id *id,
handle_t *th);
+int osd_obj_del_entry(struct osd_thread_info *info, struct osd_device *osd,
+ struct dentry *dird, char *name, int namelen,
+ handle_t *th);
char *osd_lf_fid2name(const struct lu_fid *fid);
int osd_scrub_start(const struct lu_env *env, struct osd_device *dev,
RETURN(rc);
}
+ if (dev->od_is_ost && S_ISREG(inode->i_mode) && inode->i_nlink > 1)
+ dev->od_scrub.os_scrub.os_has_ml_file = 1;
+
/* It is an EA inode, no OI mapping for it, skip it. */
if (osd_is_ea_inode(inode))
GOTO(put, rc = SCRUB_NEXT_CONTINUE);
RETURN(rc < 0 ? rc : ooc->ooc_cached_items);
}
+static int osd_scan_ml_file_main(const struct lu_env *env,
+ struct osd_device *dev);
+
static int osd_scrub_main(void *args)
{
struct lu_env env;
struct osd_device *dev = (struct osd_device *)args;
struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
- int rc;
+ int rc, ret;
ENTRY;
rc = lu_env_init(&env, LCT_LOCAL | LCT_DT_THREAD);
GOTO(out, rc = -EINVAL);
}
+ if (scrub->os_has_ml_file) {
+ ret = osd_scan_ml_file_main(&env, dev);
+ if (ret != 0)
+ rc = ret;
+ }
+
GOTO(post, rc);
post:
list_del_init(&oii->oii_list);
OBD_FREE_PTR(oii);
}
+
lu_env_fini(&env);
noenv:
scrub->os_lf_repaired,
scrub->os_lf_failed);
}
+
+typedef int (*scan_dir_helper_t)(const struct lu_env *env,
+ struct osd_device *dev, struct inode *dir,
+ struct osd_it_ea *oie);
+
+static int osd_scan_dir(const struct lu_env *env, struct osd_device *dev,
+ struct inode *inode, scan_dir_helper_t cb)
+{
+ struct osd_it_ea *oie;
+ int rc;
+
+ ENTRY;
+
+ oie = osd_it_dir_init(env, inode, LUDA_TYPE);
+ if (IS_ERR(oie))
+ RETURN(PTR_ERR(oie));
+
+ oie->oie_file.f_pos = 0;
+ rc = osd_ldiskfs_it_fill(env, (struct dt_it *)oie);
+ if (rc > 0)
+ rc = -ENODATA;
+ if (rc)
+ GOTO(out, rc);
+
+ while (oie->oie_it_dirent <= oie->oie_rd_dirent) {
+ if (!name_is_dot_or_dotdot(oie->oie_dirent->oied_name,
+ oie->oie_dirent->oied_namelen))
+ cb(env, dev, inode, oie);
+
+ oie->oie_dirent = (void *)oie->oie_dirent +
+ cfs_size_round(sizeof(struct osd_it_ea_dirent) +
+ oie->oie_dirent->oied_namelen);
+
+ oie->oie_it_dirent++;
+ if (oie->oie_it_dirent <= oie->oie_rd_dirent)
+ continue;
+
+ if (oie->oie_file.f_pos ==
+ ldiskfs_get_htree_eof(&oie->oie_file))
+ break;
+
+ rc = osd_ldiskfs_it_fill(env, (struct dt_it *)oie);
+ if (rc) {
+ if (rc > 0)
+ rc = 0;
+ break;
+ }
+ }
+
+out:
+ osd_it_dir_fini(env, oie, inode);
+ RETURN(rc);
+}
+
+static int osd_remove_ml_file(struct osd_thread_info *info,
+ struct osd_device *dev, struct inode *dir,
+ struct inode *inode, struct osd_it_ea *oie)
+{
+ handle_t *th;
+ struct lustre_scrub *scrub = &dev->od_scrub.os_scrub;
+ struct dentry *dentry;
+ int rc;
+
+ ENTRY;
+
+ if (scrub->os_file.sf_param & SP_DRYRUN)
+ RETURN(0);
+
+ th = osd_journal_start_sb(osd_sb(dev), LDISKFS_HT_MISC,
+ osd_dto_credits_noquota[DTO_INDEX_DELETE] +
+ osd_dto_credits_noquota[DTO_ATTR_SET_BASE]);
+ if (IS_ERR(th))
+ RETURN(PTR_ERR(th));
+
+ dentry = &oie->oie_dentry;
+ dentry->d_inode = dir;
+ dentry->d_sb = dir->i_sb;
+ rc = osd_obj_del_entry(info, dev, dentry, oie->oie_dirent->oied_name,
+ oie->oie_dirent->oied_namelen, th);
+ drop_nlink(inode);
+ mark_inode_dirty(inode);
+ ldiskfs_journal_stop(th);
+ RETURN(rc);
+}
+
+static int osd_scan_ml_file(const struct lu_env *env, struct osd_device *dev,
+ struct inode *dir, struct osd_it_ea *oie)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct osd_inode_id id;
+ struct inode *inode;
+ struct osd_obj_seq *oseq;
+ struct ost_id *ostid = &info->oti_ostid;
+ struct lu_fid *fid = &oie->oie_dirent->oied_fid;
+ char name[32];
+ int dirn, rc = 0;
+
+ ENTRY;
+
+ osd_id_gen(&id, oie->oie_dirent->oied_ino, OSD_OII_NOGEN);
+
+ if (!fid_is_sane(fid))
+ inode = osd_iget_fid(info, dev, &id, fid);
+ else
+ inode = osd_iget(info, dev, &id);
+
+ if (IS_ERR(inode))
+ RETURN(PTR_ERR(inode));
+
+ fid_to_ostid(fid, ostid);
+ oseq = osd_seq_load(info, dev, ostid_seq(ostid));
+ if (IS_ERR(oseq))
+ RETURN(PTR_ERR(oseq));
+
+ dirn = ostid_id(ostid) & (oseq->oos_subdir_count - 1);
+ LASSERT(oseq->oos_dirs[dirn] != NULL);
+
+ osd_oid_name(name, sizeof(name), fid, ostid_id(ostid));
+ if (((strlen(oseq->oos_root->d_name.name) !=
+ info->oti_seq_dirent->oied_namelen) ||
+ strncmp(oseq->oos_root->d_name.name,
+ info->oti_seq_dirent->oied_name,
+ info->oti_seq_dirent->oied_namelen) != 0) ||
+ ((strlen(oseq->oos_dirs[dirn]->d_name.name) !=
+ info->oti_dir_dirent->oied_namelen) ||
+ strncmp(oseq->oos_dirs[dirn]->d_name.name,
+ info->oti_dir_dirent->oied_name,
+ info->oti_dir_dirent->oied_namelen) != 0) ||
+ ((strlen(name) != oie->oie_dirent->oied_namelen) ||
+ strncmp(oie->oie_dirent->oied_name, name,
+ oie->oie_dirent->oied_namelen) != 0)) {
+ CDEBUG(D_LFSCK, "%s: the file O/%s/%s/%s is corrupted\n",
+ osd_name(dev), info->oti_seq_dirent->oied_name,
+ info->oti_dir_dirent->oied_name,
+ oie->oie_dirent->oied_name);
+
+ rc = osd_remove_ml_file(info, dev, dir, inode, oie);
+ }
+
+ iput(inode);
+ RETURN(rc);
+}
+
+static int osd_scan_ml_file_dir(const struct lu_env *env,
+ struct osd_device *dev, struct inode *dir,
+ struct osd_it_ea *oie)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct inode *inode;
+ struct osd_inode_id id;
+ int rc;
+
+ ENTRY;
+
+ osd_id_gen(&id, oie->oie_dirent->oied_ino, OSD_OII_NOGEN);
+ inode = osd_iget(info, dev, &id);
+ if (IS_ERR(inode))
+ RETURN(PTR_ERR(inode));
+
+ if (!S_ISDIR(inode->i_mode))
+ GOTO(out, rc = 0);
+
+ info->oti_dir_dirent = oie->oie_dirent;
+ rc = osd_scan_dir(env, dev, inode, osd_scan_ml_file);
+ info->oti_dir_dirent = NULL;
+
+out:
+ iput(inode);
+ RETURN(rc);
+}
+
+static int osd_scan_ml_file_seq(const struct lu_env *env,
+ struct osd_device *dev, struct inode *dir,
+ struct osd_it_ea *oie)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct inode *inode;
+ struct osd_inode_id id;
+ int rc;
+
+ ENTRY;
+
+ osd_id_gen(&id, oie->oie_dirent->oied_ino, OSD_OII_NOGEN);
+ inode = osd_iget(info, dev, &id);
+ if (IS_ERR(inode))
+ RETURN(PTR_ERR(inode));
+
+ if (!S_ISDIR(inode->i_mode))
+ GOTO(out, rc = 0);
+
+ info->oti_seq_dirent = oie->oie_dirent;
+ rc = osd_scan_dir(env, dev, inode, osd_scan_ml_file_dir);
+ info->oti_seq_dirent = NULL;
+
+out:
+ iput(inode);
+ RETURN(rc);
+}
+
+static int osd_scan_ml_file_main(const struct lu_env *env,
+ struct osd_device *dev)
+{
+ return osd_scan_dir(env, dev, dev->od_ost_map->om_root->d_inode,
+ osd_scan_ml_file_seq);
+}
OZI_POS_REAL = 3, /* cursor at real entries */
};
+/*
+ * regular ZFS direntry
+ */
+struct zpl_direntry {
+ uint64_t zde_dnode:48,
+ zde_pad:12,
+ zde_type:4;
+} __attribute__((packed));
+
+/*
+ * lustre direntry adds a fid to regular ZFS direntry
+ */
+struct luz_direntry {
+ struct zpl_direntry lzd_reg;
+ struct lu_fid lzd_fid;
+} __attribute__((packed));
+
/**
* Iterator's in-memory data structure for ZAPs
*
struct osd_object *ozi_obj;
unsigned ozi_reset:1; /* 1 -- no need to advance */
/* ozi_pos - position of the cursor */
- enum osd_zap_pos ozi_pos;
+ enum osd_zap_pos ozi_pos;
+ struct luz_direntry ozi_zde;
+ zap_attribute_t ozi_za;
union {
char ozi_name[MAXNAMELEN]; /* file name for dir */
__u64 ozi_key; /* binary key for index files */
};
#define DT_IT2DT(it) (&((struct osd_zap_it *)it)->ozi_obj->oo_dt)
-/*
- * regular ZFS direntry
- */
-struct zpl_direntry {
- uint64_t zde_dnode:48,
- zde_pad:12,
- zde_type:4;
-} __attribute__((packed));
-
-/*
- * lustre direntry adds a fid to regular ZFS direntry
- */
-struct luz_direntry {
- struct zpl_direntry lzd_reg;
- struct lu_fid lzd_fid;
-} __attribute__((packed));
-
-
/* cached SA attributes */
struct osa_attr {
uint64_t mode;
struct lu_buf oti_xattr_lbuf;
zap_cursor_t oti_zc;
zap_cursor_t oti_zc2;
+
+ char *oti_seq_name;
+ char *oti_dir_name;
};
extern struct lu_context_key osd_key;
GOTO(out, rc);
out:
+ if (dev->od_is_ost) {
+ sa_handle_t *hdl;
+ uint64_t nlink, mode;
+
+ rc = -sa_handle_get(dev->od_os, oid, NULL, SA_HDL_PRIVATE,
+ &hdl);
+ if (rc)
+ GOTO(cleanup, rc);
+
+ rc = -sa_lookup(hdl, SA_ZPL_MODE(dev), &mode, sizeof(mode));
+ if (rc || !S_ISREG(mode)) {
+ sa_handle_destroy(hdl);
+ GOTO(cleanup, rc);
+ }
+
+ rc = -sa_lookup(hdl, SA_ZPL_LINKS(dev), &nlink, sizeof(nlink));
+ if (rc == 0 && nlink > 1)
+ scrub->os_has_ml_file = 1;
+
+ sa_handle_destroy(hdl);
+ }
+
+cleanup:
if (nvbuf)
nvlist_free(nvbuf);
return 0;
}
+static int osd_scan_ml_file_main(const struct lu_env *env,
+ struct osd_device *dev);
+
static int osd_scrub_main(void *args)
{
struct lu_env env;
struct lustre_scrub *scrub = &dev->od_scrub;
struct lu_fid *fid;
uint64_t oid;
- int rc = 0;
+ int rc = 0, ret;
ENTRY;
rc = lu_env_init(&env, LCT_LOCAL | LCT_DT_THREAD);
GOTO(post, rc);
post:
+ if (scrub->os_has_ml_file) {
+ ret = osd_scan_ml_file_main(&env, dev);
+ if (ret != 0)
+ rc = ret;
+ }
+
rc = osd_scrub_post(&env, dev, rc);
CDEBUG(D_LFSCK, "%s: OI scrub: stop, pos = %llu: rc = %d\n",
scrub->os_name, scrub->os_pos_current, rc);
RETURN(ret);
}
+
+typedef int (*scan_dir_helper_t)(const struct lu_env *env,
+ struct osd_device *dev, uint64_t dir_oid,
+ struct osd_zap_it *ozi);
+
+static int osd_scan_dir(const struct lu_env *env, struct osd_device *dev,
+ uint64_t id, scan_dir_helper_t cb)
+{
+ struct osd_zap_it *it;
+ struct luz_direntry *zde;
+ zap_attribute_t *za;
+ int rc;
+
+ ENTRY;
+
+ OBD_SLAB_ALLOC_PTR_GFP(it, osd_zapit_cachep, GFP_NOFS);
+ if (it == NULL)
+ RETURN(-ENOMEM);
+
+ rc = osd_zap_cursor_init(&it->ozi_zc, dev->od_os, id, 0);
+ if (rc != 0)
+ GOTO(out, rc);
+
+ za = &it->ozi_za;
+ zde = &it->ozi_zde;
+ while (1) {
+ rc = -zap_cursor_retrieve(it->ozi_zc, za);
+ if (unlikely(rc)) {
+ if (rc == -ENOENT)
+ rc = 0;
+
+ break;
+ }
+
+ if (name_is_dot_or_dotdot(za->za_name, strlen(za->za_name))) {
+ zap_cursor_advance(it->ozi_zc);
+ continue;
+ }
+
+ strncpy(it->ozi_name, za->za_name, sizeof(it->ozi_name));
+ if (za->za_integer_length != 8) {
+ rc = -EIO;
+ break;
+ }
+
+ rc = osd_zap_lookup(dev, it->ozi_zc->zc_zapobj, NULL,
+ za->za_name, za->za_integer_length,
+ sizeof(*zde) / za->za_integer_length, zde);
+ if (rc)
+ break;
+
+ rc = cb(env, dev, id, it);
+ if (rc)
+ break;
+
+ zap_cursor_advance(it->ozi_zc);
+ }
+ osd_zap_cursor_fini(it->ozi_zc);
+
+out:
+ OBD_SLAB_FREE_PTR(it, osd_zapit_cachep);
+ RETURN(rc);
+}
+
+static int osd_remove_ml_file(const struct lu_env *env, struct osd_device *dev,
+ uint64_t dir, uint64_t id, struct lu_fid *fid,
+ char *name)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct dt_object *dt;
+ struct osd_object *obj = NULL;
+ dmu_tx_t *tx;
+ sa_handle_t *hdl;
+ uint64_t nlink;
+ int rc;
+
+ rc = -sa_handle_get(dev->od_os, id, NULL, SA_HDL_PRIVATE, &hdl);
+ if (rc)
+ RETURN(rc);
+
+ dt = lu2dt(lu_object_find_slice(env, osd2lu_dev(dev), fid, NULL));
+ if (IS_ERR(dt))
+ RETURN(PTR_ERR(dt));
+
+ if (dt) {
+ obj = osd_dt_obj(dt);
+ down_read(&obj->oo_guard);
+ }
+
+ rc = -sa_lookup(hdl, SA_ZPL_LINKS(dev), &nlink, sizeof(nlink));
+ if (rc)
+ GOTO(out, rc);
+
+ if (nlink <= 1) {
+ CERROR("%s: multi-link file O/%s/%s/%s has nlink %llu\n",
+ osd_name(dev), info->oti_seq_name, info->oti_dir_name,
+ name, nlink);
+ GOTO(out, rc = 0);
+ }
+
+ tx = dmu_tx_create(dev->od_os);
+ if (!tx) {
+ CERROR("%s: fail to create tx to remove multi-link file!\n",
+ osd_name(dev));
+ GOTO(out, rc = -ENOMEM);
+ }
+
+ dmu_tx_hold_zap(tx, dir, FALSE, NULL);
+ rc = -dmu_tx_assign(tx, TXG_WAIT);
+ if (rc)
+ GOTO(abort, rc);
+
+ nlink--;
+ rc = -sa_update(hdl, SA_ZPL_LINKS(dev), &nlink, sizeof(nlink), tx);
+ if (rc)
+ GOTO(abort, rc);
+
+ rc = -zap_remove(dev->od_os, dir, name, tx);
+ if (rc)
+ GOTO(abort, rc);
+
+ dmu_tx_commit(tx);
+ GOTO(out, rc);
+
+abort:
+ dmu_tx_abort(tx);
+
+out:
+ if (dt) {
+ up_read(&obj->oo_guard);
+ dt_object_put_nocache(env, dt);
+ }
+
+ sa_handle_destroy(hdl);
+ RETURN(rc);
+}
+
+static int osd_scan_ml_file(const struct lu_env *env, struct osd_device *dev,
+ uint64_t dir_oid, struct osd_zap_it *ozi)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct lu_fid *fid = &info->oti_fid;
+ struct ost_id *ostid = &info->oti_ostid;
+ char name[32];
+ u64 seq;
+ int rc = 0;
+
+ ENTRY;
+
+ rc = osd_get_fid_by_oid(env, dev, ozi->ozi_zde.lzd_reg.zde_dnode, fid);
+ if (rc)
+ RETURN(rc);
+
+ seq = fid_seq(fid);
+ fid_to_ostid(fid, ostid);
+
+ snprintf(name, sizeof(name), (fid_seq_is_rsvd(seq) ||
+ fid_seq_is_mdt0(seq)) ? "%llu" : "%llx",
+ fid_seq_is_idif(seq) ? 0 : seq);
+ if (strcmp(info->oti_seq_name, name) != 0)
+ GOTO(fix, rc);
+
+ snprintf(name, sizeof(name), "d%d",
+ (int)ostid_id(ostid) % OSD_OST_MAP_SIZE);
+ if (strcmp(info->oti_dir_name, name) != 0)
+ GOTO(fix, rc);
+
+ snprintf(name, sizeof(name), "%llu", ostid_id(ostid));
+ if (strcmp(ozi->ozi_name, name) == 0)
+ RETURN(0);
+
+fix:
+ CDEBUG(D_LFSCK, "%s: the file O/%s/%s/%s is corrupted\n",
+ osd_name(dev), info->oti_seq_name, info->oti_dir_name,
+ ozi->ozi_name);
+
+ rc = osd_remove_ml_file(env, dev, dir_oid,
+ ozi->ozi_zde.lzd_reg.zde_dnode, fid,
+ ozi->ozi_name);
+ RETURN(rc);
+}
+
+static int osd_scan_ml_file_dir(const struct lu_env *env,
+ struct osd_device *dev, uint64_t dir_oid,
+ struct osd_zap_it *ozi)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+
+ if (!S_ISDIR(cpu_to_le16(DTTOIF(ozi->ozi_zde.lzd_reg.zde_type))))
+ return 0;
+
+ info->oti_dir_name = ozi->ozi_name;
+ return osd_scan_dir(env, dev, ozi->ozi_zde.lzd_reg.zde_dnode,
+ osd_scan_ml_file);
+}
+
+static int osd_scan_ml_file_seq(const struct lu_env *env,
+ struct osd_device *dev, uint64_t dir_oid,
+ struct osd_zap_it *ozi)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+
+ if (!S_ISDIR(cpu_to_le16(DTTOIF(ozi->ozi_zde.lzd_reg.zde_type))))
+ return 0;
+
+ info->oti_seq_name = ozi->ozi_name;
+ return osd_scan_dir(env, dev, ozi->ozi_zde.lzd_reg.zde_dnode,
+ osd_scan_ml_file_dir);
+}
+
+static int osd_scan_ml_file_main(const struct lu_env *env,
+ struct osd_device *dev)
+{
+ return osd_scan_dir(env, dev, dev->od_O_id, osd_scan_ml_file_seq);
+}
}
run_test 18 "test mount -o resetoi to recreate OI files"
+test_19() {
+ local rcmd="do_facet ost${ost}"
+
+ check_mount_and_prep
+ $LFS setstripe -c 1 -i 0 $DIR/$tdir
+ createmany -o $DIR/$tdir/f 64 || error "(0) Fail to create 32 files."
+
+ echo "stopall"
+ stopall > /dev/null
+
+ # create mulitple link file
+ mount_fstype ost1 || error "(1) Fail to mount ost1"
+ mntpt=$(facet_mntpt ost1)
+
+ local path=$mntpt/O/0/d2
+ local file=$(${rcmd} ls $path | awk '{print $0; exit}')
+
+ # create link to the first file
+ echo "link $path/1 to $path/$file"
+ ${rcmd} ln $path/$file $path/1
+ unmount_fstype ost1 || error "(2) Fail to umount ost1"
+
+ start ost1 $(ostdevname 1) $MOUNT_OPTS_NOSCRUB > /dev/null ||
+ error "(2) Fail to start ost1"
+
+ $START_SCRUB_ON_OST -r || error "(3) Fail to start OI scrub on OST!"
+
+ wait_update_facet ost1 "$LCTL get_param -n \
+ osd-*.$(facet_svc ost1).oi_scrub |
+ awk '/^status/ { print \\\$2 }'" "completed" 6 ||
+ error "(4) Expected '$expected' on ost1"
+
+ stop ost1
+ mount_fstype ost1 || error "(5) Fail to mount ost1"
+ links=$(do_facet ost1 "stat $path/$file" | awk '/Links:/ { print $6 }')
+ unmount_fstype ost1 || error "(6) Fail to umount ost1"
+
+ start ost1 $(ostdevname 1) $MOUNT_OPTS_NOSCRUB > /dev/null ||
+ error "(7) Fail to start ost1"
+
+ (( links == 1)) || error "(8) object links $links != 1 after scrub"
+}
+run_test 19 "LFSCK can fix multiple linked files on OST"
+
# restore MDS/OST size
MDSSIZE=${SAVED_MDSSIZE}
OSTSIZE=${SAVED_OSTSIZE}