/* Returns bytes read on success and a negative value on failure.
 * If zero bytes are read it will be treated as failure as such
 * zero cannot be returned from this function.
 */
int read_proc_entry(char *proc_path, char *buf, int len)
{
	int rc, fd;

	memset(buf, 0, len);

	fd = open(proc_path, O_RDONLY);
	if (fd < 0) {
		llapi_error(LLAPI_MSG_ERROR, -errno, "cannot open '%s'",
			    proc_path);
		return -2;
	}

	rc = read(fd, buf, len - 1);
	if (rc < 0) {
		llapi_error(LLAPI_MSG_ERROR, -errno,
			    "error reading from '%s'", proc_path);
		rc = -3;
	} else if (rc == 0) {
		llapi_err_noerrno(LLAPI_MSG_ERROR,
				  "read zero bytes from '%s'", proc_path);
		rc = -4;
	} else if (buf[rc - 1] == '\n') {
		buf[rc - 1] = '\0'; /* Remove trailing newline */
	}

	close(fd);

	return rc;
}
/*
 * Give file access advices
 *
 * \param fd       File to give advice on.
 * \param ladvise  Advice to give.
 *
 * \retval 0 on success.
 * \retval -errno on failure.
 */
int llapi_ladvise(int fd, unsigned long long flags, int num_advise,
		  struct lu_ladvise *ladvise)
{
	int rc;
	struct ladvise_hdr *ladvise_hdr;

	if (num_advise < 1 || num_advise >= LAH_COUNT_MAX) {
		errno = EINVAL;
		llapi_error(LLAPI_MSG_ERROR, -EINVAL,
			    "bad advice number %d", num_advise);
		return -1;
	}

	ladvise_hdr = calloc(1, offsetof(typeof(*ladvise_hdr),
			     lah_advise[num_advise]));
	if (ladvise_hdr == NULL) {
		errno = ENOMEM;
		llapi_error(LLAPI_MSG_ERROR, -ENOMEM, "not enough memory");
		return -1;
	}
	ladvise_hdr->lah_magic = LADVISE_MAGIC;
	ladvise_hdr->lah_count = num_advise;
	ladvise_hdr->lah_flags = flags & LF_MASK;
	memcpy(ladvise_hdr->lah_advise, ladvise, sizeof(*ladvise) * num_advise);

	rc = ioctl(fd, LL_IOC_LADVISE, ladvise_hdr);
	if (rc < 0) {
		llapi_error(LLAPI_MSG_ERROR, -errno, "cannot give advice");
		return -1;
	}
	return 0;
}
Example #3
0
/**
 * Given a path to a FIFO, create a filehandle for nonblocking writes to it.
 * Intended to be used for copytool monitoring processes that read an
 * event stream from the FIFO. Events written in the absence of a reader
 * are lost.
 *
 * \param path               Path to monitor FIFO.
 *
 * \retval 0 on success.
 * \retval -errno on error.
 */
int llapi_hsm_register_event_fifo(const char *path)
{
	int rc;
	int read_fd;
	struct stat statbuf;

	/* Create the FIFO if necessary. */
	if ((mkfifo(path, 0644) < 0) && (errno != EEXIST)) {
		llapi_error(LLAPI_MSG_ERROR, errno, "mkfifo(%s) failed", path);
		return -errno;
	}
	if (errno == EEXIST) {
		if (stat(path, &statbuf) < 0) {
			llapi_error(LLAPI_MSG_ERROR, errno, "mkfifo(%s) failed",
				    path);
			return -errno;
		}
		if (!S_ISFIFO(statbuf.st_mode) ||
		    ((statbuf.st_mode & 0777) != 0644)) {
			llapi_error(LLAPI_MSG_ERROR, errno, "%s exists but is "
				    "not a pipe or has a wrong mode", path);
			return -errno;
		}
	} else {
		created_hsm_event_fifo = true;
	}

	/* Open the FIFO for read so that the subsequent open for write
	 * doesn't immediately fail. */
	read_fd = open(path, O_RDONLY | O_NONBLOCK);
	if (read_fd < 0) {
		llapi_error(LLAPI_MSG_ERROR, errno,
			    "cannot open(%s) for read", path);
		return -errno;
	}

	/* Open the FIFO for writes, but don't block on waiting
	 * for a reader. */
	llapi_hsm_event_fd = open(path, O_WRONLY | O_NONBLOCK);
	rc = -errno;

	/* Now close the reader. An external monitoring process can
	 * now open the FIFO for reads. If no reader comes along the
	 * events are lost. NOTE: Only one reader at a time! */
	close(read_fd);

	if (llapi_hsm_event_fd < 0) {
		llapi_error(LLAPI_MSG_ERROR, -rc,
			    "cannot open(%s) for write", path);
		return rc;
	}

	/* Ignore SIGPIPEs -- can occur if the reader goes away. */
	signal(SIGPIPE, SIG_IGN);

	return 0;
}
Example #4
0
/**
 * Writes a JSON event to the monitor FIFO. Noop if no FIFO has been
 * registered.
 *
 * \param event              A list of llapi_json_items comprising a
 *                           single JSON-formatted event.
 *
 * \retval 0 on success.
 * \retval -errno on error.
 */
