Esempio n. 1
0
static struct dt_key *mdd_orphan_key_fill(const struct lu_env *env,
					  const struct lu_fid *lf)
{
	char *key = mdd_env_info(env)->mti_key;

	LASSERT(key);
	snprintf(key, sizeof(mdd_env_info(env)->mti_key),
		 DFID_NOBRACE, PFID(lf));

	return (struct dt_key *)key;
}
Esempio n. 2
0
/* compatibility with orphan files created in versions before 2.11 */
static struct dt_key *mdd_orphan_key_fill_20(const struct lu_env *env,
					     const struct lu_fid *lf)
{
	char *key = mdd_env_info(env)->mti_key;

	LASSERT(key);
	snprintf(key, sizeof(mdd_env_info(env)->mti_key),
		 ORPHAN_FILE_NAME_FORMAT_20,
		 fid_seq(lf), fid_oid(lf), fid_ver(lf), ORPH_OP_UNLINK);

	return (struct dt_key *)key;
}
Esempio n. 3
0
static int mdd_convert_lma(const struct lu_env *env, struct mdd_device *mdd,
			   struct mdd_object *o)
{
	struct lustre_mdt_attrs	*lma;
	struct thandle		*th;
	struct lu_fid		 fid;
	struct lu_buf		 buf;
	int			 rc;
	ENTRY;

	lu_root_fid(&fid);

	lma = (struct lustre_mdt_attrs *)&mdd_env_info(env)->mti_xattr_buf;
	lustre_lma_init(lma, &fid, 0, 0);
	lustre_lma_swab(lma);
	buf.lb_buf = lma;
	buf.lb_len = sizeof(*lma);

	th = dt_trans_create(env, mdd->mdd_child);
	if (IS_ERR(th))
		RETURN(PTR_ERR(th));
	rc = mdo_declare_xattr_set(env, o, &buf, XATTR_NAME_LMA, 0, th);
	if (rc)
		GOTO(out, rc);
	rc = dt_trans_start_local(env, mdd->mdd_child, th);
	if (rc)
		GOTO(out, rc);
	rc = mdo_xattr_set(env, o, &buf, XATTR_NAME_LMA, 0, th, BYPASS_CAPA);
out:
	dt_trans_stop(env, mdd->mdd_child, th);
	RETURN(rc);
}
Esempio n. 4
0
/**
 * destroy osd object on mdd and associated ost objects.
 *
 * \param obj orphan object
 * \param mdd used for sending llog msg to osts
 *
 * \retval  0   success
 * \retval -ve  error
 */
static int orphan_object_kill(const struct lu_env *env,
                              struct mdd_object *obj,
                              struct mdd_device *mdd,
                              struct thandle *th)
{
        struct lu_attr *la = &mdd_env_info(env)->mti_la;
        int rc = 0;
        ENTRY;

        /* No need to lock this object as its recovery phase, and
         * no other thread can access it. But we need to lock it
         * as its precondition for osd api we using. */

        mdo_ref_del(env, obj, th);
        if (S_ISDIR(mdd_object_type(obj))) {
                mdo_ref_del(env, obj, th);
                mdd_orphan_ref_del(env, mdd, th);
        } else {
                /* regular file , cleanup linked ost objects */
                rc = mdd_la_get(env, obj, la, BYPASS_CAPA);
                if (rc == 0)
                        rc = mdd_lov_destroy(env, mdd, obj, la);
        }
        RETURN(rc);
}
Esempio n. 5
0
static struct dt_key* orph_key_fill_18(const struct lu_env *env,
                                       const struct lu_fid *lf)
{
	char *key = mdd_env_info(env)->mti_key;
        int rc;

        LASSERT(key);
        rc = snprintf(key, NAME_MAX + 1, ORPHAN_FILE_NAME_FORMAT_18,
                      (unsigned long long)fid_seq(lf), fid_oid(lf));
        if (rc > 0)
                return (struct dt_key*) key;
        else
                return ERR_PTR(rc);
}
Esempio n. 6
0
/** Add a CL_MARK record to the changelog
 * \param mdd
 * \param markerflags - CLM_*
 * \retval 0 ok
 */
