Exemple #1
0
static int dir_is_mount_point(DIR *d, const char *subdir) {
        struct file_handle *h;
        int mount_id_parent, mount_id;
        int r_p, r;

        h = alloca(MAX_HANDLE_SZ);

        h->handle_bytes = MAX_HANDLE_SZ;
        r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
        if (r_p < 0)
                r_p = -errno;

        h->handle_bytes = MAX_HANDLE_SZ;
        r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0);
        if (r < 0)
                r = -errno;

        /* got no handle; make no assumptions, return error */
        if (r_p < 0 && r < 0)
                return r_p;

        /* got both handles; if they differ, it is a mount point */
        if (r_p >= 0 && r >= 0)
                return mount_id_parent != mount_id;

        /* got only one handle; assume different mount points if one
         * of both queries was not supported by the filesystem */
        if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
                return true;

        /* return error */
        if (r_p < 0)
                return r_p;
        return r;
}
int
main(void)
{
	struct file_handle *handle =
		alloca(sizeof(struct file_handle) + MAX_HANDLE_SZ);
	const int dirfd = AT_FDCWD;
	const int flags = AT_SYMLINK_FOLLOW;
	int mount_id;
	unsigned int i;

	handle->handle_bytes = 0;

	assert(name_to_handle_at(dirfd, ".", handle, &mount_id, flags | 1) == -1);
	if (EINVAL != errno)
		perror_msg_and_skip("name_to_handle_at");
	printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=0}, %p"
	       ", AT_SYMLINK_FOLLOW|0x1) = -1 EINVAL (%m)\n", &mount_id);

	assert(name_to_handle_at(dirfd, ".", handle, &mount_id, flags) == -1);
	if (EOVERFLOW != errno)
		perror_msg_and_skip("name_to_handle_at");
	printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=0 => %u}"
	       ", %p, AT_SYMLINK_FOLLOW) = -1 EOVERFLOW (%m)\n",
	       handle->handle_bytes, &mount_id);

	assert(name_to_handle_at(dirfd, ".", handle, &mount_id, flags) == 0);
	printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=%u"
	       ", handle_type=%d, f_handle=0x",
	       handle->handle_bytes, handle->handle_type);
	for (i = 0; i < handle->handle_bytes; ++i)
		printf("%02x", handle->f_handle[i]);
	printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);

	printf("open_by_handle_at(-1, {handle_bytes=%u, handle_type=%d"
	       ", f_handle=0x", handle->handle_bytes, handle->handle_type);
	for (i = 0; i < handle->handle_bytes; ++i)
		printf("%02x", handle->f_handle[i]);
	printf("}, O_RDONLY|O_DIRECTORY) = -1 ");
	assert(open_by_handle_at(-1, handle, O_RDONLY | O_DIRECTORY) == -1);
	const char *errno_text;
	switch (errno) {
		case EPERM:
			errno_text = "EPERM";
			break;
		case EINVAL:
			errno_text = "EINVAL";
			break;
		default:
			errno_text = "EBADF";
	}
	printf("%s (%m)\n", errno_text);

	puts("+++ exited with 0 +++");
	return 0;
}
int main(int argc, char **argv)
{
#ifdef HAVE_FHANDLE_SYSCALLS
	char *filename, *file, *mount_point = NULL, *readbuf = NULL;
	int ret, rc = -EINVAL, mnt_id, mnt_fd, fd1, fd2, i, len, offset;
	struct file_handle *fh = NULL;
	int file_size, mtime, ctime;
	struct lu_fid *parent, *fid;
	struct mntent *ent;
	struct stat st;
	__ino_t inode;
	FILE *mntpt;

	if (argc != 2)
		usage(argv[0]);

	file = argv[1];
	if (file[0] != '/') {
		fprintf(stderr, "Need the absolete path of the file\n");
		goto out;
	}

	fd1 = open(file, O_RDONLY);
	if (fd1 < 0) {
		fprintf(stderr, "open file %s error: %s\n",
			file, strerror(errno));
		rc = errno;
		goto out;
	}

	/* Get file stats using fd1 from traditional open */
	bzero(&st, sizeof(struct stat));
	rc = fstat(fd1, &st);
	if (rc < 0) {
		fprintf(stderr, "fstat(%s) error: %s\n", file,
			strerror(errno));
		rc = errno;
		goto out_fd1;
	}

	inode = st.st_ino;
	mtime = st.st_mtime;
	ctime = st.st_ctime;
	file_size = st.st_size;

	/* Now for the setup to use fhandles */
	mntpt = setmntent("/etc/mtab", "r");
	if (mntpt == NULL) {
		fprintf(stderr, "setmntent error: %s\n",
			strerror(errno));
		rc = errno;
		goto out_fd1;
	}

	while (NULL != (ent = getmntent(mntpt))) {
		if ((strncmp(file, ent->mnt_dir, strlen(ent->mnt_dir)) == 0) &&
		    (strcmp(ent->mnt_type, "lustre") == 0)) {
			mount_point = ent->mnt_dir;
			break;
		}
	}
	endmntent(mntpt);

	if (mount_point == NULL) {
		fprintf(stderr, "file is not located on a lustre file "
			"system?\n");
		goto out_fd1;
	}

	filename = rindex(file, '/') + 1;

	/* Open mount point directory */
	mnt_fd = open(mount_point, O_DIRECTORY);
	if (mnt_fd < 0) {
		fprintf(stderr, "open(%s) error: %s\n)", mount_point,
			strerror(errno));
		rc = errno;
		goto out_fd1;
	}

	/* Allocate memory for file handle */
	fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
	if (!fh) {
		fprintf(stderr, "malloc(%d) error: %s\n", MAX_HANDLE_SZ,
			strerror(errno));
		rc = errno;
		goto out_mnt_fd;
	}
	fh->handle_bytes = MAX_HANDLE_SZ;

	/* Convert name to handle */
	ret = name_to_handle_at(mnt_fd, filename, fh, &mnt_id,
				AT_SYMLINK_FOLLOW);
	if (ret) {
		fprintf(stderr, "name_by_handle_at(%s) error: %s\n", filename,
			strerror(errno));
		rc = errno;
		goto out_f_handle;
	}

	/* Print out the contents of the file handle */
	fprintf(stdout, "fh_bytes: %u\nfh_type: %d\nfh_data: ",
		fh->handle_bytes, fh->handle_type);
	for (i = 0; i < fh->handle_bytes; i++)
		fprintf(stdout, "%02x ", fh->f_handle[i]);
	fprintf(stdout, "\n");

	/* Lustre stores both the parents FID and the file FID
	 * in the f_handle. */
	parent = (struct lu_fid *)(fh->f_handle + 16);
	fid = (struct lu_fid *)fh->f_handle;
	fprintf(stdout, "file's parent FID is "DFID"\n", PFID(parent));
	fprintf(stdout, "file FID is "DFID"\n", PFID(fid));

	/* Open the file handle */
	fd2 = open_by_handle_at(mnt_fd, fh, O_RDONLY);
	if (fd2 < 0) {
		fprintf(stderr, "open_by_handle_at(%s) error: %s\n", filename,
			strerror(errno));
		rc = errno;
		goto out_f_handle;
	}

	/* Get file size */
	bzero(&st, sizeof(struct stat));
	rc = fstat(fd2, &st);
	if (rc < 0) {
		fprintf(stderr, "fstat(%s) error: %s\n", filename,
			strerror(errno));
		rc = errno;
		goto out_fd2;
	}

	if (ctime != st.st_ctime || file_size != st.st_size ||
	    inode != st.st_ino || mtime != st.st_mtime) {
		fprintf(stderr, "stat data does not match between fopen "
			"and fhandle case\n");
		goto out_fd2;
	}

	if (st.st_size) {
		len = st.st_blksize;
		readbuf = malloc(len);
		if (readbuf == NULL) {
			fprintf(stderr, "malloc(%d) error: %s\n", len,
				strerror(errno));
			rc = errno;
			goto out_fd2;
		}

		for (offset = 0; offset < st.st_size; offset += len) {
			/* read from the file */
			rc = read(fd2, readbuf, len);
			if (rc < 0) {
				fprintf(stderr, "read(%s) error: %s\n",
					filename, strerror(errno));
				rc = errno;
				goto out_readbuf;
			}
		}
	}

	rc = 0;
	fprintf(stdout, "check_fhandle_syscalls test Passed!\n");

out_readbuf:
	if (readbuf != NULL)
		free(readbuf);
out_fd2:
	close(fd2);
out_f_handle:
	free(fh);
out_mnt_fd:
	close(mnt_fd);
out_fd1:
	close(fd1);
out:
	return rc;
#else /* !HAVE_FHANDLE_SYSCALLS */
	if (argc != 2)
		usage(argv[0]);

	fprintf(stderr, "HAVE_FHANDLE_SYSCALLS not defined\n");
	return 0;
#endif /* HAVE_FHANDLE_SYSCALLS */
}
Exemple #4
0
int fs_on_ssd(const char *p) {
        struct stat st;
        _cleanup_udev_unref_ struct udev *udev = NULL;
        _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
        struct udev_device *look_at = NULL;
        const char *devtype, *rotational, *model, *id;
        int r;

        assert(p);

        if (stat(p, &st) < 0)
                return -errno;

        if (major(st.st_dev) == 0) {
                _cleanup_fclose_ FILE *f = NULL;
                int mount_id;
                struct file_handle *h;

                /* Might be btrfs, which exposes "ssd" as mount flag if it is on ssd.
                 *
                 * We first determine the mount ID here, if we can,
                 * and then lookup the mount ID in mountinfo to find
                 * the mount options. */

                h = alloca(MAX_HANDLE_SZ);
                h->handle_bytes = MAX_HANDLE_SZ;
                r = name_to_handle_at(AT_FDCWD, p, h, &mount_id, AT_SYMLINK_FOLLOW);
                if (r < 0)
                        return false;

                f = fopen("/proc/self/mountinfo", "re");
                if (!f)
                        return false;

                for (;;) {
                        char line[LINE_MAX], *e;
                        _cleanup_free_ char *opts = NULL;
                        int mid;

                        if (!fgets(line, sizeof(line), f))
                                return false;

                        truncate_nl(line);

                        if (sscanf(line, "%i", &mid) != 1)
                                continue;

                        if (mid != mount_id)
                                continue;

                        e = strstr(line, " - ");
                        if (!e)
                                continue;

                        if (sscanf(e+3, "%*s %*s %ms", &opts) != 1)
                                continue;

                        if (streq(opts, "ssd") || startswith(opts, "ssd,") || endswith(opts, ",ssd") || strstr(opts, ",ssd,"))
                                return true;
                }

                return false;
        }

        udev = udev_new();
        if (!udev)
                return -ENOMEM;

        udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev);
        if (!udev_device)
                return false;

        devtype = udev_device_get_property_value(udev_device, "DEVTYPE");
        if (devtype && streq(devtype, "partition"))
                look_at = udev_device_get_parent(udev_device);
        else
                look_at = udev_device;

        if (!look_at)
                return false;

        /* First, try high-level property */
        id = udev_device_get_property_value(look_at, "ID_SSD");
        if (id)
                return streq(id, "1");

        /* Second, try kernel attribute */
        rotational = udev_device_get_sysattr_value(look_at, "queue/rotational");
        if (rotational)
                return streq(rotational, "0");

        /* Finally, fallback to heuristics */
        look_at = udev_device_get_parent(look_at);
        if (!look_at)
                return false;

        model = udev_device_get_sysattr_value(look_at, "model");
        if (model)
                return !!strstr(model, "SSD");

        return false;
}
Exemple #5
0
int main(int argc, char *argv[]) {
    struct file_handle *fhp;
    int mount_id, fhsize, flags, dirfd, j;
    char *pathname;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s pathname\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    pathname = argv[1];

    /* Allocate file_handle structure */
    fhsize = sizeof(*fhp);
    fhp = malloc(fhsize);
    if (fhp == NULL)
        errExit("malloc");

    /* Make an initial call to name_to_handle_at() to discover
       the size required for file handle */
    dirfd = AT_FDCWD;           /* For name_to_handle_at() calls */
    flags = 0;                  /* For name_to_handle_at() calls */
    fhp->handle_bytes = 0;
    if (name_to_handle_at(dirfd, pathname, fhp,
                          &mount_id, flags) != -1 || errno != EOVERFLOW) {
        fprintf(stderr, "Unexpected result from name_to_handle_at()\n");
        exit(EXIT_FAILURE);
    }

    /* Reallocate file_handle structure with correct size */
    fhsize = sizeof(struct file_handle) + fhp->handle_bytes;
    fhp = realloc(fhp, fhsize);         /* Copies fhp->handle_bytes */
    if (fhp == NULL)
        errExit("realloc");

    /* Get file handle from pathname supplied on command line */
    if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)
        errExit("name_to_handle_at");

    /* Write mount ID, file handle size, and file handle to stdout,
       for later reuse by t_open_by_handle_at.c */

    printf("%d\n", mount_id);
    printf("%d %d   ", fhp->handle_bytes, fhp->handle_type);
    for (j = 0; j < fhp->handle_bytes; j++)
        printf(" %02x", fhp->f_handle[j]);
    printf("\n");

    // Open file
    int fd = open_by_handle_at(AT_FDCWD, fhp, O_RDONLY);
    char a[1024];
    int r = read(fd, a, 1000);
    printf("%d > %s [%d]\n", fd, a, r);
    for(int i = 0; i < r; i++) {
        printf("%02x", a[i] & 0xff);
    }
    printf("\n");
    for(int i = 0; i < r; i++) {
        printf("%02x ", a[i] & 0xff);
    }
    printf("\n");
    printf("END\n");

    exit(EXIT_SUCCESS);
}
/*
 *  stress_handle()
 *	stress system by rapid open/close calls via
 *	name_to_handle_at and open_by_handle_at
 */