static int llapi_hsm_write_json_event(struct llapi_json_item_list **event)
{
	int				rc;
	char				time_string[40];
	char				json_buf[PIPE_BUF];
	FILE				*buf_file;
	time_t				event_time = time(0);
	struct tm			time_components;
	struct llapi_json_item_list	*json_items;

	/* Noop unless the event fd was initialized */
	if (llapi_hsm_event_fd < 0)
		return 0;

	if (event == NULL || *event == NULL)
		return -EINVAL;

	json_items = *event;

	localtime_r(&event_time, &time_components);

	if (strftime(time_string, sizeof(time_string), "%Y-%m-%d %T %z",
		     &time_components) == 0) {
		rc = -EINVAL;
		llapi_error(LLAPI_MSG_ERROR, rc, "strftime() failed");
		return rc;
	}

	rc = llapi_json_add_item(&json_items, "event_time", LLAPI_JSON_STRING,
				 time_string);
	if (rc < 0) {
		llapi_error(LLAPI_MSG_ERROR, -rc, "error in "
			    "llapi_json_add_item()");
		return rc;
	}

	buf_file = fmemopen(json_buf, sizeof(json_buf), "w");
	if (buf_file == NULL)
		return -errno;

	rc = llapi_json_write_list(event, buf_file);
	if (rc < 0) {
		fclose(buf_file);
		return rc;
	}

	fclose(buf_file);

	if (write(llapi_hsm_event_fd, json_buf, strlen(json_buf)) < 0) {
		/* Ignore write failures due to missing reader. */
		if (errno != EPIPE)
			return -errno;
	}

	return 0;
}
Example #5
0
/**
 * Import an existing hsm-archived file into Lustre.
 *
 * Caller must access file by (returned) newfid value from now on.
 *
 * \param dst      path to Lustre destination (e.g. /mnt/lustre/my/file).
 * \param archive  archive number.
 * \param st       struct stat buffer containing file ownership, perm, etc.
 * \param stripe_* Striping options.  Currently ignored, since the restore
 *                 operation will set the striping.  In V2, this striping might
 *                 be used.
 * \param newfid[out] Filled with new Lustre fid.
 */
int llapi_hsm_import(const char *dst, int archive, const struct stat *st,
		     unsigned long long stripe_size, int stripe_offset,
		     int stripe_count, int stripe_pattern, char *pool_name,
		     lustre_fid *newfid)
{
	struct hsm_user_import	 hui;
	int			 fd;
	int			 rc = 0;

	if (stripe_pattern == 0)
		stripe_pattern = LOV_PATTERN_RAID0;

	/* Create a non-striped file */
	fd = llapi_file_open_pool(dst, O_CREAT | O_WRONLY, st->st_mode,
				  stripe_size, stripe_offset, stripe_count,
				  stripe_pattern | LOV_PATTERN_F_RELEASED,
				  pool_name);
	if (fd < 0) {
		llapi_error(LLAPI_MSG_ERROR, fd,
			    "cannot create '%s' for import", dst);
		return fd;
	}

	/* Get the new fid in Lustre. Caller needs to use this fid
	   from now on. */
	rc = llapi_fd2fid(fd, newfid);
	if (rc != 0) {
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "cannot get fid of '%s' for import", dst);
		goto out_unlink;
	}

	hui.hui_uid = st->st_uid;
	hui.hui_gid = st->st_gid;
	hui.hui_mode = st->st_mode;
	hui.hui_size = st->st_size;
	hui.hui_archive_id = archive;
	hui.hui_atime = st->st_atime;
	hui.hui_atime_ns = st->st_atim.tv_nsec;
	hui.hui_mtime = st->st_mtime;
	hui.hui_mtime_ns = st->st_mtim.tv_nsec;
	rc = ioctl(fd, LL_IOC_HSM_IMPORT, &hui);
	if (rc != 0) {
		rc = -errno;
		llapi_error(LLAPI_MSG_ERROR, rc, "cannot import '%s'", dst);
		goto out_unlink;
	}