int mdd_changelog_write_header(const struct lu_env *env,
			       struct mdd_device *mdd, int markerflags)
{
	struct obd_device		*obd = mdd2obd_dev(mdd);
	struct llog_changelog_rec	*rec;
	struct lu_buf			*buf;
	struct llog_ctxt		*ctxt;
	int				 reclen;
	int				 len = strlen(obd->obd_name);
	int				 rc;

	ENTRY;

	if (mdd->mdd_cl.mc_mask & (1 << CL_MARK)) {
		mdd->mdd_cl.mc_starttime = cfs_time_current_64();
		RETURN(0);
	}

	reclen = llog_data_len(sizeof(*rec) + len);
	buf = lu_buf_check_and_alloc(&mdd_env_info(env)->mti_big_buf, reclen);
	if (buf->lb_buf == NULL)
		RETURN(-ENOMEM);
	rec = buf->lb_buf;

        rec->cr.cr_flags = CLF_VERSION;
        rec->cr.cr_type = CL_MARK;
        rec->cr.cr_namelen = len;
	memcpy(changelog_rec_name(&rec->cr), obd->obd_name, rec->cr.cr_namelen);
        /* Status and action flags */
	rec->cr.cr_markerflags = mdd->mdd_cl.mc_flags | markerflags;
	rec->cr_hdr.lrh_len = llog_data_len(changelog_rec_size(&rec->cr) +
					    rec->cr.cr_namelen);
	rec->cr_hdr.lrh_type = CHANGELOG_REC;
	rec->cr.cr_time = cl_time();
	spin_lock(&mdd->mdd_cl.mc_lock);
	rec->cr.cr_index = ++mdd->mdd_cl.mc_index;
	spin_unlock(&mdd->mdd_cl.mc_lock);

	ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT);
	LASSERT(ctxt);

	rc = llog_cat_add(env, ctxt->loc_handle, &rec->cr_hdr, NULL);
	if (rc > 0)
		rc = 0;
	llog_ctxt_put(ctxt);

	/* assume on or off event; reset repeat-access time */
	mdd->mdd_cl.mc_starttime = cfs_time_current_64();
	RETURN(rc);
}
Esempio n. 7
0
static inline int mdd_orphan_insert_obj(const struct lu_env *env,
					struct mdd_device *mdd,
					struct mdd_object *obj,
					__u32 op, struct thandle *th)
{
	struct dt_insert_rec	*rec	= &mdd_env_info(env)->mti_dt_rec;
	struct dt_object	*dor	= mdd->mdd_orphans;
	const struct lu_fid	*lf	= mdo2fid(obj);
	struct dt_key		*key	= orph_key_fill(env, lf, op);

	rec->rec_fid = lf;
	rec->rec_type = mdd_object_type(obj);

	return dt_insert(env, dor, (const struct dt_rec *)rec, key, th, 1);
}
Esempio n. 8
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);
	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));

        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, rc = 0);

        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, 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, 1);

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

        mdd_orphan_write_unlock(env, mdd);

        RETURN(rc);
}
Esempio n. 9
0
int orph_declare_index_insert(const struct lu_env *env,
			      struct mdd_object *obj,
			      umode_t mode, struct thandle *th)
{
	struct dt_insert_rec	*rec = &mdd_env_info(env)->mti_dt_rec;
	struct mdd_device	*mdd = mdo2mdd(&obj->mod_obj);
	struct dt_key		*key;
	int			rc;

	key = orph_key_fill(env, mdo2fid(obj), ORPH_OP_UNLINK);

	rec->rec_fid = mdo2fid(obj);
	rec->rec_type = mode;
	rc = dt_declare_insert(env, mdd->mdd_orphans,
			       (const struct dt_rec *)rec, key, th);
	if (rc != 0)
		return rc;

	rc = mdo_declare_ref_add(env, obj, th);
	if (rc)
		return rc;

	if (!S_ISDIR(mode))
		return 0;

	rc = mdo_declare_ref_add(env, obj, th);
	if (rc)
		return rc;

	rc = dt_declare_ref_add(env, mdd->mdd_orphans, th);
	if (rc)
		return rc;

	rc = mdo_declare_index_delete(env, obj, dotdot, th);
	if (rc)
		return rc;

	rc = mdo_declare_index_insert(env, obj,
				      lu_object_fid(&mdd->mdd_orphans->do_lu),
				      S_IFDIR, dotdot, th);

	return rc;
}
Esempio n. 10
0
/**
 * delete unreferenced files and directories in the PENDING directory
 *
 * Files that remain in PENDING after client->MDS recovery has completed
 * have to be referenced (opened) by some client during recovery, or they
 * will be deleted here (for clients that did not complete recovery).
 *
 * \param mdd  MDD device finishing recovery
 *
 * \retval 0   success
 * \retval -ve error
 */
