Beispiel #1
0
int lfsck_bookmark_setup(const struct lu_env *env,
                         struct lfsck_instance *lfsck)
{
    struct dt_object *root;
    struct dt_object *obj;
    int		  rc;
    ENTRY;

    root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid);
    if (IS_ERR(root))
        RETURN(PTR_ERR(root));

    dt_try_as_dir(env, root);
    obj = local_file_find_or_create(env, lfsck->li_los, root,
                                    lfsck_bookmark_name,
                                    S_IFREG | S_IRUGO | S_IWUSR);
    lu_object_put(env, &root->do_lu);
    if (IS_ERR(obj))
        RETURN(PTR_ERR(obj));

    lfsck->li_bookmark_obj = obj;
    rc = lfsck_bookmark_load(env, lfsck);
    if (rc == -ENODATA)
        rc = lfsck_bookmark_init(env, lfsck);

    RETURN(rc);
}
Beispiel #2
0
/**
 * This is helper function to get llog directory object. It is used by named
 * llog operations to find/insert/delete llog entry from llog directory.
 *
 * \param[in] env	execution environment
 * \param[in] ctxt	llog context
 *
 * \retval		dt_object of llog directory
 * \retval		ERR_PTR of negative value on error
 */
struct dt_object *llog_osd_dir_get(const struct lu_env *env,
				   struct llog_ctxt *ctxt)
{
	struct dt_device	*dt;
	struct dt_thread_info	*dti = dt_info(env);
	struct dt_object	*dir;
	int			 rc;

	dt = ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt;
	if (ctxt->loc_dir == NULL) {
		rc = dt_root_get(env, dt, &dti->dti_fid);
		if (rc)
			return ERR_PTR(rc);
		dir = dt_locate(env, dt, &dti->dti_fid);

		if (!IS_ERR(dir) && !dt_try_as_dir(env, dir)) {
			lu_object_put(env, &dir->do_lu);
			return ERR_PTR(-ENOTDIR);
		}
	} else {
		lu_object_get(&ctxt->loc_dir->do_lu);
		dir = ctxt->loc_dir;
	}

	return dir;
}
Beispiel #3
0
/**
 * open the PENDING directory for device \a mdd
 *
 * The PENDING directory persistently tracks files and directories that were
 * unlinked from the namespace (nlink == 0) but are still held open by clients.
 * Those inodes shouldn't be deleted if the MDS crashes, because the clients
 * would not be able to recover and reopen those files.  Instead, these inodes
 * are linked into the PENDING directory on disk, and only deleted if all
 * clients close them, or the MDS finishes client recovery without any client
 * reopening them (i.e. former clients didn't join recovery).
 *  \param d   mdd device being started.
 *
 *  \retval 0  success
 *  \retval  -ve index operation error.
 *
 */
int orph_index_init(const struct lu_env *env, struct mdd_device *mdd)
{
	struct lu_fid		 fid;
	struct dt_object	*d;
	int			 rc = 0;

	ENTRY;

	/* create PENDING dir */
	fid_zero(&fid);
	rc = mdd_local_file_create(env, mdd, &mdd->mdd_local_root_fid,
				   orph_index_name, S_IFDIR | S_IRUGO |
				   S_IWUSR | S_IXUGO, &fid);
	if (rc < 0)
		RETURN(rc);

	d = dt_locate(env, mdd->mdd_child, &fid);
	if (IS_ERR(d))
		RETURN(PTR_ERR(d));
	LASSERT(lu_object_exists(&d->do_lu));
	if (!dt_try_as_dir(env, d)) {
		CERROR("%s: \"%s\" is not an index: rc = %d\n",
		       mdd2obd_dev(mdd)->obd_name, orph_index_name, rc);
		lu_object_put(env, &d->do_lu);
		RETURN(-ENOTDIR);
	}
	mdd->mdd_orphans = d;
	RETURN(0);
}
Beispiel #4
0
static int out_tx_index_insert_undo(struct mdt_thread_info *info,
				    struct thandle *th, struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "index delete "DFID" name: %s\n",
	       PFID(lu_object_fid(&arg->object->do_lu)),
	       (char *)arg->u.insert.key);

	if (dt_try_as_dir(info->mti_env, dt_obj) == 0) {
		CERROR("%s: "DFID" is not directory: rc = %d\n",
		       mdt_obd_name(info->mti_mdt),
		       PFID(lu_object_fid(&dt_obj->do_lu)), -ENOTDIR);
		return -ENOTDIR;
	}

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	rc = dt_delete(info->mti_env, dt_obj, arg->u.insert.key, th, NULL);
	dt_write_unlock(info->mti_env, dt_obj);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Beispiel #5
0
static int __out_tx_index_delete(const struct lu_env *env,
				 struct dt_object *dt_obj, char *name,
				 struct thandle_exec_args *ta,
				 struct update_reply *reply,
				 int index, char *file, int line)
{
	struct tx_arg *arg;

	if (dt_try_as_dir(env, dt_obj) == 0) {
		ta->ta_err = -ENOTDIR;
		return ta->ta_err;
	}

	LASSERT(ta->ta_handle != NULL);
	ta->ta_err = dt_declare_delete(env, dt_obj,
				       (struct dt_key *)name,
				       ta->ta_handle);
	if (ta->ta_err != 0)
		return ta->ta_err;

	arg = tx_add_exec(ta, out_tx_index_delete_exec,
			  out_tx_index_delete_undo, file,
			  line);
	LASSERT(arg);
	lu_object_get(&dt_obj->do_lu);
	arg->object = dt_obj;
	arg->reply = reply;
	arg->index = index;
	arg->u.insert.key = (struct dt_key *)name;
	return 0;
}
Beispiel #6
0
static int out_tx_index_insert_exec(struct mdt_thread_info *info,
				    struct thandle *th, struct tx_arg *arg)
{
	struct dt_object *dt_obj = arg->object;
	int rc;

	LASSERT(dt_obj != NULL && !IS_ERR(dt_obj));

	CDEBUG(D_OTHER, "index insert "DFID" name: %s fid "DFID"\n",
	       PFID(lu_object_fid(&arg->object->do_lu)),
	       (char *)arg->u.insert.key,
	       PFID((struct lu_fid *)arg->u.insert.rec));