out_unlink:
	if (fd >= 0)
		close(fd);
	if (rc)
		unlink(dst);
	return rc;
}
Example #6
0
/** Create the destination volatile file for a restore operation.
 *
 * \param hcp        Private copyaction handle.
 * \param mdt_index  MDT index where to create the volatile file.
 * \param flags      Volatile file creation flags.
 * \return 0 on success.
 */
static int create_restore_volatile(struct hsm_copyaction_private *hcp,
				   int mdt_index, int open_flags)
{
	int			 rc;
	int			 fd;
	char			 parent[PATH_MAX + 1];
	const char		*mnt = hcp->ct_priv->mnt;
	struct hsm_action_item	*hai = &hcp->copy.hc_hai;

	rc = fid_parent(mnt, &hai->hai_fid, parent, sizeof(parent));
	if (rc < 0) {
		/* fid_parent() failed, try to keep on going */
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "cannot get parent path to restore "DFID" "
			    "using '%s'", PFID(&hai->hai_fid), mnt);
		snprintf(parent, sizeof(parent), "%s", mnt);
	}

	fd = llapi_create_volatile_idx(parent, mdt_index, open_flags);
	if (fd < 0)
		return fd;

	rc = fchown(fd, hcp->stat.st_uid, hcp->stat.st_gid);
	if (rc < 0)
		goto err_cleanup;

	rc = llapi_fd2fid(fd, &hai->hai_dfid);
	if (rc < 0)
		goto err_cleanup;

	hcp->data_fd = fd;

	return 0;

err_cleanup:
	hcp->data_fd = -1;
	close(fd);

	return rc;
}
Example #7
0
/**
 * Get metadata attributes of file by FID.
 *
 * Use the IOC_MDC_GETFILEINFO ioctl (to send a MDS_GETATTR_NAME RPC)
 * to get the attributes of the file identified by \a fid. This
 * returns only the attributes stored on the MDT and avoids taking
 * layout locks or accessing OST objects. It also bypasses the inode
 * cache. Attributes are returned in \a st.
 */
static int ct_md_getattr(const struct hsm_copytool_private *ct,
			 const struct lu_fid *fid,
			 lstat_t *st)
{
	struct lov_user_mds_data *lmd;
	size_t lmd_size;
	int rc;

	lmd_size = sizeof(lmd->lmd_st) +
		lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);

	if (lmd_size < sizeof(lmd->lmd_st) + XATTR_SIZE_MAX)
		lmd_size = sizeof(lmd->lmd_st) + XATTR_SIZE_MAX;

	if (lmd_size < FID_NOBRACE_LEN + 1)
		lmd_size = FID_NOBRACE_LEN + 1;

	lmd = malloc(lmd_size);
	if (lmd == NULL)
		return -ENOMEM;

	snprintf((char *)lmd, lmd_size, DFID_NOBRACE, PFID(fid));

	rc = ioctl(ct->open_by_fid_fd, IOC_MDC_GETFILEINFO, lmd);
	if (rc != 0) {
		rc = -errno;
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "cannot get metadata attributes of "DFID" in '%s'",
			    PFID(fid), ct->mnt);
		goto out;
	}

	*st = lmd->lmd_st;
out:
	free(lmd);

	return rc;
}
Example #8
0
/** Register a copytool
 * \param[out] priv		Opaque private control structure
 * \param mnt			Lustre filesystem mount point
 * \param archive_count		Number of valid archive IDs in \a archives
 * \param archives		Which archive numbers this copytool is
 *				responsible for
 * \param rfd_flags		flags applied to read fd of pipe
 *				(e.g. O_NONBLOCK)
 *
 * \retval 0 on success.
 * \retval -errno on error.
 */