static int orph_index_iterate(const struct lu_env *env,
			      struct mdd_device *mdd)
{
	struct dt_object *dor = mdd->mdd_orphans;
	struct lu_dirent *ent = &mdd_env_info(env)->mti_ent;
	const struct dt_it_ops *iops;
	struct dt_it     *it;
	struct lu_fid     fid;
        int               key_sz = 0;
        int               rc;
        __u64             cookie;
        ENTRY;

        /* In recovery phase, do not need for any lock here */
        iops = &dor->do_index_ops->dio_it;
        it = iops->init(env, dor, LUDA_64BITHASH, BYPASS_CAPA);
        if (IS_ERR(it)) {
                rc = PTR_ERR(it);
                CERROR("%s: cannot clean PENDING: rc = %d\n",
		       mdd2obd_dev(mdd)->obd_name, rc);
                GOTO(out, rc);
        }

        rc = iops->load(env, it, 0);
        if (rc < 0)
                GOTO(out_put, rc);
        if (rc == 0) {
                CERROR("%s: error loading iterator to clean PENDING\n",
		       mdd2obd_dev(mdd)->obd_name);
                /* Index contains no zero key? */
                GOTO(out_put, rc = -EIO);
        }

	do {
		key_sz = iops->key_size(env, it);
		/* filter out "." and ".." entries from PENDING dir. */
		if (key_sz < 8)
			goto next;

		rc = iops->rec(env, it, (struct dt_rec *)ent, LUDA_64BITHASH);
		if (rc != 0) {
			CERROR("%s: fail to get FID for orphan it: rc = %d\n",
			       mdd2obd_dev(mdd)->obd_name, rc);
			goto next;
		}

		fid_le_to_cpu(&fid, &ent->lde_fid);
		if (!fid_is_sane(&fid)) {
			CERROR("%s: bad FID "DFID" cleaning PENDING\n",
			       mdd2obd_dev(mdd)->obd_name, PFID(&fid));
			goto next;
		}

		/* kill orphan object */
		cookie = iops->store(env, it);
		iops->put(env, it);
		rc = orph_key_test_and_del(env, mdd, &fid,
					   (struct dt_key *)ent->lde_name);

		/* after index delete reset iterator */
		if (rc == 0)
			rc = iops->get(env, it, (const void *)"");
		else
			rc = iops->load(env, it, cookie);
next:
		rc = iops->next(env, it);
	} while (rc == 0);

	GOTO(out_put, rc = 0);
out_put:
	iops->put(env, it);
	iops->fini(env, it);

out:
	return rc;
}
Esempio n. 11
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);
}
Esempio n. 12
0
static int mdd_fix_children(const struct lu_env *env,
			    struct mdd_device *mdd,
			    struct dt_object *o)
{
	struct mdd_thread_info *info = mdd_env_info(env);
	const struct dt_it_ops *iops;
	struct lu_name		name;
	struct dt_it	       *it;
	struct lu_dirent       *ent;
	int			rc;
	ENTRY;

	/* scan /ROOT and update all ".." and linkEAs */
	ent = (struct lu_dirent *)&info->mti_xattr_buf;
	iops = &o->do_index_ops->dio_it;