	if (dt_try_as_dir(info->mti_env, dt_obj) == 0)
		return -ENOTDIR;

	dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD);
	rc = dt_insert(info->mti_env, dt_obj, arg->u.insert.rec,
		       arg->u.insert.key, th, NULL, 0);
	dt_write_unlock(info->mti_env, dt_obj);

	update_insert_reply(arg->reply, NULL, 0, arg->index, rc);

	return rc;
}
Beispiel #7
0
static int out_index_lookup(struct tgt_session_info *tsi)
{
	const struct lu_env	*env = tsi->tsi_env;
	struct tgt_thread_info	*tti = tgt_th_info(env);
	struct object_update	*update = tti->tti_u.update.tti_update;
	struct dt_object	*obj = tti->tti_u.update.tti_dt_object;
	char			*name;
	int			 rc;

	ENTRY;

	if (unlikely(update->ou_result_size < sizeof(tti->tti_fid1)))
		return -EPROTO;

	if (!lu_object_exists(&obj->do_lu))
		RETURN(-ENOENT);

	name = object_update_param_get(update, 0, NULL);
	if (IS_ERR(name)) {
		CERROR("%s: empty name for lookup: rc = %ld\n",
		       tgt_name(tsi->tsi_tgt), PTR_ERR(name));
		RETURN(PTR_ERR(name));
	}

	dt_read_lock(env, obj, MOR_TGT_CHILD);
	if (!dt_try_as_dir(env, obj))
		GOTO(out_unlock, rc = -ENOTDIR);

	rc = dt_lookup(env, obj, (struct dt_rec *)&tti->tti_fid1,
		       (struct dt_key *)name);

	if (rc < 0)
		GOTO(out_unlock, rc);

	if (rc == 0)
		rc += 1;

out_unlock:
	dt_read_unlock(env, obj);

	CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n",
	       PFID(lu_object_fid(&obj->do_lu)), name,
	       PFID(&tti->tti_fid1), rc);

	CDEBUG(D_INFO, "%s: insert lookup reply %p index %d: rc = %d\n",
	       tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply,
	       0, rc);

	object_update_result_insert(tti->tti_u.update.tti_update_reply,
			    &tti->tti_fid1, sizeof(tti->tti_fid1),
			    tti->tti_u.update.tti_update_reply_index, rc);
	RETURN(rc);
}
Beispiel #8
0
static int out_index_lookup(struct tgt_session_info *tsi)
{
	const struct lu_env	*env = tsi->tsi_env;
	struct tgt_thread_info	*tti = tgt_th_info(env);
	struct update		*update = tti->tti_u.update.tti_update;
	struct dt_object	*obj = tti->tti_u.update.tti_dt_object;
	char			*name;
	int			 rc;

	ENTRY;

	if (!lu_object_exists(&obj->do_lu))
		RETURN(-ENOENT);

	name = (char *)update_param_buf(update, 0, NULL);
	if (name == NULL) {
		CERROR("%s: empty name for lookup: rc = %d\n",
		       tgt_name(tsi->tsi_tgt), -EPROTO);
		RETURN(err_serious(-EPROTO));
	}

	dt_read_lock(env, obj, MOR_TGT_CHILD);
	if (!dt_try_as_dir(env, obj))
		GOTO(out_unlock, rc = -ENOTDIR);

	rc = dt_lookup(env, obj, (struct dt_rec *)&tti->tti_fid1,
		(struct dt_key *)name, NULL);

	if (rc < 0)
		GOTO(out_unlock, rc);

	if (rc == 0)
		rc += 1;

	CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n",
	       PFID(lu_object_fid(&obj->do_lu)), name,
	       PFID(&tti->tti_fid1), rc);
	fid_cpu_to_le(&tti->tti_fid1, &tti->tti_fid1);

out_unlock:
	dt_read_unlock(env, obj);

	CDEBUG(D_INFO, "%s: insert lookup reply %p index %d: rc = %d\n",
	       tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply,
	       0, rc);

	update_insert_reply(tti->tti_u.update.tti_update_reply,
			    &tti->tti_fid1, sizeof(tti->tti_fid1), 0, rc);
	RETURN(rc);
}
Beispiel #9
0
static int orph_index_insert(const struct lu_env *env,
                             struct mdd_object *obj,
                             __u32 op,
                             struct thandle *th)
{
        struct mdd_device       *mdd    = mdo2mdd(&obj->mod_obj);
        struct dt_object        *dor    = mdd->mdd_orphans;
        const struct lu_fid     *lf_dor = lu_object_fid(&dor->do_lu);
        struct dt_object        *next   = mdd_object_child(obj);
        int rc;
        ENTRY;

        LASSERT(mdd_write_locked(env, obj) != 0);
        LASSERT(!(obj->mod_flags & ORPHAN_OBJ));

        mdd_orphan_write_lock(env, mdd);

        rc = mdd_orphan_insert_obj(env, mdd, obj, op, th);
        if (rc)
                GOTO(out, rc);

        mdo_ref_add(env, obj, th);
        if (!S_ISDIR(mdd_object_type(obj)))
                goto out;

        mdo_ref_add(env, obj, th);
        mdd_orphan_ref_add(env, mdd, th);

        /* try best to fixup directory, dont return errors
         * from here */
        if (!dt_try_as_dir(env, next))
                goto out;
        next->do_index_ops->dio_delete(env, next,
                                       (const struct dt_key *)dotdot,
                                       th, BYPASS_CAPA);

        next->do_index_ops->dio_insert(env, next,
                                       (struct dt_rec *)lf_dor,
                                       (const struct dt_key *)dotdot,
                                       th, BYPASS_CAPA, 1);

out:
        if (rc == 0)
                obj->mod_flags |= ORPHAN_OBJ;

        mdd_orphan_write_unlock(env, mdd);

        RETURN(rc);
}
Beispiel #10
0
/**
 *  add an orphan \a obj to the orphan index.
 *  \param obj file or directory.
 *  \param th  transaction for index insert.
 *
 *  \pre obj nlink == 0 && obj->mod_count != 0
 *
 *  \retval 0  success
 *  \retval  -ve index operation error.
 */