int llapi_hsm_copytool_register(struct hsm_copytool_private **priv,
				const char *mnt, int archive_count,
				int *archives, int rfd_flags)
{
	struct hsm_copytool_private	*ct;
	int				 rc;

	if (archive_count > 0 && archives == NULL) {
		llapi_err_noerrno(LLAPI_MSG_ERROR,
				  "NULL archive numbers");
		return -EINVAL;
	}

	if (archive_count > LL_HSM_MAX_ARCHIVE) {
		llapi_err_noerrno(LLAPI_MSG_ERROR, "%d requested when maximum "
				  "of %zu archives supported", archive_count,
				  LL_HSM_MAX_ARCHIVE);
		return -EINVAL;
	}

	ct = calloc(1, sizeof(*ct));
	if (ct == NULL)
		return -ENOMEM;

	ct->magic = CT_PRIV_MAGIC;
	ct->mnt_fd = -1;
	ct->open_by_fid_fd = -1;
	ct->kuc.lk_rfd = LK_NOFD;
	ct->kuc.lk_wfd = LK_NOFD;

	ct->mnt = strdup(mnt);
	if (ct->mnt == NULL) {
		rc = -ENOMEM;
		goto out_err;
	}

	ct->kuch = malloc(HAL_MAXSIZE + sizeof(*ct->kuch));
	if (ct->kuch == NULL) {
		rc = -ENOMEM;
		goto out_err;
	}

	ct->mnt_fd = open(ct->mnt, O_RDONLY);
	if (ct->mnt_fd < 0) {
		rc = -errno;
		goto out_err;
	}

	ct->open_by_fid_fd = openat(ct->mnt_fd, OPEN_BY_FID_PATH, O_RDONLY);
	if (ct->open_by_fid_fd < 0) {
		rc = -errno;
		goto out_err;
	}

	/* no archives specified means "match all". */
	ct->archives = 0;
	for (rc = 0; rc < archive_count; rc++) {
		if ((archives[rc] > LL_HSM_MAX_ARCHIVE) || (archives[rc] < 0)) {
			llapi_err_noerrno(LLAPI_MSG_ERROR, "%d requested when "
					  "archive id [0 - %zu] is supported",
					  archives[rc], LL_HSM_MAX_ARCHIVE);
			rc = -EINVAL;
			goto out_err;
		}
		/* in the list we have an all archive wildcard
		 * so move to all archives mode
		 */
		if (archives[rc] == 0) {
			ct->archives = 0;
			archive_count = 0;
			break;
		}
		ct->archives |= (1 << (archives[rc] - 1));
	}

	rc = libcfs_ukuc_start(&ct->kuc, KUC_GRP_HSM, rfd_flags);
	if (rc < 0)
		goto out_err;

	/* Storing archive(s) in lk_data; see mdc_ioc_hsm_ct_start */
	ct->kuc.lk_data = ct->archives;
	rc = ioctl(ct->mnt_fd, LL_IOC_HSM_CT_START, &ct->kuc);
	if (rc < 0) {
		rc = -errno;
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "cannot start copytool on '%s'", mnt);
		goto out_kuc;
	}

	llapi_hsm_log_ct_registration(&ct, CT_REGISTER);

	/* Only the kernel reference keeps the write side open */
	close(ct->kuc.lk_wfd);
	ct->kuc.lk_wfd = LK_NOFD;
	*priv = ct;

	return 0;

out_kuc:
	/* cleanup the kuc channel */
	libcfs_ukuc_stop(&ct->kuc);

out_err:
	if (!(ct->mnt_fd < 0))
		close(ct->mnt_fd);

	if (!(ct->open_by_fid_fd < 0))
		close(ct->open_by_fid_fd);

	free(ct->mnt);

	free(ct->kuch);

	free(ct);

	return rc;
}
Example #9
0
/**
 * Given a copytool progress update, construct a JSON event suitable for
 * consumption by a copytool monitoring process.
 *
 * Examples of various events generated here and written by
 * llapi_hsm_write_json_event:
 *
 * Copytool registration and deregistration:
 * {"event_time": "2014-02-26 14:58:01 -0500", "event_type": "REGISTER",
 *  "archive": 0, "mount_point": "/mnt/lustre",
 *  "uuid": "80379a60-1f8a-743f-daf2-307cde793ec2"}
 * {"event_time": "2014-02-26 14:58:01 -0500", "event_type": "UNREGISTER",
 *  "archive": 0, "mount_point": "/mnt/lustre",
 *  "uuid": "80379a60-1f8a-743f-daf2-307cde793ec2"}
 *
 * An archive action, start to completion:
 * {"event_time": "2014-02-26 14:50:13 -0500", "event_type": "ARCHIVE_START",
 *  "total_bytes": 0, "lustre_path": "d71.sanity-hsm/f71.sanity-hsm",
 *  "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"}
 * {"event_time": "2014-02-26 14:50:18 -0500", "event_type": "ARCHIVE_RUNNING",
 *  "current_bytes": 5242880, "total_bytes": 39000000,
 *  "lustre_path": "d71.sanity-hsm/f71.sanity-hsm",
 *  "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"}
 * {"event_time": "2014-02-26 14:50:50 -0500", "event_type": "ARCHIVE_FINISH",
 *  "source_fid": "0x2000013a1:0x2:0x0", "data_fid": "0x2000013a1:0x2:0x0"}
 *
 * A log message:
 * {"event_time": "2014-02-26 14:50:13 -0500", "event_type": "LOGGED_MESSAGE",
 *  "level": "INFO",
 *  "message": "lhsmtool_posix[42]: copytool fs=lustre archive#=2 item_count=1"}
 *
 * \param hcp                Opaque action handle returned by
 *                           llapi_hsm_action_start.
 * \param hai                The hsm_action_item describing the request.
 * \param progress_type      The ct_progress_type describing the update.
 * \param total              The total expected bytes for the request.
 * \param current            The current copied byte count for the request.
 *
 * \retval 0 on success.
 * \retval -errno on error.
 */