	it = iops->init(env, o, LUDA_64BITHASH, BYPASS_CAPA);
	if (IS_ERR(it)) {
		rc = PTR_ERR(it);
		CERROR("%s: can't initialize the iterator: rc = %d\n",
		       mdd2obd_dev(mdd)->obd_name, rc);
		GOTO(out, rc);
	}

	rc = iops->load(env, it, 0);
	if (rc <= 0)
		GOTO(out_put, rc);

	do {
		rc = iops->key_size(env, it);
		if (rc == 0)
			goto next;

		/* calculate max space required for lu_dirent */
		rc = lu_dirent_calc_size(rc, 0);
		LASSERT(rc <= sizeof(info->mti_xattr_buf));

		rc = iops->rec(env, it, (struct dt_rec *)ent, LUDA_TYPE);
		if (rc == 0) {
			CDEBUG(D_OTHER, "convert %*s -> "DFID"\n",
			       ent->lde_namelen, ent->lde_name,
			       PFID(&ent->lde_fid));
			name.ln_namelen = ent->lde_namelen;
			name.ln_name = ent->lde_name;
			rc = mdd_convert_object(env, mdd, &ent->lde_fid, &name);
			if (rc) {
				CERROR("%s: can't convert "DFID": rc = %d\n",
				       mdd2obd_dev(mdd)->obd_name,
				       PFID(&ent->lde_fid), rc);
				break;
			}
		}

next:
		rc = iops->next(env, it);
	} while (rc == 0);
	if (rc > 0)
		rc = 0;

out_put:
	iops->put(env, it);
	iops->fini(env, it);
out:
	RETURN(rc);
}
Esempio n. 13
0
static int orph_index_iterate(const struct lu_env *env,
                              struct mdd_device *mdd)
{
        struct dt_object *dor = mdd->mdd_orphans;
        char             *mti_key = mdd_env_info(env)->mti_orph_key;
        const struct dt_it_ops *iops;
        struct dt_it     *it;
        char             *key;
        struct lu_fid     fid;
        int               result = 0;
        int               key_sz = 0;
        int               rc;
        __u64             cookie;
        ENTRY;

        /* In recovery phase, do not need for any lock here */

        iops = &dor->do_index_ops->dio_it;
        it = iops->init(env, dor, BYPASS_CAPA);
        if (it != NULL) {
                result = iops->load(env, it, 0);
                if (result > 0) {
                        /* main cycle */
                        do {

                                key = (void *)iops->key(env, it);
                                if (IS_ERR(key)) {
                                        CERROR("key failed when clean pending.\n");
                                        goto next;
                                }
                                key_sz = iops->key_size(env, it);

                                /* filter out "." and ".." entries from
                                 * PENDING dir. */
                                if (key_sz < 8)
                                        goto next;

                                memcpy(mti_key, key, key_sz);
                                mti_key[key_sz] = 0;

                                if (orphan_key_to_fid(mti_key, &fid))
                                        goto next;
                                if (!fid_is_sane(&fid)) {
                                        CERROR("fid is not sane when clean pending.\n");
                                        goto next;
                                }

                                /* kill orphan object */
                                cookie =  iops->store(env, it);
                                iops->put(env, it);
                                rc = orph_key_test_and_del(env, mdd, &fid,
                                                (struct dt_key *)mti_key);

                                /* after index delete reset iterator */
                                if (!rc)
                                        result = iops->get(env, it,
                                                           (const void *)"");
                                else
                                        result = iops->load(env, it, cookie);
next:
                                result = iops->next(env, it);
                        } while (result == 0);
                        result = 0;
                } else if (result == 0) {
                        CERROR("Input/Output for clean pending.\n");
                        /* Index contains no zero key? */
                        result = -EIO;
                }
                iops->put(env, it);
                iops->fini(env, it);
        } else {
                CERROR("not enough memory for clean pending.\n");
                result = -ENOMEM;
        }

        RETURN(result);
}