int mdd_orphan_insert(const struct lu_env *env, struct mdd_object *obj,
		      struct thandle *th)
{
	struct mdd_device *mdd = mdo2mdd(&obj->mod_obj);
	struct dt_object *dor = mdd->mdd_orphans;
	const struct lu_fid *lf_dor = lu_object_fid(&dor->do_lu);
	struct dt_object *next = mdd_object_child(obj);
	struct dt_insert_rec *rec = &mdd_env_info(env)->mti_dt_rec;
	int rc;
	ENTRY;

	LASSERT(mdd_write_locked(env, obj) != 0);
	LASSERT(!(obj->mod_flags & ORPHAN_OBJ));

	dt_write_lock(env, mdd->mdd_orphans, MOR_TGT_ORPHAN);

	rc = mdd_orphan_insert_obj(env, mdd, obj, th);
	if (rc)
		GOTO(out, rc);

	mdo_ref_add(env, obj, th);
	if (!S_ISDIR(mdd_object_type(obj)))
		GOTO(out, rc = 0);

	mdo_ref_add(env, obj, th);
	dt_ref_add(env, mdd->mdd_orphans, th);

	/* try best to fixup directory, do not return errors from here */
	if (!dt_try_as_dir(env, next))
		GOTO(out, rc = 0);

	dt_delete(env, next, (const struct dt_key *)dotdot, th);

	rec->rec_fid = lf_dor;
	rec->rec_type = S_IFDIR;
	dt_insert(env, next, (const struct dt_rec *)rec,
		  (const struct dt_key *)dotdot, th);

out:
	if (rc == 0)
		obj->mod_flags |= ORPHAN_OBJ;

	dt_write_unlock(env, mdd->mdd_orphans);

	RETURN(rc);
}
Beispiel #11
0
static int out_index_lookup(struct mdt_thread_info *info)
{
	struct update		*update = info->mti_u.update.mti_update;
	const struct lu_env	*env = info->mti_env;
	struct dt_object	*obj = info->mti_u.update.mti_dt_object;
	char			*name;
	int			rc;

	ENTRY;

	if (!lu_object_exists(&obj->do_lu))
		RETURN(-ENOENT);

	name = (char *)update_param_buf(update, 0, NULL);
	if (name == NULL) {
		CERROR("%s: empty name for lookup: rc = %d\n",
		       mdt_obd_name(info->mti_mdt), -EPROTO);
		RETURN(err_serious(-EPROTO));
	}

	dt_read_lock(env, obj, MOR_TGT_CHILD);
	if (!dt_try_as_dir(env, obj))
		GOTO(out_unlock, rc = -ENOTDIR);

	rc = dt_lookup(env, obj, (struct dt_rec *)&info->mti_tmp_fid1,
		(struct dt_key *)name, NULL);

	if (rc < 0)
		GOTO(out_unlock, rc);

	if (rc == 0)
		rc += 1;

	CDEBUG(D_INFO, "lookup "DFID" %s get "DFID" rc %d\n",
	       PFID(lu_object_fid(&obj->do_lu)), name,
	       PFID(&info->mti_tmp_fid1), rc);
	fid_cpu_to_le(&info->mti_tmp_fid1, &info->mti_tmp_fid1);

out_unlock:
	dt_read_unlock(env, obj);
	update_insert_reply(info->mti_u.update.mti_update_reply,
			    &info->mti_tmp_fid1, sizeof(info->mti_tmp_fid1),
			    0, rc);
	RETURN(rc);
}
Beispiel #12
0
int lfsck_bookmark_setup(const struct lu_env *env,
			 struct lfsck_instance *lfsck)
{
	struct dt_object *root;
	struct dt_object *obj;
	int		  rc;
	ENTRY;

	root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid);
	if (IS_ERR(root))
		RETURN(PTR_ERR(root));

	if (unlikely(!dt_try_as_dir(env, root))) {
		lfsck_object_put(env, root);

		RETURN(-ENOTDIR);
	}

	obj = local_file_find_or_create(env, lfsck->li_los, root,
					LFSCK_BOOKMARK,
					S_IFREG | S_IRUGO | S_IWUSR);
	lfsck_object_put(env, root);
	if (IS_ERR(obj))
		RETURN(PTR_ERR(obj));

	lfsck->li_bookmark_obj = obj;
	rc = lfsck_bookmark_load(env, lfsck);
	if (rc == 0) {
		struct lfsck_bookmark *mb = &lfsck->li_bookmark_ram;

		/* It is upgraded from old release, set it as
		 * LFSCK_ASYNC_WIN_DEFAULT to avoid memory pressure. */
		if (unlikely(mb->lb_async_windows == 0)) {
			mb->lb_async_windows = LFSCK_ASYNC_WIN_DEFAULT;
			mutex_lock(&lfsck->li_mutex);
			rc = lfsck_bookmark_store(env, lfsck);
			mutex_unlock(&lfsck->li_mutex);
		}
	} else if (rc == -ENODATA) {
		rc = lfsck_bookmark_init(env, lfsck);
	}

	RETURN(rc);
}
Beispiel #13
0
/*
 * To enable DNE functionality we need FID of /ROOT directory
 * (which is / as seen by the clients) to belong to MDT0 and
 * not to FID_SEQ_LOCAL_FILE or some other local sequence,
 * which can be used by any node, so can't be part of FLDB.
 *
 * Pre-production code was using FID_SEQ_LOCAL_FILE for /ROOT
 * making few existing setups incompatibile with DNE. This
 * applies to ZFS-based setups only as ldiskfs-based setups
 * are still using IGIF to identify /ROOT.
 *
 * The intention of this code is to fix on-disk state to use
 * FID_SEQ_ROOT for /ROOT:
 *  - "." and ".." references in /ROOT itself and it`s subdirectories
 *  - LinkEA in all the objects listed in /ROOT
 *
 * Given only ZFS is affected where "." and ".." are not stored, we need to:
 *  - delete "." and ".." from /ROOT and its subdirectories
 *  - rename references in LinkEA in all the objects listed in /ROOT
 *
 * This code is subject for removal in 2.5
 */