static int llapi_hsm_log_ct_progress(struct hsm_copyaction_private **phcp,
				     const struct hsm_action_item *hai,
				     __u32 progress_type,
				     __u64 total, __u64 current)
{
	int				rc;
	int				linkno = 0;
	long long			recno = -1;
	char				lustre_path[PATH_MAX];
	char				strfid[FID_NOBRACE_LEN + 1];
	struct hsm_copyaction_private	*hcp;
	struct llapi_json_item_list	*json_items;

	/* Noop unless the event fd was initialized */
	if (llapi_hsm_event_fd < 0)
		return 0;

	if (phcp == NULL || *phcp == NULL)
		return -EINVAL;

	hcp = *phcp;

	rc = llapi_json_init_list(&json_items);
	if (rc < 0)
		goto err;

	snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(&hai->hai_dfid));
	rc = llapi_json_add_item(&json_items, "data_fid",
				 LLAPI_JSON_STRING, strfid);
	if (rc < 0)
		goto err;

	snprintf(strfid, sizeof(strfid), DFID_NOBRACE, PFID(&hai->hai_fid));
	rc = llapi_json_add_item(&json_items, "source_fid",
				 LLAPI_JSON_STRING, strfid);
	if (rc < 0)
		goto err;

	if (hcp->copy.hc_errval == ECANCELED) {
		progress_type = CT_CANCEL;
		goto cancel;
	}

	if (hcp->copy.hc_errval != 0) {
		progress_type = CT_ERROR;

		rc = llapi_json_add_item(&json_items, "errno",
					 LLAPI_JSON_INTEGER,
					 &hcp->copy.hc_errval);
		if (rc < 0)
			goto err;

		rc = llapi_json_add_item(&json_items, "error",
					 LLAPI_JSON_STRING,
					 strerror(hcp->copy.hc_errval));
		if (rc < 0)
			goto err;

		goto cancel;
	}

	/* lustre_path isn't available after a restore completes */
	/* total_bytes isn't available after a restore or archive completes */
	if (progress_type != CT_FINISH) {
		rc = llapi_fid2path(hcp->ct_priv->mnt, strfid, lustre_path,
				    sizeof(lustre_path), &recno, &linkno);
		if (rc < 0)
			goto err;

		rc = llapi_json_add_item(&json_items, "lustre_path",
					 LLAPI_JSON_STRING, lustre_path);
		if (rc < 0)
			goto err;

		rc = llapi_json_add_item(&json_items, "total_bytes",
					 LLAPI_JSON_BIGNUM, &total);
		if (rc < 0)
			goto err;
	}

	if (progress_type == CT_RUNNING)
		rc = llapi_json_add_item(&json_items, "current_bytes",
					 LLAPI_JSON_BIGNUM, &current);
		if (rc < 0)
			goto err;

cancel:
	rc = llapi_json_add_item(&json_items, "event_type", LLAPI_JSON_STRING,
				 (char *)llapi_hsm_ct_ev2str(hai->hai_action +
							     progress_type));
	if (rc < 0)
		goto err;

	rc = llapi_hsm_write_json_event(&json_items);
	if (rc < 0)
		goto err;

	goto out_free;

err:
	llapi_error(LLAPI_MSG_ERROR, rc, "error in "
		    "llapi_hsm_log_ct_progress()");