int stress_handle(
	uint64_t *const counter,
	const uint32_t instance,
	const uint64_t max_ops,
	const char *name)
{
	int mounts;

	(void)instance;

	if ((mounts = get_mount_info(name)) < 0) {
		pr_fail(stderr, "%s: failed to parse /proc/self/mountinfo\n", name);
		return EXIT_FAILURE;
	}

	do {
		struct file_handle *fhp, *tmp;
		int mount_id, mount_fd, fd, i;

		if ((fhp = malloc(sizeof(*fhp))) == NULL)
			continue;

		fhp->handle_bytes = 0;
		if ((name_to_handle_at(AT_FDCWD, FILENAME, fhp, &mount_id, 0) != -1) &&
		    (errno != EOVERFLOW)) {
			pr_fail(stderr, "%s: name_to_handle_at: failed to get file handle size: errno=%d (%s)\n",
				name, errno, strerror(errno));
			free(fhp);
			break;
		}
		tmp = realloc(fhp, sizeof(struct file_handle) + fhp->handle_bytes);
		if (tmp == NULL) {
			free(fhp);
			continue;
		}
		fhp = tmp;
		if (name_to_handle_at(AT_FDCWD, FILENAME, fhp, &mount_id, 0) < 0) {
			pr_fail(stderr, "%s: name_to_handle_at: failed to get file handle: errno=%d (%s)\n",
				name, errno, strerror(errno));
			free(fhp);
			break;
		}

		mount_fd = -2;
		for (i = 0; i < mounts; i++) {
			if (mount_info[i].mount_id == mount_id) {
				mount_fd = open(mount_info[i].mount_path, O_RDONLY);
				break;
			}
		}
		if (mount_fd == -2) {
			pr_fail(stderr, "%s: cannot find mount id %d\n", name, mount_id);
			free(fhp);
			break;
		}
		if (mount_fd < 0) {
			pr_fail(stderr, "%s: failed to open mount path '%s': errno=%d (%s)\n",
				name, mount_info[i].mount_path, errno, strerror(errno));
			free(fhp);
			break;
		}
		if ((fd = open_by_handle_at(mount_fd, fhp, O_RDONLY)) < 0) {
			/* We don't abort if EPERM occurs, that's not a test failure */
			if (errno != EPERM) {
				pr_fail(stderr, "%s: open_by_handle_at: failed to open: errno=%d (%s)\n",
					name, errno, strerror(errno));
				(void)close(mount_fd);
				free(fhp);
				break;
			}
		} else {
			(void)close(fd);
		}
		(void)close(mount_fd);
		free(fhp);
	} while (opt_do_run && (!max_ops || *counter < max_ops));

	free_mount_info(mounts);

	return EXIT_SUCCESS;
}