static int mdd_convert_remove_dots(const struct lu_env *env,
				   struct mdd_device *mdd,
				   struct mdd_object *o)
{
	struct thandle		*th;
	const struct dt_key	*dot = (const struct dt_key *)".";
	const struct dt_key	*dotdot = (const struct dt_key *)"..";
	int			 rc;

	if (dt_try_as_dir(env, mdd_object_child(o)) == 0)
		RETURN(-ENOTDIR);

	/* remove "."/".." and do not insert them back - not stored in ZFS */
	th = dt_trans_create(env, mdd->mdd_child);
	if (IS_ERR(th))
		RETURN(PTR_ERR(th));

	rc = dt_declare_delete(env, mdd_object_child(o), dot, th);
	if (rc)
		GOTO(out, rc);
	rc = dt_declare_delete(env, mdd_object_child(o), dotdot, th);
	if (rc)
		GOTO(out, rc);
	rc = dt_trans_start_local(env, mdd->mdd_child, th);
	if (rc)
		GOTO(out, rc);
	/* ignore non-existing "."/".." - we stored them on disk for
	 * pre-production systems, but this is not how regular ZFS works */
	rc = dt_delete(env, mdd_object_child(o), dot, th, BYPASS_CAPA);
	if (rc == -ENOENT)
		rc = 0;
	if (rc)
		GOTO(out, rc);
	rc = dt_delete(env, mdd_object_child(o), dotdot, th, BYPASS_CAPA);
	if (rc == -ENOENT)
		rc = 0;
	if (rc)
		GOTO(out, rc);

out:
	dt_trans_stop(env, mdd->mdd_child, th);
	RETURN(rc);
}
Beispiel #14
0
static int out_obj_index_delete(const struct lu_env *env,
				struct dt_object *dt_obj,
				const struct dt_key *key,
				struct thandle *th)
{
	int rc;

	CDEBUG(D_INFO, "%s: index delete "DFID" name: %s\n",
	       dt_obd_name(th->th_dev), PFID(lu_object_fid(&dt_obj->do_lu)),
	       (char *)key);

	if (dt_try_as_dir(env, dt_obj) == 0)
		return -ENOTDIR;

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_delete(env, dt_obj, key, th, NULL);
	dt_write_unlock(env, dt_obj);

	return rc;
}
Beispiel #15
0
static int out_obj_index_insert(const struct lu_env *env,
				struct dt_object *dt_obj,
				const struct dt_rec *rec,
				const struct dt_key *key,
				struct thandle *th)
{
	int rc;

	CDEBUG(D_INFO, "%s: index insert "DFID" name: %s fid "DFID"\n",
	       dt_obd_name(th->th_dev), PFID(lu_object_fid(&dt_obj->do_lu)),
	       (char *)key, PFID((struct lu_fid *)rec));

	if (dt_try_as_dir(env, dt_obj) == 0)
		return -ENOTDIR;

	dt_write_lock(env, dt_obj, MOR_TGT_CHILD);
	rc = dt_insert(env, dt_obj, rec, key, th, NULL, 0);
	dt_write_unlock(env, dt_obj);

	return rc;
}
Beispiel #16
0
static int __out_tx_index_insert(struct mdt_thread_info *info,
				 struct dt_object *dt_obj,
				 char *name, struct lu_fid *fid,
				 struct thandle_exec_args *th,
				 struct update_reply *reply,
				 int index, char *file, int line)
{
	struct tx_arg *arg;

	LASSERT(th->ta_handle != NULL);

	if (lu_object_exists(&dt_obj->do_lu)) {
		if (dt_try_as_dir(info->mti_env, dt_obj) == 0) {
			th->ta_err = -ENOTDIR;
			return th->ta_err;
		}
		th->ta_err = dt_declare_insert(info->mti_env, dt_obj,
					       (struct dt_rec *)fid,
					       (struct dt_key *)name,
					       th->ta_handle);
	}

	if (th->ta_err != 0)
		return th->ta_err;

	arg = tx_add_exec(th, out_tx_index_insert_exec,
			  out_tx_index_insert_undo, file,
			  line);
	LASSERT(arg);
	lu_object_get(&dt_obj->do_lu);
	arg->object = dt_obj;
	arg->reply = reply;
	arg->index = index;
	arg->u.insert.rec = (struct dt_rec *)fid;
	arg->u.insert.key = (struct dt_key *)name;

	return 0;
}
Beispiel #17
0
/**
 * open the PENDING directory for device \a mdd
 *
 * The PENDING directory persistently tracks files and directories that were
 * unlinked from the namespace (nlink == 0) but are still held open by clients.
 * Those inodes shouldn't be deleted if the MDS crashes, because the clients
 * would not be able to recover and reopen those files.  Instead, these inodes
 * are linked into the PENDING directory on disk, and only deleted if all
 * clients close them, or the MDS finishes client recovery without any client
 * reopening them (i.e. former clients didn't join recovery).
 *  \param d   mdd device being started.
 *
 *  \retval 0  success
 *  \retval  -ve index operation error.
 *
 */