out_free:
	if (json_items != NULL)
		llapi_json_destroy_list(&json_items);

	return rc;
}
Example #10
0
/**
 * Hook for llapi_hsm_copytool_register and llapi_hsm_copytool_unregister
 * to generate JSON events suitable for consumption by a copytool
 * monitoring process.
 *
 * \param priv               Opaque private control structure.
 * \param event_type         The type of event (register or unregister).
 *
 * \retval 0 on success.
 * \retval -errno on error.
 */
static int llapi_hsm_log_ct_registration(struct hsm_copytool_private **priv,
					 __u32 event_type)
{
	int				rc;
	char				agent_uuid[UUID_MAX];
	struct hsm_copytool_private	*ct;
	struct llapi_json_item_list	*json_items;

	/* Noop unless the event fd was initialized */
	if (llapi_hsm_event_fd < 0)
		return 0;

	if (priv == NULL || *priv == NULL)
		return -EINVAL;

	ct = *priv;
	if (ct->magic != CT_PRIV_MAGIC)
		return -EINVAL;

	if (event_type != CT_REGISTER && event_type != CT_UNREGISTER)
		return -EINVAL;

	rc = llapi_json_init_list(&json_items);
	if (rc < 0)
		goto err;

	rc = llapi_get_agent_uuid(ct->mnt, agent_uuid, sizeof(agent_uuid));
	if (rc < 0)
		goto err;
	llapi_chomp_string(agent_uuid);

	rc = llapi_json_add_item(&json_items, "uuid", LLAPI_JSON_STRING,
				 agent_uuid);
	if (rc < 0)
		goto err;

	rc = llapi_json_add_item(&json_items, "mount_point", LLAPI_JSON_STRING,
				 ct->mnt);
	if (rc < 0)
		goto err;

	rc = llapi_json_add_item(&json_items, "archive", LLAPI_JSON_INTEGER,
				 &ct->archives);
	if (rc < 0)
		goto err;

	rc = llapi_json_add_item(&json_items, "event_type", LLAPI_JSON_STRING,
				 (char *)llapi_hsm_ct_ev2str(event_type));
	if (rc < 0)
		goto err;

	rc = llapi_hsm_write_json_event(&json_items);
	if (rc < 0)
		goto err;

	goto out_free;

err:
	llapi_error(LLAPI_MSG_ERROR, rc, "error in "
		    "llapi_hsm_log_ct_registration()");

out_free:
	if (json_items != NULL)
		llapi_json_destroy_list(&json_items);

	return rc;
}
int main(int argc, char **argv)
{
	struct lov_user_md *lum_dir, *lum_file1 = NULL, *lum_file2 = NULL;
	struct obd_uuid uuid;
	int lum_size, rc;
	DIR *dir;

	if (argc < 3) {
		llapi_err_noerrno(LLAPI_MSG_ERROR,
				  "Usage: %s <dirname> <filename1> [filename2]\n",
				  argv[0]);
		return 1;
	}

	dir = opendir(argv[1]);
	if (dir == NULL) {
		rc = -errno;
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: %s opendir failed", argv[1]);
		return rc;
	}

	lum_size = lov_user_md_size(MAX_LOV_UUID_COUNT, LOV_USER_MAGIC);
	lum_dir = (struct lov_user_md *)malloc(lum_size);
	if (lum_dir == NULL) {
		rc = -ENOMEM;
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: can't allocate %d bytes "
			    "for dir EA", lum_size);
		goto cleanup;
	}

	rc = llapi_file_get_stripe(argv[1], lum_dir);
	if (rc == -ENODATA) {
		char root[PATH_MAX], path[PATH_MAX + 2];

		rc = llapi_search_mounts(argv[1], 0, root, NULL);
		if (rc) {
			llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get "
				    "root path for %s\n", argv[1]);
			goto cleanup;
		}

		snprintf(path, sizeof(path), "%s/.", root);
		rc = llapi_file_get_stripe(path, lum_dir);
		if (rc == -ENODATA) {
			free(lum_dir);
			lum_dir = NULL;
		} else if (rc) {
			llapi_error(LLAPI_MSG_ERROR, rc, "error: cant't get "
				    "root's LOVEA for %s\n", path);
			goto cleanup;
		}
	} else if (rc) {
		llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get LOVEA for "
			    "%s", argv[1]);
		goto cleanup;
	}

	/* XXX should be llapi_lov_getname() */
	rc = llapi_file_get_lov_uuid(argv[1], &uuid);
	if (rc) {
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: can't get lov name for %s",
			    argv[1]);
		return rc;
	}

	lum_file1 = malloc(lum_size);
	if (lum_file1 == NULL) {
		rc = -ENOMEM;
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: can't allocate %d bytes for EA",
			    lum_size);
		goto cleanup;
	}

	rc = llapi_file_get_stripe(argv[2], lum_file1);
	if (rc) {
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: unable to get EA for %s", argv[2]);
		goto cleanup;
	}

	if (argc == 4) {
		lum_file2 = (struct lov_user_md *)malloc(lum_size);
		if (lum_file2 == NULL) {
			rc = -ENOMEM;
			llapi_error(LLAPI_MSG_ERROR, rc,
				    "error: can't allocate %d "
				    "bytes for file2 EA", lum_size);
			goto cleanup;
		}

		rc = llapi_file_get_stripe(argv[3], lum_file2);
		if (rc) {
			llapi_error(LLAPI_MSG_ERROR, rc,
				    "error: can't get EA for %s", argv[3]);
			goto cleanup;
		}
	}

	rc = compare_lum(&uuid, lum_dir, lum_file1, lum_file2);

