};
struct lustre_scrub {
- struct lu_object_header os_obj_header;
/* Object for the scrub file. */
struct dt_object *os_obj;
}
/* utility to make a directory */
-static struct dentry *simple_mkdir(struct dentry *dir, struct vfsmount *mnt,
- const char *name, int mode, int fix)
+static struct dentry *
+simple_mkdir(const struct lu_env *env, struct osd_device *osd,
+ struct dentry *dir, const struct lu_fid *fid,
+ const char *name, __u32 compat, int mode, bool *created)
{
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct lu_fid *tfid = &info->oti_fid3;
+ struct inode *inode;
struct dentry *dchild;
int err = 0;
ENTRY;
CDEBUG(D_INODE, "creating directory %.*s\n", (int)strlen(name), name);
dchild = ll_lookup_one_len(name, dir, strlen(name));
if (IS_ERR(dchild))
- GOTO(out_up, dchild);
+ RETURN(dchild);
+
+ inode = dchild->d_inode;
+ if (inode) {
+ struct lustre_mdt_attrs *lma = &info->oti_ost_attrs.loa_lma;
+ int old_mode = inode->i_mode;
+
+ if (created)
+ *created = false;
- if (dchild->d_inode) {
- int old_mode = dchild->d_inode->i_mode;
if (!S_ISDIR(old_mode)) {
CERROR("found %s (%lu/%u) is mode %o\n", name,
- dchild->d_inode->i_ino,
- dchild->d_inode->i_generation, old_mode);
+ inode->i_ino, inode->i_generation, old_mode);
GOTO(out_err, err = -ENOTDIR);
}
+ if (unlikely(osd->od_dt_dev.dd_rdonly))
+ RETURN(dchild);
+
/* Fixup directory permissions if necessary */
- if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
+ if ((old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
CDEBUG(D_CONFIG,
"fixing permissions on %s from %o to %o\n",
name, old_mode, mode);
- dchild->d_inode->i_mode = (mode & S_IALLUGO) |
- (old_mode & ~S_IALLUGO);
- mark_inode_dirty(dchild->d_inode);
+ inode->i_mode = (mode & S_IALLUGO) |
+ (old_mode & ~S_IALLUGO);
+ mark_inode_dirty(inode);
}
- GOTO(out_up, dchild);
+
+ err = osd_get_lma(info, inode, &info->oti_obj_dentry,
+ &info->oti_ost_attrs);
+ if (err == -ENODATA)
+ goto set_fid;
+
+ if (err)
+ GOTO(out_err, err);
+
+ if ((fid && !lu_fid_eq(fid, &lma->lma_self_fid)) ||
+ lma->lma_compat != compat)
+ goto set_fid;
+
+ RETURN(dchild);
}
err = vfs_mkdir(dir->d_inode, dchild, mode);
if (err)
GOTO(out_err, err);
+ inode = dchild->d_inode;
+ if (created)
+ *created = true;
+
+set_fid:
+ if (fid)
+ *tfid = *fid;
+ else
+ lu_igif_build(tfid, inode->i_ino, inode->i_generation);
+ err = osd_ea_fid_set(info, inode, tfid, compat, 0);
+ if (err)
+ GOTO(out_err, err);
+
RETURN(dchild);
out_err:
dput(dchild);
- dchild = ERR_PTR(err);
-out_up:
- return dchild;
+ return ERR_PTR(err);
}
static int osd_last_rcvd_subdir_count(struct osd_device *osd)
parent = osd_sb(dev)->s_root;
osd_push_ctxt(dev, &new, &save);
- d = simple_mkdir(parent, dev->od_mnt, REMOTE_PARENT_DIR,
- 0755, 1);
+ lu_local_obj_fid(fid, REMOTE_PARENT_DIR_OID);
+ d = simple_mkdir(env, dev, parent, fid, REMOTE_PARENT_DIR,
+ LMAC_NOT_IN_OI, 0755, NULL);
if (IS_ERR(d))
GOTO(cleanup, rc = PTR_ERR(d));
omm->omm_remote_parent = d;
- /* Set LMA for remote parent inode */
- lu_local_obj_fid(fid, REMOTE_PARENT_DIR_OID);
- rc = osd_ea_fid_set(info, d->d_inode, fid, LMAC_NOT_IN_OI, 0);
-
- GOTO(cleanup, rc);
+ GOTO(cleanup, rc = 0);
cleanup:
pop_ctxt(&save, &new);
*/
static int osd_ost_init(const struct lu_env *env, struct osd_device *dev)
{
- struct lvfs_run_ctxt new;
- struct lvfs_run_ctxt save;
- struct dentry *rootd = osd_sb(dev)->s_root;
- struct dentry *d;
- struct osd_thread_info *info = osd_oti_get(env);
- struct inode *inode;
- struct lu_fid *fid = &info->oti_fid3;
- int rc;
+ struct lvfs_run_ctxt new;
+ struct lvfs_run_ctxt save;
+ struct dentry *d;
+ int rc;
+ bool created = false;
ENTRY;
OBD_ALLOC_PTR(dev->od_ost_map);
GOTO(cleanup_alloc, rc);
dev->od_ost_map->om_subdir_count = rc;
- rc = 0;
-
INIT_LIST_HEAD(&dev->od_ost_map->om_seq_list);
rwlock_init(&dev->od_ost_map->om_seq_list_lock);
mutex_init(&dev->od_ost_map->om_dir_init_mutex);
- osd_push_ctxt(dev, &new, &save);
-
- d = ll_lookup_one_len("O", rootd, strlen("O"));
+ osd_push_ctxt(dev, &new, &save);
+ d = simple_mkdir(env, dev, osd_sb(dev)->s_root, NULL, "O",
+ LMAC_NOT_IN_OI | LMAC_FID_ON_OST, 0755, &created);
if (IS_ERR(d))
GOTO(cleanup_ctxt, rc = PTR_ERR(d));
- if (d->d_inode == NULL) {
- dput(d);
- /* The lookup() may be called again inside simple_mkdir().
- * Since the repeated lookup() only be called for "/O" at
- * mount time, it will not affect the whole performance. */
- d = simple_mkdir(rootd, dev->od_mnt, "O", 0755, 1);
- if (IS_ERR(d))
- GOTO(cleanup_ctxt, rc = PTR_ERR(d));
+ if (created)
/* It is quite probably that the device is new formatted. */
dev->od_maybe_new = 1;
- }
- inode = d->d_inode;
dev->od_ost_map->om_root = d;
- /* 'What the @fid is' is not imporatant, because the object
- * has no OI mapping, and only is visible inside the OSD.*/
- lu_igif_build(fid, inode->i_ino, inode->i_generation);
- rc = osd_ea_fid_set(info, inode, fid,
- LMAC_NOT_IN_OI | LMAC_FID_ON_OST, 0);
- if (rc)
- GOTO(cleanup_dentry, rc);
-
pop_ctxt(&save, &new);
RETURN(0);
-cleanup_dentry:
- dput(d);
cleanup_ctxt:
pop_ctxt(&save, &new);
cleanup_alloc:
EXIT;
}
+static int osd_index_backup_dir_init(const struct lu_env *env,
+ struct osd_device *dev)
+{
+ struct lu_fid *fid = &osd_oti_get(env)->oti_fid;
+ struct lvfs_run_ctxt new;
+ struct lvfs_run_ctxt save;
+ struct dentry *dentry;
+ int rc = 0;
+ ENTRY;
+
+ lu_local_obj_fid(fid, INDEX_BACKUP_OID);
+ osd_push_ctxt(dev, &new, &save);
+ dentry = simple_mkdir(env, dev, osd_sb(dev)->s_root, fid,
+ INDEX_BACKUP_DIR, LMAC_NOT_IN_OI, 0755, NULL);
+ if (IS_ERR(dentry)) {
+ rc = PTR_ERR(dentry);
+ } else {
+ dev->od_index_backup_inode = igrab(dentry->d_inode);
+ dput(dentry);
+ }
+ pop_ctxt(&save, &new);
+
+ RETURN(rc);
+}
+
+static void osd_index_backup_dir_fini(struct osd_device *dev)
+{
+ if (dev->od_index_backup_inode) {
+ iput(dev->od_index_backup_inode);
+ dev->od_index_backup_inode = NULL;
+ }
+}
+
int osd_obj_map_init(const struct lu_env *env, struct osd_device *dev)
{
int rc;
+ bool ost_init = false;
+ bool mdt_init = false;
ENTRY;
- /* prepare structures for OST */
rc = osd_ost_init(env, dev);
if (rc)
RETURN(rc);
- /* prepare structures for MDS */
+ ost_init = true;
rc = osd_mdt_init(env, dev);
- if (rc)
- osd_ost_fini(dev);
+ if (!rc) {
+ mdt_init = true;
+ rc = osd_index_backup_dir_init(env, dev);
+ }
- RETURN(rc);
+ if (rc) {
+ if (ost_init)
+ osd_ost_fini(dev);
+ if (mdt_init)
+ osd_mdt_fini(dev);
+ }
+
+ RETURN(rc);
}
static struct osd_obj_seq *osd_seq_find_locked(struct osd_obj_map *map, u64 seq)
void osd_obj_map_fini(struct osd_device *dev)
{
+ osd_index_backup_dir_fini(dev);
osd_ost_fini(dev);
osd_mdt_fini(dev);
}
{
struct osd_obj_map *map = osd->od_ost_map;
struct dentry *seq_dir;
- struct inode *inode;
- struct lu_fid *fid = &info->oti_fid3;
int rc = 0;
int i;
char dir_name[32];
osd_seq_name(dir_name, sizeof(dir_name), osd_seq->oos_seq);
- seq_dir = simple_mkdir(map->om_root, osd->od_mnt, dir_name, 0755, 1);
+ seq_dir = simple_mkdir(info->oti_env, osd, map->om_root, NULL, dir_name,
+ LMAC_NOT_IN_OI | LMAC_FID_ON_OST, 0755, NULL);
if (IS_ERR(seq_dir))
GOTO(out_err, rc = PTR_ERR(seq_dir));
else if (seq_dir->d_inode == NULL)
GOTO(out_put, rc = -EFAULT);
- inode = seq_dir->d_inode;
osd_seq->oos_root = seq_dir;
- /* 'What the @fid is' is not imporatant, because the object
- * has no OI mapping, and only is visible inside the OSD.*/
- lu_igif_build(fid, inode->i_ino, inode->i_generation);
- rc = osd_ea_fid_set(info, inode, fid,
- LMAC_NOT_IN_OI | LMAC_FID_ON_OST, 0);
- if (rc != 0)
- GOTO(out_put, rc);
-
LASSERT(osd_seq->oos_dirs == NULL);
OBD_ALLOC(osd_seq->oos_dirs,
sizeof(seq_dir) * osd_seq->oos_subdir_count);
struct dentry *dir;
snprintf(dir_name, sizeof(dir_name), "d%u", i);
- dir = simple_mkdir(osd_seq->oos_root, osd->od_mnt, dir_name,
- 0700, 1);
+ dir = simple_mkdir(info->oti_env, osd, osd_seq->oos_root, NULL,
+ dir_name, LMAC_NOT_IN_OI | LMAC_FID_ON_OST,
+ 0700, NULL);
if (IS_ERR(dir)) {
GOTO(out_free, rc = PTR_ERR(dir));
} else if (dir->d_inode == NULL) {
GOTO(out_free, rc = -EFAULT);
}
- inode = dir->d_inode;
osd_seq->oos_dirs[i] = dir;
-
- /* 'What the @fid is' is not imporatant, because the object
- * has no OI mapping, and only is visible inside the OSD.*/
- lu_igif_build(fid, inode->i_ino, inode->i_generation);
- rc = osd_ea_fid_set(info, inode, fid,
- LMAC_NOT_IN_OI | LMAC_FID_ON_OST, 0);
- if (rc != 0)
- GOTO(out_free, rc);
}
if (rc != 0) {
if (mo != NULL) {
struct lu_object *l;
struct lu_object_header *h;
+ struct osd_device *o = osd_dev(d);
l = &mo->oo_dt.do_lu;
- h = &osd_dev(d)->od_scrub.os_scrub.os_obj_header;
- if (unlikely(fid_is_zero(&h->loh_fid))) {
- /* For the OI_scrub object during OSD device init. */
+ if (unlikely(o->od_in_init)) {
+ OBD_ALLOC_PTR(h);
+ if (!h) {
+ OBD_FREE_PTR(mo);
+ return NULL;
+ }
+
lu_object_header_init(h);
lu_object_init(l, h, d);
lu_object_add_top(h, l);
+ mo->oo_header = h;
} else {
dt_object_init(&mo->oo_dt, NULL, d);
+ mo->oo_header = NULL;
}
+
mo->oo_dt.do_ops = &osd_obj_ops;
l->lo_ops = &osd_lu_obj_ops;
init_rwsem(&mo->oo_sem);
}
-static struct inode *
+struct inode *
osd_iget_fid(struct osd_thread_info *info, struct osd_device *dev,
struct osd_inode_id *id, struct lu_fid *fid)
{
goto found;
check_lma:
- result = osd_check_lma(env, obj);
checked = true;
+ if (unlikely(obj->oo_header))
+ goto found;
+
+ result = osd_check_lma(env, obj);
if (!result)
goto found;
}
result = osd_fid_lookup(env, obj, lu_object_fid(l), conf);
- if (unlikely(l->lo_header ==
- &osd_obj2dev(obj)->od_scrub.os_scrub.os_obj_header)) {
- /* For the OI_scrub object during OSD device init. */
- l->lo_header->loh_attr |= LOHA_EXISTS;
- obj->oo_dt.do_body_ops = &osd_body_ops;
- } else {
- obj->oo_dt.do_body_ops = &osd_body_ops_new;
- }
+ obj->oo_dt.do_body_ops = &osd_body_ops_new;
if (result == 0 && obj->oo_inode != NULL) {
struct osd_thread_info *oti = osd_oti_get(env);
struct lustre_ost_attrs *loa = &oti->oti_ost_attrs;
osd_object_init0(obj);
+ if (unlikely(obj->oo_header))
+ return 0;
+
result = osd_get_lma(oti, obj->oo_inode,
&oti->oti_obj_dentry, loa);
if (!result) {
static void osd_object_free(const struct lu_env *env, struct lu_object *l)
{
struct osd_object *obj = osd_obj(l);
- struct lu_object_header *h = NULL;
+ struct lu_object_header *h = obj->oo_header;
LINVRNT(osd_invariant(obj));
- if (unlikely(l->lo_header ==
- &osd_obj2dev(obj)->od_scrub.os_scrub.os_obj_header))
- h = l->lo_header;
-
osd_oxc_fini(obj);
dt_object_fini(&obj->oo_dt);
if (obj->oo_hl_head != NULL)
ldiskfs_htree_lock_head_free(obj->oo_hl_head);
OBD_FREE_PTR(obj);
- if (unlikely(h))
+ if (unlikely(h)) {
lu_object_header_fini(h);
+ OBD_FREE_PTR(h);
+ }
}
/*
qid_t uid = i_uid_read(inode);
qid_t gid = i_gid_read(inode);
- iput(inode);
- obj->oo_inode = NULL;
-
- if (qsd != NULL) {
+ obj->oo_inode = NULL;
+ iput(inode);
+ if (!obj->oo_header && qsd) {
struct osd_thread_info *info = osd_oti_get(env);
struct lquota_id_info *qi = &info->oti_qi;
dt->do_index_ops = &osd_acct_index_ops;
result = 0;
skip_iam = 1;
- } else if (!osd_has_index(obj)) {
- struct osd_directory *dir;
+ } else if (!osd_has_index(obj)) {
+ struct osd_directory *dir;
+ struct osd_device *osd = osd_obj2dev(obj);
+ const struct lu_fid *fid = lu_object_fid(&dt->do_lu);
- OBD_ALLOC_PTR(dir);
- if (dir != NULL) {
+ OBD_ALLOC_PTR(dir);
+ if (dir) {
spin_lock(&obj->oo_guard);
if (obj->oo_dir == NULL)
/*
* recheck under lock.
*/
- if (!osd_has_index(obj))
- result = osd_iam_container_init(env, obj,
- obj->oo_dir);
- else
+
+ if (osd_has_index(obj)) {
result = 0;
+ goto unlock;
+ }
+
+ result = osd_iam_container_init(env, obj, obj->oo_dir);
+ if (result || feat == &dt_lfsck_namespace_features ||
+ feat == &dt_lfsck_layout_orphan_features ||
+ feat == &dt_lfsck_layout_dangling_features)
+ goto unlock;
+
+ result = osd_index_register(osd, fid,
+ feat->dif_keysize_max,
+ feat->dif_recsize_max);
+ if (result < 0)
+ CWARN("%s: failed to register index "
+ DFID": rc = %d\n",
+ osd_name(osd), PFID(fid), result);
+ else if (result > 0)
+ result = 0;
+ else
+ CDEBUG(D_LFSCK, "%s: index object "DFID
+ " (%d/%d) registered\n",
+ osd_name(osd), PFID(fid),
+ (int)feat->dif_keysize_max,
+ (int)feat->dif_recsize_max);
+
+unlock:
up_write(&obj->oo_ext_idx_sem);
} else {
result = -ENOMEM;
/* shutdown quota slave instance associated with the device */
if (o->od_quota_slave != NULL) {
- qsd_fini(env, o->od_quota_slave);
+ struct qsd_instance *qsd = o->od_quota_slave;
+
o->od_quota_slave = NULL;
+ qsd_fini(env, qsd);
}
osd_fid_fini(env, o);
spin_lock_init(&o->od_osfs_lock);
mutex_init(&o->od_otable_mutex);
INIT_LIST_HEAD(&o->od_orphan_list);
+ INIT_LIST_HEAD(&o->od_index_backup_list);
+ INIT_LIST_HEAD(&o->od_index_restore_list);
+ spin_lock_init(&o->od_lock);
+ o->od_index_backup_policy = LIBP_NONE;
o->od_read_cache = 1;
o->od_writethrough_cache = 1;
GOTO(out, rc);
}
+ o->od_index_backup_stop = 0;
o->od_index = -1; /* -1 means index is invalid */
rc = server_name2index(o->od_svname, &o->od_index, NULL);
if (rc == LDD_F_SV_TYPE_OST)
INIT_LIST_HEAD(&o->od_ios_list);
/* setup scrub, including OI files initialization */
+ o->od_in_init = 1;
rc = osd_scrub_setup(env, o);
+ o->od_in_init = 0;
if (rc < 0)
GOTO(out_site, rc);
rc = osd_mount(env, o, cfg);
break;
case LCFG_CLEANUP:
+ /* For the case LCFG_PRE_CLEANUP is not called in advance,
+ * that may happend if hit failure during mount process. */
+ osd_index_backup(env, o, false);
lu_dev_del_linkage(d->ld_site, d);
rc = osd_shutdown(env, o);
break;
rc = 0;
}
break;
+ case LCFG_PRE_CLEANUP:
+ osd_index_backup(env, o,
+ o->od_index_backup_policy != LIBP_NONE);
+ rc = 0;
+ break;
default:
rc = -ENOSYS;
}
#endif
struct list_head oo_xattr_list;
+ struct lu_object_header *oo_header;
};
struct osd_obj_seq {
od_igif_inoi:1,
od_check_ff:1,
od_is_ost:1,
+ od_in_init:1,
od_index_in_idif:1;
__s64 od_auto_scrub_interval;
/* a list of orphaned agent inodes, protected with od_osfs_lock */
struct list_head od_orphan_list;
+ struct list_head od_index_backup_list;
+ struct list_head od_index_restore_list;
+ spinlock_t od_lock;
+ struct inode *od_index_backup_inode;
+ enum lustre_index_backup_policy od_index_backup_policy;
+ int od_index_backup_stop;
};
enum osd_full_scrub_ratio {
unsigned int oti_declare_ops[OSD_OT_MAX];
unsigned int oti_declare_ops_cred[OSD_OT_MAX];
unsigned int oti_declare_ops_used[OSD_OT_MAX];
+ struct osd_directory oti_iam;
};
extern int ldiskfs_pdo;
struct obd_statfs *sfs);
struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
struct osd_inode_id *id);
+struct inode *
+osd_iget_fid(struct osd_thread_info *info, struct osd_device *dev,
+ 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);
int osd_get_lma(struct osd_thread_info *info, struct inode *inode,
void osd_fini_iobuf(struct osd_device *d, struct osd_iobuf *iobuf);
+static inline int
+osd_index_register(struct osd_device *osd, const struct lu_fid *fid,
+ __u32 keysize, __u32 recsize)
+{
+ return lustre_index_register(&osd->od_dt_dev, osd_name(osd),
+ &osd->od_index_backup_list, &osd->od_lock,
+ &osd->od_index_backup_stop,
+ fid, keysize, recsize);
+}
+
+static inline void
+osd_index_backup(const struct lu_env *env, struct osd_device *osd, bool backup)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct lu_fid *fid = &info->oti_fid3;
+ struct osd_inode_id *id = &info->oti_id3;
+
+ lu_local_obj_fid(fid, INDEX_BACKUP_OID);
+ osd_id_gen(id, osd->od_index_backup_inode->i_ino,
+ osd->od_index_backup_inode->i_generation);
+ osd_add_oi_cache(info, osd, id, fid);
+
+ lustre_index_backup(env, &osd->od_dt_dev, osd_name(osd),
+ &osd->od_index_backup_list, &osd->od_lock,
+ &osd->od_index_backup_stop, backup);
+}
#endif /* _OSD_INTERNAL_H */
}
#endif
+static int ldiskfs_osd_index_backup_seq_show(struct seq_file *m, void *data)
+{
+ struct osd_device *dev = osd_dt_dev((struct dt_device *)m->private);
+
+ LASSERT(dev != NULL);
+ if (unlikely(dev->od_mnt == NULL))
+ return -EINPROGRESS;
+
+ seq_printf(m, "%d\n", dev->od_index_backup_policy);
+ return 0;
+}
+
+static ssize_t ldiskfs_osd_index_backup_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
+{
+ struct seq_file *m = file->private_data;
+ struct dt_device *dt = m->private;
+ struct osd_device *dev = osd_dt_dev(dt);
+ __s64 val;
+ int rc;
+
+ LASSERT(dev != NULL);
+ if (unlikely(dev->od_mnt == NULL))
+ return -EINPROGRESS;
+
+ rc = lprocfs_str_to_s64(buffer, count, &val);
+ if (rc)
+ return rc;
+
+ dev->od_index_backup_policy = val;
+ return count;
+}
+LPROC_SEQ_FOPS(ldiskfs_osd_index_backup);
+
LPROC_SEQ_FOPS_RO_TYPE(ldiskfs, dt_blksize);
LPROC_SEQ_FOPS_RO_TYPE(ldiskfs, dt_kbytestotal);
LPROC_SEQ_FOPS_RO_TYPE(ldiskfs, dt_kbytesfree);
.fops = &ldiskfs_osd_wcache_fops },
{ .name = "readcache_max_filesize",
.fops = &ldiskfs_osd_readcache_fops },
+ { .name = "index_backup",
+ .fops = &ldiskfs_osd_index_backup_fops },
{ NULL }
};
.olm_name = LUSTRE_NODEMAP_NAME,
},
+ /* index_backup */
+ {
+ .olm_name = INDEX_BACKUP_DIR,
+ .olm_fid = {
+ .f_seq = FID_SEQ_LOCAL_FILE,
+ .f_oid = INDEX_BACKUP_OID,
+ },
+ .olm_flags = OLF_SCAN_SUBITEMS | OLF_NOT_BACKUP,
+ .olm_namelen = sizeof(INDEX_BACKUP_DIR) - 1,
+ .olm_scandir = osd_ios_general_scan,
+ .olm_filldir = osd_ios_varfid_fill,
+ },
+
{
.olm_name = NULL
}
RETURN(0);
}
+static bool osd_index_need_recreate(const struct lu_env *env,
+ struct osd_device *dev, struct inode *inode)
+{
+ struct osd_directory *iam = &osd_oti_get(env)->oti_iam;
+ struct iam_container *bag = &iam->od_container;
+ int rc;
+ ENTRY;
+
+ rc = iam_container_init(bag, &iam->od_descr, inode);
+ if (rc)
+ RETURN(true);
+
+ rc = iam_container_setup(bag);
+ iam_container_fini(bag);
+ if (rc)
+ RETURN(true);
+
+ RETURN(false);
+}
+
+static void osd_ios_index_register(const struct lu_env *env,
+ struct osd_device *osd,
+ const struct lu_fid *fid,
+ struct inode *inode)
+{
+ struct osd_directory *iam = &osd_oti_get(env)->oti_iam;
+ struct iam_container *bag = &iam->od_container;
+ struct super_block *sb = osd_sb(osd);
+ struct iam_descr *descr;
+ __u32 keysize = 0;
+ __u32 recsize = 0;
+ int rc;
+ ENTRY;
+
+ /* Index must be a regular file. */
+ if (!S_ISREG(inode->i_mode))
+ RETURN_EXIT;
+
+ /* Index's size must be block aligned. */
+ if (inode->i_size < sb->s_blocksize ||
+ (inode->i_size & (sb->s_blocksize - 1)) != 0)
+ RETURN_EXIT;
+
+ iam_container_init(bag, &iam->od_descr, inode);
+ rc = iam_container_setup(bag);
+ if (rc)
+ GOTO(fini, rc = 1);
+
+ descr = bag->ic_descr;
+ /* May be regular file with IAM_LFIX_ROOT_MAGIC matched
+ * coincidentally, or corrupted index object, skip it. */
+ if (descr->id_ptr_size != 4)
+ GOTO(fini, rc = 1);
+
+ keysize = descr->id_key_size;
+ recsize = descr->id_rec_size;
+ rc = osd_index_register(osd, fid, keysize, recsize);
+
+ GOTO(fini, rc);
+
+fini:
+ iam_container_fini(bag);
+ if (!rc)
+ CDEBUG(D_LFSCK, "%s: index object "DFID" (%u/%u) registered\n",
+ osd_name(osd), PFID(fid), keysize, recsize);
+}
+
+static void osd_index_restore(const struct lu_env *env, struct osd_device *dev,
+ struct lustre_index_restore_unit *liru,
+ void *buf, int bufsize)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct osd_inode_id *id = &info->oti_id;
+ struct lu_fid *tgt_fid = &liru->liru_cfid;
+ struct inode *bak_inode = NULL;
+ struct ldiskfs_dir_entry_2 *de = NULL;
+ struct buffer_head *bh = NULL;
+ struct dentry *dentry;
+ char *name = buf;
+ struct lu_fid bak_fid;
+ int rc;
+ ENTRY;
+
+ lustre_fid2lbx(name, tgt_fid, bufsize);
+ dentry = osd_child_dentry_by_inode(env, dev->od_index_backup_inode,
+ name, strlen(name));
+ bh = osd_ldiskfs_find_entry(dev->od_index_backup_inode,
+ &dentry->d_name, &de, NULL, NULL);
+ if (IS_ERR(bh))
+ GOTO(log, rc = PTR_ERR(bh));
+
+ osd_id_gen(id, le32_to_cpu(de->inode), OSD_OII_NOGEN);
+ brelse(bh);
+ bak_inode = osd_iget_fid(info, dev, id, &bak_fid);
+ if (IS_ERR(bak_inode))
+ GOTO(log, rc = PTR_ERR(bak_inode));
+
+ iput(bak_inode);
+ /* The OI mapping for index may be invalid, since it will be
+ * re-created, not update the OI mapping, just cache it in RAM. */
+ osd_id_gen(id, liru->liru_clid, OSD_OII_NOGEN);
+ osd_add_oi_cache(info, dev, id, tgt_fid);
+ rc = lustre_index_restore(env, &dev->od_dt_dev, &liru->liru_pfid,
+ tgt_fid, &bak_fid, liru->liru_name,
+ &dev->od_index_backup_list, &dev->od_lock,
+ buf, bufsize);
+ GOTO(log, rc);
+
+log:
+ CDEBUG(D_WARNING, "%s: restore index '%s' with "DFID": rc = %d\n",
+ osd_name(dev), liru->liru_name, PFID(tgt_fid), rc);
+}
+
/**
* osd_ios_scan_one() - check/fix LMA FID and OI entry for one inode
*
*/
static int
osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev,
- struct inode *inode, const struct lu_fid *fid, int flags)
+ struct inode *parent, struct inode *inode,
+ const struct lu_fid *fid, const char *name,
+ int namelen, int flags)
{
struct lustre_mdt_attrs *lma = &info->oti_ost_attrs.loa_lma;
struct osd_inode_id *id = &info->oti_id;
RETURN(0);
tfid = lma->lma_self_fid;
+ if (lma->lma_compat & LMAC_IDX_BACKUP &&
+ osd_index_need_recreate(info->oti_env, dev, inode)) {
+ struct lu_fid *pfid = &info->oti_fid3;
+
+ if (parent == osd_sb(dev)->s_root->d_inode) {
+ lu_local_obj_fid(pfid, OSD_FS_ROOT_OID);
+ } else {
+ rc = osd_scrub_get_fid(info, dev, parent, pfid,
+ false);
+ if (rc)
+ RETURN(rc);
+ }
+
+ rc = lustre_liru_new(&dev->od_index_restore_list, pfid,
+ &tfid, inode->i_ino, name, namelen);
+
+ RETURN(rc);
+ }
+
+ if (!(flags & OLF_NOT_BACKUP))
+ osd_ios_index_register(info->oti_env, dev, &tfid,
+ inode);
}
rc = osd_oi_lookup(info, dev, &tfid, id2, 0);
if (IS_ERR(child))
RETURN(PTR_ERR(child));
- rc = osd_ios_scan_one(fill_buf->oifb_info, dev, child->d_inode,
- NULL, 0);
+ rc = osd_ios_scan_one(fill_buf->oifb_info, dev,
+ fill_buf->oifb_dentry->d_inode, child->d_inode,
+ NULL, name, namelen, 0);
if (rc == 0 && S_ISDIR(child->d_inode->i_mode))
rc = osd_ios_new_item(dev, child, osd_ios_general_scan,
osd_ios_varfid_fill);
if (IS_ERR(child))
RETURN(PTR_ERR(child));
- rc = osd_ios_scan_one(fill_buf->oifb_info, dev, child->d_inode,
- &map->olm_fid, map->olm_flags);
+ rc = osd_ios_scan_one(fill_buf->oifb_info, dev,
+ fill_buf->oifb_dentry->d_inode, child->d_inode,
+ &map->olm_fid, name, namelen, map->olm_flags);
dput(child);
RETURN(rc);
sscanf(&name[1], SFID, RFID(&tfid));
if (fid_is_sane(&tfid))
rc = osd_ios_scan_one(fill_buf->oifb_info, fill_buf->oifb_dev,
- child->d_inode, &tfid, 0);
+ fill_buf->oifb_dentry->d_inode,
+ child->d_inode, &tfid, name, namelen, 0);
else
rc = -EIO;
dput(child);
RETURN(PTR_ERR(child));
if (!(map->olm_flags & OLF_NO_OI))
- rc = osd_ios_scan_one(fill_buf->oifb_info, dev, child->d_inode,
- &map->olm_fid, map->olm_flags);
+ rc = osd_ios_scan_one(fill_buf->oifb_info, dev,
+ fill_buf->oifb_dentry->d_inode, child->d_inode,
+ &map->olm_fid, name, namelen, map->olm_flags);
if (rc == 0 && map->olm_flags & OLF_SCAN_SUBITEMS)
rc = osd_ios_new_item(dev, child, map->olm_scandir,
map->olm_filldir);
* Usually, it is rare case for the old connected clients
* to access the ".lustre" with cached IGIF. So we prefer
* to the solution 2). */
- rc = osd_ios_scan_one(info, dev, child->d_inode,
- &LU_DOT_LUSTRE_FID, 0);
+ rc = osd_ios_scan_one(info, dev, dentry->d_inode,
+ child->d_inode, &LU_DOT_LUSTRE_FID,
+ dot_lustre_name,
+ strlen(dot_lustre_name), 0);
if (rc == 0)
rc = osd_ios_new_item(dev, child, osd_ios_general_scan,
osd_ios_dl_fill);
child = osd_ios_lookup_one_len(ADMIN_USR, dentry, strlen(ADMIN_USR));
if (!IS_ERR(child)) {
- rc = osd_ios_scan_one(info, dev, child->d_inode, NULL, 0);
+ rc = osd_ios_scan_one(info, dev, dentry->d_inode,
+ child->d_inode, NULL, ADMIN_USR,
+ strlen(ADMIN_USR), 0);
dput(child);
} else {
rc = PTR_ERR(child);
child = osd_ios_lookup_one_len(ADMIN_GRP, dentry, strlen(ADMIN_GRP));
if (!IS_ERR(child)) {
- rc = osd_ios_scan_one(info, dev, child->d_inode, NULL, 0);
+ rc = osd_ios_scan_one(info, dev, dentry->d_inode,
+ child->d_inode, NULL, ADMIN_GRP,
+ strlen(ADMIN_GRP), 0);
dput(child);
} else {
rc = PTR_ERR(child);
RETURN(rc);
}
-static int osd_initial_OI_scrub(struct osd_thread_info *info,
- struct osd_device *dev)
+static void osd_initial_OI_scrub(struct osd_thread_info *info,
+ struct osd_device *dev)
{
struct osd_ios_item *item = NULL;
scandir_t scandir = osd_ios_general_scan;
filldir_t filldir = osd_ios_root_fill;
struct dentry *dentry = osd_sb(dev)->s_root;
const struct osd_lf_map *map = osd_lf_maps;
- int rc;
ENTRY;
/* Lookup IGIF in OI by force for initial OI scrub. */
dev->od_igif_inoi = 1;
while (1) {
- rc = scandir(info, dev, dentry, filldir);
+ scandir(info, dev, dentry, filldir);
if (item != NULL) {
dput(item->oii_dentry);
OBD_FREE_PTR(item);
}
- if (rc != 0)
- break;
-
if (list_empty(&dev->od_ios_list))
break;
dentry = item->oii_dentry;
}
- while (!list_empty(&dev->od_ios_list)) {
- item = list_entry(dev->od_ios_list.next,
- struct osd_ios_item, oii_list);
- list_del_init(&item->oii_list);
- dput(item->oii_dentry);
- OBD_FREE_PTR(item);
- }
-
- if (rc != 0)
- RETURN(rc);
-
/* There maybe the case that the object has been removed, but its OI
* mapping is still in the OI file, such as the "CATALOGS" after MDT
* file-level backup/restore. So here cleanup the stale OI mappings. */
map++;
}
- RETURN(0);
+ if (!list_empty(&dev->od_index_restore_list)) {
+ char *buf;
+
+ OBD_ALLOC_LARGE(buf, INDEX_BACKUP_BUFSIZE);
+ if (!buf)
+ CERROR("%s: not enough RAM for rebuild index\n",
+ osd_name(dev));
+
+ while (!list_empty(&dev->od_index_restore_list)) {
+ struct lustre_index_restore_unit *liru;
+
+ liru = list_entry(dev->od_index_restore_list.next,
+ struct lustre_index_restore_unit,
+ liru_link);
+ list_del(&liru->liru_link);
+ if (buf)
+ osd_index_restore(info->oti_env, dev, liru,
+ buf, INDEX_BACKUP_BUFSIZE);
+ OBD_FREE(liru, liru->liru_len);
+ }
+
+ if (buf)
+ OBD_FREE_LARGE(buf, INDEX_BACKUP_BUFSIZE);
+ }
+
+ EXIT;
}
char *osd_lf_fid2name(const struct lu_fid *fid)
struct file *filp;
struct inode *inode;
struct lu_fid *fid = &info->oti_fid;
- struct lu_object_conf conf;
+ struct osd_inode_id *id = &info->oti_id;
struct dt_object *obj;
bool dirty = false;
bool restored = false;
}
}
- igrab(inode);
+ osd_id_gen(id, inode->i_ino, inode->i_generation);
+ osd_add_oi_cache(info, dev, id, fid);
filp_close(filp, NULL);
pop_ctxt(&saved, ctxt);
- conf.loc_flags = LOC_F_NEW;
- obj = lu2dt(lu_object_find_slice(env, osd2lu_dev(dev), fid, &conf));
- if (IS_ERR_OR_NULL(obj)) {
- iput(inode);
- RETURN(obj == NULL ? -ENOENT : PTR_ERR(obj));
- }
+ obj = lu2dt(lu_object_find_slice(env, osd2lu_dev(dev), fid, NULL));
+ if (IS_ERR_OR_NULL(obj))
+ RETURN(obj ? PTR_ERR(obj) : -ENOENT);
- osd_dt_obj(obj)->oo_inode = inode;
scrub->os_obj = obj;
rc = scrub_file_load(env, scrub);
if (rc == -ENOENT || rc == -EFAULT) {
if (rc < 0)
GOTO(cleanup_obj, rc);
- if (!dev->od_dt_dev.dd_rdonly) {
- rc = osd_initial_OI_scrub(info, dev);
- if (rc)
- GOTO(cleanup_oi, rc);
- }
+ if (!dev->od_dt_dev.dd_rdonly)
+ osd_initial_OI_scrub(info, dev);
if (sf->sf_flags & SF_UPGRADE ||
!(sf->sf_internal_flags & SIF_NO_HANDLE_OLD_FID ||
run_test 15 "Dryrun mode OI scrub"
test_16() {
- [ $(facet_fstype $SINGLEMDS) != "zfs" ] &&
- skip "only support zfs temporarily" && return
-
check_mount_and_prep
scrub_enable_index_backup