int orph_index_init(const struct lu_env *env, struct mdd_device *mdd)
{
        struct lu_fid fid;
        struct dt_object *d;
        int rc = 0;
        ENTRY;

        d = dt_store_open(env, mdd->mdd_child, "", orph_index_name, &fid);
        if (!IS_ERR(d)) {
                mdd->mdd_orphans = d;
                if (!dt_try_as_dir(env, d)) {
                        rc = -ENOTDIR;
                        CERROR("\"%s\" is not an index! : rc = %d\n",
                                        orph_index_name, rc);
                }
        } else {
                CERROR("cannot find \"%s\" obj %d\n",
                       orph_index_name, (int)PTR_ERR(d));
                rc = PTR_ERR(d);
        }

        RETURN(rc);
}
Beispiel #18
0
int mdd_compat_fixes(const struct lu_env *env, struct mdd_device *mdd)
{
	struct mdd_thread_info	*info = mdd_env_info(env);
	struct mdd_object	*root;
	struct dt_object	*o;
	struct lustre_mdt_attrs	*lma;
	struct lu_buf		 buf;
	int			 rc;
	ENTRY;

	/* IGIF FIDS are valid for old 1.8 and 2.[123] ROOT and are kept.
	 * Normal FIDs used by Xyratex 1.8->2.1 upgrade tool are also kept. */
	if (fid_is_igif(&mdd->mdd_root_fid) || fid_is_norm(&mdd->mdd_root_fid))
		RETURN(0);

	/*
	 * FID is supposed to be FID_SEQ_ROOT for:
	 *  - new ldiskfs fs
	 *  - new ZFS fs
	 *  - old ZFS fs, by now processed with osd_convert_root_to_new_seq()
	 */
	if (fid_seq(&mdd->mdd_root_fid) != FID_SEQ_ROOT) {
		CERROR("%s: wrong FID "DFID" is used for /ROOT\n",
		       mdd2obd_dev(mdd)->obd_name,
		       PFID(&mdd->mdd_root_fid));
		RETURN(-EINVAL);
	}

	root = mdd_object_find(env, mdd, &mdd->mdd_root_fid);
	if (IS_ERR(root))
		RETURN(PTR_ERR(root));
	o = mdd_object_child(root);

	CDEBUG(D_OTHER, "/ROOT = "DFID"\n", PFID(&mdd->mdd_root_fid));

	if (dt_try_as_dir(env, o) == 0) {
		CERROR("%s: not a directory\n", mdd2obd_dev(mdd)->obd_name);
		GOTO(out, rc = -ENOTDIR);
	}

	lma = (struct lustre_mdt_attrs *)&info->mti_xattr_buf;
	CLASSERT(sizeof(info->mti_xattr_buf) >= LMA_OLD_SIZE);
	buf.lb_len = LMA_OLD_SIZE;
	buf.lb_buf = lma;
	rc = mdo_xattr_get(env, root, &buf, XATTR_NAME_LMA, BYPASS_CAPA);
	if (rc < 0 && rc != -ENODATA) {
		CERROR("%s: can't fetch LMA: rc = %d\n",
		       mdd2obd_dev(mdd)->obd_name, rc);
		GOTO(out, rc);
	}

	lustre_lma_swab(lma);
	if (lu_fid_eq(&lma->lma_self_fid, &mdd->mdd_root_fid)) {
		/* /ROOT has been converted already
		 * or was correct from the beginning */
		CDEBUG(D_OTHER, "%s: converted already\n",
		       mdd2obd_dev(mdd)->obd_name);
		GOTO(out, rc = 0);
	}

	/* this is supposed to happen only on pre-production ZFS backend */
	if (strcmp(mdd->mdd_bottom->dd_lu_dev.ld_type->ldt_name,
		   LUSTRE_OSD_ZFS_NAME) != 0) {
		CERROR("%s: "DFID" is used on ldiskfs?!\n",
		       mdd2obd_dev(mdd)->obd_name, PFID(&mdd->mdd_root_fid));
		GOTO(out, rc = -ENOTSUPP);
	}

	LCONSOLE_INFO("%s: FID of /ROOT has been changed. "
		      "Please remount the clients.\n",
		      mdd2obd_dev(mdd)->obd_name);

	/* Fill FLDB first */
	rc = mdd_fill_fldb(env, mdd);
	if (rc)
		GOTO(out, rc);

	/* remove ./.. from /ROOT */
	rc = mdd_convert_remove_dots(env, mdd, root);
	if (rc)
		GOTO(out, rc);

	/* go over the directory, fix all the objects */
	rc = mdd_fix_children(env, mdd, o);
	if (rc)
		GOTO(out, rc);

	/* Update LMA on /ROOT.  Done for simplicity in MDD, not in osd-zfs.
	 * Correct LMA will imply the whole directory has been coverted
	 * successfully, otherwise it will be retried on next mount. */
	rc = mdd_convert_lma(env, mdd, root);

out:
	mdd_object_put(env, root);
	RETURN(rc);
}
Beispiel #19
0
static int out_attr_get(struct tgt_session_info *tsi)
{
	const struct lu_env	*env = tsi->tsi_env;
	struct tgt_thread_info	*tti = tgt_th_info(env);
	struct obdo		*obdo = &tti->tti_u.update.tti_obdo;
	struct lu_attr		*la = &tti->tti_attr;
	struct dt_object        *obj = tti->tti_u.update.tti_dt_object;
	int			rc;

	ENTRY;

	if (!lu_object_exists(&obj->do_lu))
		RETURN(-ENOENT);

	dt_read_lock(env, obj, MOR_TGT_CHILD);
	rc = dt_attr_get(env, obj, la, NULL);
	if (rc)
		GOTO(out_unlock, rc);
	/*
	 * If it is a directory, we will also check whether the
	 * directory is empty.
	 * la_flags = 0 : Empty.
	 *          = 1 : Not empty.
	 */
	la->la_flags = 0;
	if (S_ISDIR(la->la_mode)) {
		struct dt_it		*it;
		const struct dt_it_ops	*iops;

		if (!dt_try_as_dir(env, obj))
			GOTO(out_unlock, rc = -ENOTDIR);

		iops = &obj->do_index_ops->dio_it;
		it = iops->init(env, obj, LUDA_64BITHASH, BYPASS_CAPA);
		if (!IS_ERR(it)) {
			int  result;
			result = iops->get(env, it, (const void *)"");
			if (result > 0) {
				int i;
				for (result = 0, i = 0; result == 0 && i < 3;
				     ++i)
					result = iops->next(env, it);
				if (result == 0)
					la->la_flags = 1;
			} else if (result == 0)
				/*
				 * Huh? Index contains no zero key?
				 */
				rc = -EIO;

			iops->put(env, it);
			iops->fini(env, it);
		}
	}

	obdo->o_valid = 0;
	obdo_from_la(obdo, la, la->la_valid);
	obdo_cpu_to_le(obdo, obdo);
	lustre_set_wire_obdo(NULL, obdo, obdo);

out_unlock:
	dt_read_unlock(env, obj);

	CDEBUG(D_INFO, "%s: insert attr get reply %p index %d: rc = %d\n",
	       tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply,
	       0, rc);

	update_insert_reply(tti->tti_u.update.tti_update_reply, obdo,
			    sizeof(*obdo), 0, rc);
	RETURN(rc);
}
Beispiel #20
0
/*
 * Set up quota directory (either "quota_master" or "quota_slave") for a QMT or
 * QSD instance. This function is also used to create per-pool directory on
 * the quota master.
 * The directory is created with a local sequence if it does not exist already.
 * This function is called at ->ldo_prepare time when the full device stack is
 * configured.
 *
 * \param env  - is the environment passed by the caller
 * \param dev  - is the dt_device where to create the quota directory
 * \param parent  - is the parent directory. If not specified, the directory
 *                  will be created under the root directory
 * \param name - is the name of quota directory to be created
 *
 * \retval     - pointer to quota root dt_object on success, appropriate error
 *               on failure
 */