cleanup:
	closedir(dir);
	if (lum_dir != NULL)
		free(lum_dir);
	if (lum_file1 != NULL)
		free(lum_file1);
	if (lum_file2 != NULL)
		free(lum_file2);

	return rc;
}
Example #12
0
int compare(struct lov_user_md *lum_dir, struct lov_user_md *lum_file1,
            struct lov_user_md *lum_file2)
{
        int stripe_count = 0, min_stripe_count = 0, def_stripe_count = 1;
        int stripe_size = 0;
        int stripe_offset = -1;
        int ost_count;
        char buf[128];
        char lov_path[PATH_MAX];
        char tmp_path[PATH_MAX];
        int i;
        FILE *fp;

	fp = popen("\\ls -d  /proc/fs/lustre/lov/*clilov* | head -1", "r");
	if (fp == NULL) {
		llapi_error(LLAPI_MSG_ERROR, -errno,
			    "open(lustre/lov/*clilov*) failed");
		return 2;
        }

	if (fscanf(fp, "%s", lov_path) < 1) {
		llapi_error(LLAPI_MSG_ERROR, -EINVAL,
			    "read(lustre/lov/*clilov*) failed");
		pclose(fp);
		return 3;
	}

        pclose(fp);

        snprintf(tmp_path, sizeof(tmp_path) - 1, "%s/stripecount",
                 lov_path);
        if (read_proc_entry(tmp_path, buf, sizeof(buf)) < 0)
                return 5;
        def_stripe_count = (short)atoi(buf);

        snprintf(tmp_path, sizeof(tmp_path) - 1, "%s/numobd", lov_path);
        if (read_proc_entry(tmp_path, buf, sizeof(buf)) < 0)
                return 6;
        ost_count = atoi(buf);

        if (lum_dir == NULL) {
                stripe_count = def_stripe_count;
                min_stripe_count = -1;
        } else {
                stripe_count = (signed short)lum_dir->lmm_stripe_count;
                printf("dir stripe %d, ", stripe_count);
                min_stripe_count = 1;
        }

        printf("default stripe %d, ost count %d\n",
               def_stripe_count, ost_count);

        if (stripe_count == 0) {
                min_stripe_count = -1;
                stripe_count = 1;
        }

        stripe_count = (stripe_count > 0 && stripe_count <= ost_count) ?
                                                stripe_count : ost_count;
        min_stripe_count = min_stripe_count > 0 ? stripe_count :
                                                ((stripe_count + 1) / 2);

        if (lum_file1->lmm_stripe_count != stripe_count ||
            lum_file1->lmm_stripe_count < min_stripe_count) {
                llapi_err_noerrno(LLAPI_MSG_ERROR,
                                  "file1 stripe count %d != dir %d\n",
                                  lum_file1->lmm_stripe_count, stripe_count);
                return 7;
        }

        if (lum_file1->lmm_stripe_count < stripe_count)
                llapi_err_noerrno(LLAPI_MSG_WARN,
                                  "warning: file1 used fewer stripes"
                                  " %d < dir %d (likely due to bug 4900)\n",
                                  lum_file1->lmm_stripe_count, stripe_count);

        if (lum_dir != NULL)
                stripe_size = (int)lum_dir->lmm_stripe_size;
        if (stripe_size == 0) {
                snprintf(tmp_path, sizeof(tmp_path) - 1, "%s/stripesize",
                         lov_path);
                if (read_proc_entry(tmp_path, buf, sizeof(buf)) < 0)
                        return 5;

                stripe_size = atoi(buf);
        }