struct dt_object *lquota_disk_dir_find_create(const struct lu_env *env,
					      struct dt_device *dev,
					      struct dt_object *parent,
					      const char *name)
{
	struct lquota_thread_info	*qti = lquota_info(env);
	struct dt_object		*qt_dir = NULL;
	struct local_oid_storage	*los = NULL;
	int				 rc;
	ENTRY;

	/* Set up local storage to create the quota directory.
	 * We use the sequence reserved for local named objects */
	lu_local_name_obj_fid(&qti->qti_fid, 1);
	rc = local_oid_storage_init(env, dev, &qti->qti_fid, &los);
	if (rc)
		RETURN(ERR_PTR(rc));

	if (parent == NULL) {
		/* Fetch dt object associated with root directory */
		rc = dt_root_get(env, dev, &qti->qti_fid);
		if (rc)
			GOTO(out, rc);

		parent = dt_locate_at(env, dev, &qti->qti_fid,
				      dev->dd_lu_dev.ld_site->ls_top_dev, NULL);
		if (IS_ERR(parent))
			GOTO(out, rc = PTR_ERR(parent));
	} else {
		lu_object_get(&parent->do_lu);
	}

	/* create quota directory to be used for all quota index files */
	qt_dir = local_file_find_or_create(env, los, parent, name, S_IFDIR |
					   S_IRUGO | S_IWUSR | S_IXUGO);
	if (IS_ERR(qt_dir))
		GOTO(out, rc = PTR_ERR(qt_dir));

	/* local_oid_storage_fini() will finalize the local storage device,
	 * we have to open the object in another device stack */
	qti->qti_fid = qt_dir->do_lu.lo_header->loh_fid;
	lu_object_put_nocache(env, &qt_dir->do_lu);
	qt_dir = dt_locate(env, dev, &qti->qti_fid);
	if (IS_ERR(qt_dir))
		GOTO(out, rc = PTR_ERR(qt_dir));

	if (!dt_try_as_dir(env, qt_dir))
		GOTO(out, rc = -ENOTDIR);
	EXIT;
out:
	if (parent != NULL && !IS_ERR(parent))
		lu_object_put(env, &parent->do_lu);
	if (los != NULL)
		local_oid_storage_fini(env, los);
	if (rc) {
		if (qt_dir != NULL && !IS_ERR(qt_dir))
			lu_object_put(env, &qt_dir->do_lu);
		qt_dir = ERR_PTR(rc);
	}
	return qt_dir;
}
Beispiel #21
0
/**
 * \retval +ve	repaired
 * \retval 0	no need to repair
 * \retval -ve	error cases
 */
static int lfsck_namespace_double_scan_one(const struct lu_env *env,
					   struct lfsck_component *com,
					   struct dt_object *child, __u8 flags)
{
	struct lfsck_thread_info *info	  = lfsck_env_info(env);
	struct lu_attr		 *la	  = &info->lti_la;
	struct lu_name		 *cname	  = &info->lti_name;
	struct lu_fid		 *pfid	  = &info->lti_fid;
	struct lu_fid		 *cfid	  = &info->lti_fid2;
	struct lfsck_instance	*lfsck	  = com->lc_lfsck;
	struct lfsck_bookmark	*bk	  = &lfsck->li_bookmark_ram;
	struct lfsck_namespace	*ns	  = com->lc_file_ram;
	struct linkea_data	 ldata	  = { 0 };
	struct thandle		*handle   = NULL;
	bool			 locked   = false;
	bool			 update	  = false;
	int			 rc;
	ENTRY;

	if (com->lc_journal) {

again:
		LASSERT(!locked);

		update = false;
		com->lc_journal = 1;
		handle = dt_trans_create(env, lfsck->li_next);
		if (IS_ERR(handle))
			RETURN(rc = PTR_ERR(handle));

		rc = dt_declare_xattr_set(env, child,
			lfsck_buf_get_const(env, NULL, DEFAULT_LINKEA_SIZE),
			XATTR_NAME_LINK, 0, handle);
		if (rc != 0)
			GOTO(stop, rc);

		rc = dt_trans_start(env, lfsck->li_next, handle);
		if (rc != 0)
			GOTO(stop, rc);

		dt_write_lock(env, child, MOR_TGT_CHILD);
		locked = true;
	}

	if (unlikely(lfsck_is_dead_obj(child)))
		GOTO(stop, rc = 0);

	rc = dt_attr_get(env, child, la, BYPASS_CAPA);
	if (rc == 0)
		rc = lfsck_links_read(env, child, &ldata);
	if (rc != 0) {
		if ((bk->lb_param & LPF_DRYRUN) &&
		    (rc == -EINVAL || rc == -ENODATA))
			rc = 1;

		GOTO(stop, rc);
	}

	linkea_first_entry(&ldata);
	while (ldata.ld_lee != NULL) {
		struct dt_object *parent = NULL;

		rc = lfsck_linkea_entry_unpack(lfsck, &ldata, cname, pfid);
		if (rc > 0)
			update = true;

		if (!fid_is_sane(pfid))
			goto shrink;

		parent = lfsck_object_find(env, lfsck, pfid);
		if (parent == NULL)
			goto shrink;
		else if (IS_ERR(parent))
			GOTO(stop, rc = PTR_ERR(parent));

		if (!dt_object_exists(parent))
			goto shrink;

		/* XXX: Currently, skip remote object, the consistency for
		 *	remote object will be processed in LFSCK phase III. */
		if (dt_object_remote(parent)) {
			lfsck_object_put(env, parent);
			linkea_next_entry(&ldata);
			continue;
		}

		if (unlikely(!dt_try_as_dir(env, parent)))
			goto shrink;

		/* To guarantee the 'name' is terminated with '0'. */
		memcpy(info->lti_key, cname->ln_name, cname->ln_namelen);
		info->lti_key[cname->ln_namelen] = 0;
		cname->ln_name = info->lti_key;
		rc = dt_lookup(env, parent, (struct dt_rec *)cfid,
			       (const struct dt_key *)cname->ln_name,
			       BYPASS_CAPA);
		if (rc != 0 && rc != -ENOENT) {
			lfsck_object_put(env, parent);
			GOTO(stop, rc);
		}

		if (rc == 0) {
			if (lu_fid_eq(cfid, lfsck_dto2fid(child))) {
				lfsck_object_put(env, parent);
				linkea_next_entry(&ldata);
				continue;
			}

			goto shrink;
		}

		/* If there is no name entry in the parent dir and the object
		 * link count is less than the linkea entries count, then the
		 * linkea entry should be removed. */
		if (ldata.ld_leh->leh_reccount > la->la_nlink)
			goto shrink;

		/* XXX: For the case of there is a linkea entry, but without
		 *	name entry pointing to the object and its hard links
		 *	count is not less than the object name entries count,
		 *	then seems we should add the 'missed' name entry back
		 *	to namespace, but before LFSCK phase III finished, we
		 *	do not know whether the object has some inconsistency
		 *	on other MDTs. So now, do NOT add the name entry back
		 *	to the namespace, but keep the linkEA entry. LU-2914 */
		lfsck_object_put(env, parent);
		linkea_next_entry(&ldata);
		continue;

shrink:
		if (parent != NULL)
			lfsck_object_put(env, parent);
		if (bk->lb_param & LPF_DRYRUN)
			RETURN(1);

		CDEBUG(D_LFSCK, "Remove linkEA: "DFID"[%.*s], "DFID"\n",
		       PFID(lfsck_dto2fid(child)), cname->ln_namelen, cname->ln_name,
		       PFID(pfid));
		linkea_del_buf(&ldata, cname);
		update = true;
	}

	if (update) {
		if (!com->lc_journal) {
			com->lc_journal = 1;
			goto again;
		}

		rc = lfsck_links_write(env, child, &ldata, handle);
	}

	GOTO(stop, rc);

stop:
	if (locked) {
	/* XXX: For the case linkea entries count does not match the object hard
	 *	links count, we cannot update the later one simply. Before LFSCK
	 *	phase III finished, we cannot know whether there are some remote
	 *	name entries to be repaired or not. LU-2914 */
		if (rc == 0 && !lfsck_is_dead_obj(child) &&
		    ldata.ld_leh != NULL &&
		    ldata.ld_leh->leh_reccount != la->la_nlink)
			CWARN("%s: the object "DFID" linkEA entry count %u "
			      "may not match its hardlink count %u\n",
			      lfsck_lfsck2name(lfsck), PFID(cfid),
			      ldata.ld_leh->leh_reccount, la->la_nlink);

		dt_write_unlock(env, child);
	}

	if (handle != NULL)
		dt_trans_stop(env, lfsck->li_next, handle);

	if (rc == 0 && update) {
		ns->ln_objs_nlink_repaired++;
		rc = 1;
	}

	return rc;
}
Beispiel #22
0
static int lfsck_namespace_reset(const struct lu_env *env,
				 struct lfsck_component *com, bool init)
{
	struct lfsck_instance	*lfsck = com->lc_lfsck;
	struct lfsck_namespace	*ns    = com->lc_file_ram;
	struct dt_object	*root;
	struct dt_object	*dto;
	int			 rc;
	ENTRY;

	root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid);
	if (IS_ERR(root))
		RETURN(PTR_ERR(root));

	if (unlikely(!dt_try_as_dir(env, root))) {
		lu_object_put(env, &root->do_lu);
		RETURN(-ENOTDIR);
	}

	down_write(&com->lc_sem);
	if (init) {
		memset(ns, 0, sizeof(*ns));
	} else {
		__u32 count = ns->ln_success_count;
		__u64 last_time = ns->ln_time_last_complete;

		memset(ns, 0, sizeof(*ns));
		ns->ln_success_count = count;
		ns->ln_time_last_complete = last_time;
	}
	ns->ln_magic = LFSCK_NAMESPACE_MAGIC;
	ns->ln_status = LS_INIT;

	rc = local_object_unlink(env, lfsck->li_bottom, root,
				 lfsck_namespace_name);
	if (rc != 0)
		GOTO(out, rc);

	lfsck_object_put(env, com->lc_obj);
	com->lc_obj = NULL;
	dto = local_index_find_or_create(env, lfsck->li_los, root,
					 lfsck_namespace_name,
					 S_IFREG | S_IRUGO | S_IWUSR,
					 &dt_lfsck_features);
	if (IS_ERR(dto))
		GOTO(out, rc = PTR_ERR(dto));

	com->lc_obj = dto;
	rc = dto->do_ops->do_index_try(env, dto, &dt_lfsck_features);
	if (rc != 0)
		GOTO(out, rc);

	rc = lfsck_namespace_store(env, com, true);

	GOTO(out, rc);