        if (lum_file1->lmm_stripe_size != stripe_size) {
                llapi_err_noerrno(LLAPI_MSG_ERROR,
                                  "file1 stripe size %d != dir %d\n",
                                  lum_file1->lmm_stripe_size, stripe_size);
                return 8;
        }

        if (lum_dir != NULL)
                stripe_offset = (short int)lum_dir->lmm_stripe_offset;
        if (stripe_offset != -1) {
                for (i = 0; i < stripe_count; i++)
                        if (lum_file1->lmm_objects[i].l_ost_idx !=
                            (stripe_offset + i) % ost_count) {
                                llapi_err_noerrno(LLAPI_MSG_WARN,
                                          "warning: file1 non-sequential "
                                          "stripe[%d] %d != %d\n", i,
                                          lum_file1->lmm_objects[i].l_ost_idx,
                                          (stripe_offset + i) % ost_count);
                        }
        } else if (lum_file2 != NULL) {
                int next, idx, stripe = stripe_count - 1;
                next = (lum_file1->lmm_objects[stripe].l_ost_idx + 1) %
                       ost_count;
                idx = lum_file2->lmm_objects[0].l_ost_idx;
                if (idx != next) {
                        llapi_err_noerrno(LLAPI_MSG_WARN,
                                  "warning: non-sequential "
                                  "file1 stripe[%d] %d != file2 stripe[0] %d\n",
                                  stripe, lum_file1->lmm_objects[stripe].l_ost_idx,
                                  idx);
                }
        }

        return 0;
}
Example #13
0
int main(int argc, char **argv)
{
        DIR * dir;
        struct lov_user_md *lum_dir, *lum_file1 = NULL, *lum_file2 = NULL;
        int rc;
        int lum_size;

        if (argc < 3) {
                llapi_err_noerrno(LLAPI_MSG_ERROR,
                                "Usage: %s <dirname> <filename1> [filename2]\n",
                                argv[0]);
                return 1;
        }

	dir = opendir(argv[1]);
	if (dir == NULL) {
		rc = -errno;
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: %s opendir failed", argv[1]);
		return rc;
	}

	lum_size = lov_user_md_size(MAX_LOV_UUID_COUNT, LOV_USER_MAGIC);
	lum_dir = (struct lov_user_md *)malloc(lum_size);
	if (lum_dir == NULL) {
		rc = -ENOMEM;
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: can't allocate %d bytes "
			    "for dir EA", lum_size);
		goto cleanup;
	}

	rc = llapi_file_get_stripe(argv[1], lum_dir);
	if (rc) {
		if (rc == -ENODATA) {
			free(lum_dir);
			lum_dir = NULL;
		} else {
			llapi_error(LLAPI_MSG_ERROR, rc,
				    "error: can't get EA for %s", argv[1]);
			goto cleanup;
		}
	}

	/* XXX should be llapi_lov_getname() */
	rc = llapi_file_get_lov_uuid(argv[1], &lov_uuid);
	if (rc) {
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: can't get lov name for %s",
			    argv[1]);
		return rc;
	}

	lum_file1 = malloc(lum_size);
	if (lum_file1 == NULL) {
		rc = -ENOMEM;
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: can't allocate %d bytes for EA",
			    lum_size);
		goto cleanup;
	}

	rc = llapi_file_get_stripe(argv[2], lum_file1);
	if (rc) {
		llapi_error(LLAPI_MSG_ERROR, rc,
			    "error: unable to get EA for %s", argv[2]);
		goto cleanup;
	}

	if (argc == 4) {
		lum_file2 = (struct lov_user_md *)malloc(lum_size);
		if (lum_file2 == NULL) {
			rc = -ENOMEM;
			llapi_error(LLAPI_MSG_ERROR, rc,
				    "error: can't allocate %d "
				    "bytes for file2 EA", lum_size);
			goto cleanup;
		}

		rc = llapi_file_get_stripe(argv[3], lum_file2);
		if (rc) {
			llapi_error(LLAPI_MSG_ERROR, rc,
				    "error: can't get EA for %s", argv[3]);
			goto cleanup;
		}
	}

	rc = compare(lum_dir, lum_file1, lum_file2);

cleanup:
        closedir(dir);
        if (lum_dir != NULL)
                free(lum_dir);
        if (lum_file1 != NULL)
                free(lum_file1);
        if (lum_file2 != NULL)
                free(lum_file2);

        return rc;
}