out:
	up_write(&com->lc_sem);
	lu_object_put(env, &root->do_lu);
	return rc;
}
Beispiel #23
0
static int out_attr_get(struct tgt_session_info *tsi)
{
	const struct lu_env	*env = tsi->tsi_env;
	struct tgt_thread_info	*tti = tgt_th_info(env);
	struct obdo		*obdo = &tti->tti_u.update.tti_obdo;
	struct lu_attr		*la = &tti->tti_attr;
	struct dt_object        *obj = tti->tti_u.update.tti_dt_object;
	int			idx = tti->tti_u.update.tti_update_reply_index;
	int			rc;

	ENTRY;

	if (!lu_object_exists(&obj->do_lu)) {
		/* Usually, this will be called when the master MDT try
		 * to init a remote object(see osp_object_init), so if
		 * the object does not exist on slave, we need set BANSHEE flag,
		 * so the object can be removed from the cache immediately */
		set_bit(LU_OBJECT_HEARD_BANSHEE,
			&obj->do_lu.lo_header->loh_flags);
		RETURN(-ENOENT);
	}

	dt_read_lock(env, obj, MOR_TGT_CHILD);
	rc = dt_attr_get(env, obj, la, NULL);
	if (rc)
		GOTO(out_unlock, rc);
	/*
	 * If it is a directory, we will also check whether the
	 * directory is empty.
	 * la_flags = 0 : Empty.
	 *          = 1 : Not empty.
	 */
	la->la_flags = 0;
	if (S_ISDIR(la->la_mode)) {
		struct dt_it		*it;
		const struct dt_it_ops	*iops;

		if (!dt_try_as_dir(env, obj))
			GOTO(out_unlock, rc = -ENOTDIR);

		iops = &obj->do_index_ops->dio_it;
		it = iops->init(env, obj, LUDA_64BITHASH, BYPASS_CAPA);
		if (!IS_ERR(it)) {
			int  result;
			result = iops->get(env, it, (const void *)"");
			if (result > 0) {
				int i;
				for (result = 0, i = 0; result == 0 && i < 3;
				     ++i)
					result = iops->next(env, it);
				if (result == 0)
					la->la_flags = 1;
			} else if (result == 0)
				/*
				 * Huh? Index contains no zero key?
				 */
				rc = -EIO;

			iops->put(env, it);
			iops->fini(env, it);
		}
	}

	obdo->o_valid = 0;
	obdo_from_la(obdo, la, la->la_valid);
	obdo_cpu_to_le(obdo, obdo);
	lustre_set_wire_obdo(NULL, obdo, obdo);

out_unlock:
	dt_read_unlock(env, obj);

	CDEBUG(D_INFO, "%s: insert attr get reply %p index %d: rc = %d\n",
	       tgt_name(tsi->tsi_tgt), tti->tti_u.update.tti_update_reply,
	       0, rc);

	object_update_result_insert(tti->tti_u.update.tti_update_reply, obdo,
				    sizeof(*obdo), idx, rc);

	RETURN(rc);
}
Beispiel #24
0
int lfsck_namespace_setup(const struct lu_env *env,
			  struct lfsck_instance *lfsck)
{
	struct lfsck_component	*com;
	struct lfsck_namespace	*ns;
	struct dt_object	*root = NULL;
	struct dt_object	*obj;
	int			 rc;
	ENTRY;

	LASSERT(lfsck->li_master);

	OBD_ALLOC_PTR(com);
	if (com == NULL)
		RETURN(-ENOMEM);

	CFS_INIT_LIST_HEAD(&com->lc_link);
	CFS_INIT_LIST_HEAD(&com->lc_link_dir);
	init_rwsem(&com->lc_sem);
	atomic_set(&com->lc_ref, 1);
	com->lc_lfsck = lfsck;
	com->lc_type = LT_NAMESPACE;
	com->lc_ops = &lfsck_namespace_ops;
	com->lc_file_size = sizeof(struct lfsck_namespace);
	OBD_ALLOC(com->lc_file_ram, com->lc_file_size);
	if (com->lc_file_ram == NULL)
		GOTO(out, rc = -ENOMEM);

	OBD_ALLOC(com->lc_file_disk, com->lc_file_size);
	if (com->lc_file_disk == NULL)
		GOTO(out, rc = -ENOMEM);

	root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid);
	if (IS_ERR(root))
		GOTO(out, rc = PTR_ERR(root));

	if (unlikely(!dt_try_as_dir(env, root)))
		GOTO(out, rc = -ENOTDIR);

	obj = local_index_find_or_create(env, lfsck->li_los, root,
					 lfsck_namespace_name,
					 S_IFREG | S_IRUGO | S_IWUSR,
					 &dt_lfsck_features);
	if (IS_ERR(obj))
		GOTO(out, rc = PTR_ERR(obj));

	com->lc_obj = obj;
	rc = obj->do_ops->do_index_try(env, obj, &dt_lfsck_features);
	if (rc != 0)
		GOTO(out, rc);

	rc = lfsck_namespace_load(env, com);
	if (rc > 0)
		rc = lfsck_namespace_reset(env, com, true);
	else if (rc == -ENODATA)
		rc = lfsck_namespace_init(env, com);
	if (rc != 0)
		GOTO(out, rc);

	ns = com->lc_file_ram;
	switch (ns->ln_status) {
	case LS_INIT:
	case LS_COMPLETED:
	case LS_FAILED:
	case LS_STOPPED:
		spin_lock(&lfsck->li_lock);
		cfs_list_add_tail(&com->lc_link, &lfsck->li_list_idle);
		spin_unlock(&lfsck->li_lock);
		break;
	default:
		CERROR("%s: unknown lfsck_namespace status: rc = %u\n",
		       lfsck_lfsck2name(lfsck), ns->ln_status);
		/* fall through */
	case LS_SCANNING_PHASE1:
	case LS_SCANNING_PHASE2:
		/* No need to store the status to disk right now.
		 * If the system crashed before the status stored,
		 * it will be loaded back when next time. */
		ns->ln_status = LS_CRASHED;
		/* fall through */
	case LS_PAUSED:
	case LS_CRASHED:
		spin_lock(&lfsck->li_lock);
		cfs_list_add_tail(&com->lc_link, &lfsck->li_list_scan);
		cfs_list_add_tail(&com->lc_link_dir, &lfsck->li_list_dir);
		spin_unlock(&lfsck->li_lock);
		break;
	}

	GOTO(out, rc = 0);

out:
	if (root != NULL && !IS_ERR(root))
		lu_object_put(env, &root->do_lu);
	if (rc != 0)
		lfsck_component_cleanup(env, com);
	return rc;
}