1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002 Cluster File Systems, Inc.
5 * Author: Peter J. Braam <braam@clusterfs.com>
6 * Author: Phil Schwan <phil@clusterfs.com>
7 * Author: Robert Read <rread@clusterfs.com>
9 * This file is part of Lustre, http://www.lustre.org.
11 * Lustre is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
15 * Lustre is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Lustre; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34 #include <sys/ioctl.h>
41 #include <sys/types.h>
42 #include <sys/syscall.h>
43 #ifdef HAVE_LINUX_TYPES_H
44 #include <linux/types.h>
46 #ifdef HAVE_LINUX_UNISTD_H
47 #include <linux/unistd.h>
52 #include <lnet/lnetctl.h>
54 #include <liblustre.h>
55 #include <linux/obd.h>
56 #include <linux/lustre_lib.h>
57 #include <lustre/liblustreapi.h>
58 #include <linux/obd_lov.h>
59 #include <lustre/liblustreapi.h>
61 static void err_msg(char *fmt, ...)
64 int tmp_errno = abs(errno);
67 vfprintf(stderr, fmt, args);
69 fprintf(stderr, ": %s (%d)\n", strerror(tmp_errno), tmp_errno);
72 int llapi_file_create(char *name, long stripe_size, int stripe_offset,
73 int stripe_count, int stripe_pattern)
75 struct lov_user_md lum = { 0 };
80 fd = open(name, O_CREAT | O_RDWR | O_LOV_DELAY_CREATE, 0644);
81 if (errno == EISDIR) {
82 fd = open(name, O_DIRECTORY | O_RDONLY);
87 err_msg("unable to open '%s'",name);
92 /* 64 KB is the largest common page size I'm aware of (on ia64), but
93 * check the local page size just in case. */
94 page_size = LOV_MIN_STRIPE_SIZE;
95 if (getpagesize() > page_size) {
96 page_size = getpagesize();
97 fprintf(stderr, "warning: your page size (%u) is larger than "
98 "expected (%u).\n", page_size, LOV_MIN_STRIPE_SIZE);
100 if (stripe_size < 0 || (stripe_size & (LOV_MIN_STRIPE_SIZE - 1))) {
101 errno = rc = -EINVAL;
102 err_msg("error: stripe_size must be an even "
103 "multiple of %d bytes", page_size);
106 if (stripe_offset < -1 || stripe_offset > 2048) {
107 errno = rc = -EINVAL;
108 err_msg("error: bad stripe offset %d", stripe_offset);
111 if (stripe_count < -1 || stripe_count > LOV_MAX_STRIPE_COUNT) {
112 errno = rc = -EINVAL;
113 err_msg("error: bad stripe count %d", stripe_count);
116 if (stripe_count > 0 && (__u64)stripe_size * stripe_count > ~0UL) {
117 errno = rc = -EINVAL;
118 err_msg("error: stripe_size %ld * stripe_count %d "
119 "exceeds %lu bytes", ~0UL);
123 /* Initialize IOCTL striping pattern structure */
124 lum.lmm_magic = LOV_USER_MAGIC;
125 lum.lmm_pattern = stripe_pattern;
126 lum.lmm_stripe_size = stripe_size;
127 lum.lmm_stripe_count = stripe_count;
128 lum.lmm_stripe_offset = stripe_offset;
130 if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
131 char *errmsg = "stripe already set";
132 if (errno != EEXIST && errno != EALREADY)
133 errmsg = strerror(errno);
135 fprintf(stderr, "error on ioctl "LPX64" for '%s' (%d): %s\n",
136 (__u64)LL_IOC_LOV_SETSTRIPE, name, fd, errmsg);
141 err_msg("error on close for '%s' (%d)", name, fd);
148 /* short term backwards compat only */
149 int op_create_file(char *name, long stripe_size, int stripe_offset,
152 return llapi_file_create(name, stripe_size, stripe_offset,
160 struct obd_uuid *obduuid;
162 struct lov_user_mds_data *lmd;
163 /* struct lov_user_md *lum;*/
166 int (* process_file)(DIR *dir, char *dname, char *fname,
167 struct find_param *param);
170 #define MAX_LOV_UUID_COUNT max(LOV_MAX_STRIPE_COUNT, 1000)
171 #define OBD_NOT_FOUND (-1)
173 static int prepare_find(struct find_param *param)
175 param->lumlen = lov_mds_md_size(MAX_LOV_UUID_COUNT);
176 if ((param->lmd = malloc(sizeof(lstat_t) + param->lumlen)) == NULL) {
177 err_msg("unable to allocate %d bytes of memory for ioctl",
178 sizeof(lstat_t) + param->lumlen);
182 param->got_uuids = 0;
183 param->obdindex = OBD_NOT_FOUND;
188 static void cleanup_find(struct find_param *param)
191 free(param->obduuid);
196 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
198 struct obd_ioctl_data data = { 0, };
199 struct lov_desc desc = { 0, };
201 int max_ost_count, rc;
204 max_ost_count = (OBD_MAX_IOCTL_BUFFER - size_round(sizeof(data)) -
205 size_round(sizeof(desc))) /
206 (sizeof(*uuidp) + sizeof(*obdgens));
207 if (max_ost_count > *ost_count)
208 max_ost_count = *ost_count;
210 obdgens = malloc(size_round(max_ost_count * sizeof(*obdgens)));
212 err_msg("no memory for %d generation #'s", max_ost_count);
216 data.ioc_inllen1 = sizeof(desc);
217 data.ioc_inlbuf1 = (char *)&desc;
218 data.ioc_inllen2 = size_round(max_ost_count * sizeof(*uuidp));
219 data.ioc_inlbuf2 = (char *)uuidp;
220 data.ioc_inllen3 = size_round(max_ost_count * sizeof(*obdgens));
221 data.ioc_inlbuf3 = (char *)obdgens;
223 desc.ld_tgt_count = max_ost_count;
225 if (obd_ioctl_pack(&data, &buf, OBD_MAX_IOCTL_BUFFER)) {
226 fprintf(stderr, "internal buffer error packing\n");
231 rc = ioctl(fd, OBD_IOC_LOV_GET_CONFIG, buf);
233 err_msg("error getting LOV config");
238 if (obd_ioctl_unpack(&data, buf, OBD_MAX_IOCTL_BUFFER)) {
239 fprintf(stderr, "invalid reply from ioctl");
244 *ost_count = desc.ld_tgt_count;
252 static int setup_obd_uuids(DIR *dir, char *dname, struct find_param *param)
254 char uuid[sizeof(struct obd_uuid)];
259 param->got_uuids = 1;
261 /* Get the lov name */
262 rc = ioctl(dirfd(dir), OBD_IOC_GETNAME, (void *)uuid);
264 fprintf(stderr, "error: can't get lov name: %s\n",
265 strerror(rc = errno));
269 /* Now get the ost uuids from /proc */
270 snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
272 fp = fopen(buf, "r");
274 fprintf(stderr, "error: %s opening %s\n",
275 strerror(rc = errno), buf);
279 if (!param->obduuid && !param->quiet)
282 while (fgets(buf, sizeof(buf), fp) != NULL) {
283 if (sscanf(buf, "%d: %s", &index, uuid) < 2)
286 if (param->obduuid) {
287 if (strncmp(param->obduuid->uuid, uuid,
288 sizeof(uuid)) == 0) {
289 param->obdindex = index;
292 } else if (!param->quiet) {
293 /* Print everything */
300 if (param->obduuid && (param->obdindex == OBD_NOT_FOUND)) {
301 printf("unknown obduuid: %s\n", param->obduuid->uuid);
308 void lov_dump_user_lmm_v1(struct lov_user_md_v1 *lum, char *dname, char *fname,
309 int obdindex, int quiet, int header, int body)
311 int i, obdstripe = 0;
313 if (obdindex != OBD_NOT_FOUND) {
314 for (i = 0; fname[0] && i < lum->lmm_stripe_count; i++) {
315 if (obdindex == lum->lmm_objects[i].l_ost_idx) {
316 printf("%s/%s\n", dname, fname);
322 printf("%s/%s\n", dname, fname);
326 /* if it's a directory */
327 if (*fname == '\0') {
328 if (obdstripe == 1) {
329 printf("default stripe_count: %d stripe_size: %u "
330 "stripe_offset: %d\n",
331 lum->lmm_stripe_count == (__u16)-1 ? -1 :
332 lum->lmm_stripe_count,
333 lum->lmm_stripe_size,
334 lum->lmm_stripe_offset == (__u16)-1 ? -1 :
335 lum->lmm_stripe_offset);
340 if (header && (obdstripe == 1)) {
341 printf("lmm_magic: 0x%08X\n", lum->lmm_magic);
342 printf("lmm_object_gr: "LPX64"\n", lum->lmm_object_gr);
343 printf("lmm_object_id: "LPX64"\n", lum->lmm_object_id);
344 printf("lmm_stripe_count: %u\n", (int)lum->lmm_stripe_count);
345 printf("lmm_stripe_size: %u\n", lum->lmm_stripe_size);
346 printf("lmm_stripe_pattern: %x\n", lum->lmm_pattern);
350 if ((!quiet) && (obdstripe == 1))
351 printf("\tobdidx\t\t objid\t\tobjid\t\t group\n");
353 for (i = 0; i < lum->lmm_stripe_count; i++) {
354 int idx = lum->lmm_objects[i].l_ost_idx;
355 long long oid = lum->lmm_objects[i].l_object_id;
356 long long gr = lum->lmm_objects[i].l_object_gr;
357 if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
358 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
360 obdindex == idx ? " *" : "");
366 void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *dname,
367 char *fname, int obdindex, int quiet,
368 int header, int body)
370 struct lov_user_md_join *lumj = (struct lov_user_md_join *)lum;
371 int i, obdstripe = 0;
373 if (obdindex != OBD_NOT_FOUND) {
374 for (i = 0; i < lumj->lmm_stripe_count; i++) {
375 if (obdindex == lumj->lmm_objects[i].l_ost_idx) {
376 printf("%s/%s\n", dname, fname);
382 printf("%s/%s\n", dname, fname);
386 if (header && obdstripe == 1) {
387 printf("lmm_magic: 0x%08X\n", lumj->lmm_magic);
388 printf("lmm_object_gr: "LPX64"\n", lumj->lmm_object_gr);
389 printf("lmm_object_id: "LPX64"\n", lumj->lmm_object_id);
390 printf("lmm_stripe_count: %u\n", (int)lumj->lmm_stripe_count);
391 printf("lmm_stripe_size: %u\n", lumj->lmm_stripe_size);
392 printf("lmm_stripe_pattern: %x\n", lumj->lmm_pattern);
393 printf("lmm_extent_count: %x\n", lumj->lmm_extent_count);
397 unsigned long long start = -1, end = 0;
398 if (!quiet && obdstripe == 1)
399 printf("joined\tobdidx\t\t objid\t\tobjid\t\t group"
400 "\t\tstart\t\tend\n");
401 for (i = 0; i < lumj->lmm_stripe_count; i++) {
402 int idx = lumj->lmm_objects[i].l_ost_idx;
403 long long oid = lumj->lmm_objects[i].l_object_id;
404 long long gr = lumj->lmm_objects[i].l_object_gr;
405 if (obdindex == OBD_NOT_FOUND || obdindex == idx)
406 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s",
408 obdindex == idx ? " *" : "");
409 if (start != lumj->lmm_objects[i].l_extent_start ||
410 end != lumj->lmm_objects[i].l_extent_end) {
411 start = lumj->lmm_objects[i].l_extent_start;
412 printf("\t%14llu", start);
413 end = lumj->lmm_objects[i].l_extent_end;
414 if (end == (unsigned long long)-1)
417 printf("\t\t%llu\n", end);
419 printf("\t\t\t\t\n");
426 void llapi_lov_dump_user_lmm(struct find_param *param, char *dname, char *fname)
428 switch(*(__u32 *)¶m->lmd->lmd_lmm) { /* lum->lmm_magic */
429 case LOV_USER_MAGIC_V1:
430 lov_dump_user_lmm_v1(¶m->lmd->lmd_lmm, dname, fname,
431 param->obdindex, param->quiet,
433 (param->verbose || !param->obduuid));
435 case LOV_USER_MAGIC_JOIN:
436 lov_dump_user_lmm_join(¶m->lmd->lmd_lmm, dname, fname,
437 param->obdindex, param->quiet,
439 (param->verbose || !param->obduuid));
442 printf("unknown lmm_magic: %#x (expecting %#x)\n",
443 *(__u32 *)¶m->lmd->lmd_lmm, LOV_USER_MAGIC_V1);
448 int llapi_file_get_stripe(char *path, struct lov_user_md *lum)
453 fname = strrchr(path, '/');
455 /* It should be a file (or other non-directory) */
457 dname = (char *)malloc(2);
463 dname = (char *)malloc(fname - path + 1);
466 strncpy(dname, path, fname - path);
467 dname[fname - path] = '\0';
471 if ((fd = open(dname, O_RDONLY)) == -1) {
476 strcpy((char *)lum, fname);
477 if (ioctl(fd, IOC_MDC_GETSTRIPE, (void *)lum) == -1) {
491 /* short term backwards compat only */
492 int op_get_file_stripe(char *path, struct lov_user_md *lum)
494 return llapi_file_get_stripe(path, lum);
497 static int find_process_file(DIR *dir, char *dname, char *fname,
498 struct find_param *param)
502 strncpy((char *)¶m->lmd->lmd_lmm, fname, param->lumlen);
504 rc = ioctl(dirfd(dir), IOC_MDC_GETSTRIPE, (void *)¶m->lmd->lmd_lmm);
506 if (errno == ENODATA) {
507 if (!param->obduuid && !param->quiet)
509 "%s/%s has no stripe info\n",
512 } else if (errno == EISDIR) {
513 fprintf(stderr, "process_file on directory %s/%s!\n",
515 /* add fname to directory list; */
518 err_msg("IOC_MDC_GETSTRIPE ioctl failed for '%s/%s'",
525 llapi_lov_dump_user_lmm(param, dname, fname);
530 /* some 64bit libcs implement readdir64() by calling sys_getdents(). the
531 * kernel's sys_getdents() doesn't return d_type. */
532 unsigned char handle_dt_unknown(char *parent, char *entry)
534 char path[PATH_MAX + 1];
537 ret = snprintf(path, PATH_MAX, "%s/%s", parent, entry);
541 fd = open(path, O_DIRECTORY|O_RDONLY);
543 if (errno == ENOTDIR)
544 return DT_REG; /* kind of a lie */
551 static int process_dir(DIR *dir, char *dname, struct find_param *param)
553 struct dirent64 *dirp;
558 if (!param->got_uuids) {
559 rc = setup_obd_uuids(dir, dname, param);
564 /* retrieve dir's stripe info */
565 strncpy((char *)¶m->lmd->lmd_lmm, dname, param->lumlen);
566 rc = ioctl(dirfd(dir), LL_IOC_LOV_GETSTRIPE, (void *)¶m->lmd->lmd_lmm);
568 if (errno == ENODATA) {
569 if (!param->obduuid && param->verbose)
570 printf("%s/%s has no stripe info\n", dname, "");
573 err_msg("GETSTRIPE failed for %s", dname);
576 llapi_lov_dump_user_lmm(param, dname, "");
579 /* Handle the contents of the directory */
580 while ((dirp = readdir64(dir)) != NULL) {
581 if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, ".."))
584 if (dirp->d_type == DT_UNKNOWN)
585 dirp->d_type = handle_dt_unknown(dname, dirp->d_name);
587 switch (dirp->d_type) {
589 err_msg("\"%s\" is UNKNOWN type %d", dirp->d_name,
591 /* If we cared we could stat the file to determine
592 * type and continue on here, but we don't since we
593 * know d_type should be valid for lustre and this
594 * tool only makes sense for lustre filesystems. */
597 if (!param->recursive)
601 strcat(path, dirp->d_name);
602 subdir = opendir(path);
603 if (subdir == NULL) {
604 err_msg("\"%.40s\" opendir failed", path);
607 rc = process_dir(subdir, path, param);
611 rc = param->process_file(dir,dname,dirp->d_name,param);
621 static int process_path(char *path, struct find_param *param)
627 fname = strrchr(path, '/');
628 if (fname != NULL && fname[1] == '\0') {
629 /* Trailing '/', it must be a dir */
633 err_msg("\"%.40s\" opendir failed", path);
636 rc = process_dir(dir, path, param);
639 } else if ((dir = opendir(path)) != NULL) {
640 /* No trailing '/', but it is still a dir */
641 rc = process_dir(dir, path, param);
644 /* It must be a file (or other non-directory) */
653 dir = opendir(dname);
655 err_msg("\"%.40s\" opendir failed", dname);
658 if (!param->got_uuids)
659 rc = setup_obd_uuids(dir, dname, param);
661 rc = param->process_file(dir, dname, fname, param);
669 int llapi_find(char *path, struct obd_uuid *obduuid, int recursive,
670 int verbose, int quiet)
672 struct find_param param;
675 memset(¶m, 0, sizeof(param));
676 param.recursive = recursive;
677 param.verbose = verbose;
679 param.process_file = find_process_file;
681 param.obduuid = malloc(sizeof(*obduuid));
682 if (param.obduuid == NULL) {
686 memcpy(param.obduuid, obduuid, sizeof(*obduuid));
689 ret = prepare_find(¶m);
693 process_path(path, ¶m);
695 cleanup_find(¶m);
699 #define MAX_STRING_SIZE 128
700 #define DEVICES_LIST "/proc/fs/lustre/devices"
702 int llapi_ping(char *obd_type, char *obd_name)
704 char path[MAX_STRING_SIZE];
708 snprintf(path, MAX_STRING_SIZE, "/proc/fs/lustre/%s/%s/ping",
711 fd = open(path, O_WRONLY);
713 fprintf(stderr, "error opening %s: %s\n", path, strerror(errno));
717 rc = write(fd, buf, 1);
725 int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb)
727 char buf[MAX_STRING_SIZE];
728 FILE *fp = fopen(DEVICES_LIST, "r");
732 fprintf(stderr, "error: %s opening "DEVICES_LIST"\n",
733 strerror(rc = errno));
737 while (fgets(buf, sizeof(buf), fp) != NULL) {
738 char *obd_type_name = NULL;
739 char *obd_name = NULL;
740 char *obd_uuid = NULL;
741 char rawbuf[OBD_MAX_IOCTL_BUFFER];
744 struct obd_ioctl_data datal = { 0, };
745 struct obd_statfs osfs_buffer;
747 while(bufp[0] == ' ')
750 for(i = 0; i < 3; i++) {
751 obd_type_name = strsep(&bufp, " ");
753 obd_name = strsep(&bufp, " ");
754 obd_uuid = strsep(&bufp, " ");
756 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
758 memset(bufl, 0, sizeof(rawbuf));
759 datal.ioc_pbuf1 = (char *)&osfs_buffer;
760 datal.ioc_plen1 = sizeof(osfs_buffer);
762 for (i = 0; i < type_num; i++) {
763 if (strcmp(obd_type_name, obd_type[i]) != 0)
766 cb(obd_type_name, obd_name, obd_uuid, args);
773 static void do_target_check(char *obd_type_name, char *obd_name,
774 char *obd_uuid, void *args)
778 rc = llapi_ping(obd_type_name, obd_name);
780 fprintf(stderr, "error: check %s: %s\n",
781 obd_name, strerror(rc = errno));
783 printf("%s active.\n", obd_name);
787 int llapi_target_check(int type_num, char **obd_type, char *dir)
789 return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
792 #undef MAX_STRING_SIZE
794 int llapi_catinfo(char *dir, char *keyword, char *node_name)
796 char raw[OBD_MAX_IOCTL_BUFFER];
797 char out[LLOG_CHUNK_SIZE];
799 struct obd_ioctl_data data;
804 sprintf(key, "%s", keyword);
805 memset(raw, 0, sizeof(raw));
806 memset(out, 0, sizeof(out));
807 data.ioc_inlbuf1 = key;
808 data.ioc_inllen1 = strlen(key) + 1;
810 data.ioc_inlbuf2 = node_name;
811 data.ioc_inllen2 = strlen(node_name) + 1;
813 data.ioc_pbuf1 = out;
814 data.ioc_plen1 = sizeof(out);
815 rc = obd_ioctl_pack(&data, &buf, sizeof(raw));
821 err_msg("open %s failed", dir);
825 rc = ioctl(dirfd(root), OBD_IOC_LLOG_CATINFO, buf);
827 err_msg("ioctl OBD_IOC_CATINFO failed");
829 fprintf(stdout, "%s", data.ioc_pbuf1);
835 int llapi_is_lustre_mnttype(char *type)
837 return (strcmp(type,"lustre") == 0 || strcmp(type,"lustre_lite") == 0);
840 int llapi_quotacheck(char *mnt, int check_type)
847 err_msg("open %s failed", mnt);
851 rc = ioctl(dirfd(root), LL_IOC_QUOTACHECK, check_type);
857 int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
865 err_msg("open %s failed", mnt);
870 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
882 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
889 err_msg("open %s failed", mnt);
893 rc = ioctl(dirfd(root), LL_IOC_QUOTACTL, qctl);
899 static int quotachown_process_file(DIR *dir, char *dname, char *fname,
900 struct find_param *param)
903 char pathname[PATH_MAX + 1] = "";
906 strncpy((char *)param->lmd, fname, param->lumlen);
908 rc = ioctl(dirfd(dir), IOC_MDC_GETFILEINFO, (void *)param->lmd);
910 if (errno == ENODATA) {
911 if (!param->obduuid && !param->quiet)
913 "%s/%s has no stripe info\n",
916 } else if (errno != EISDIR) {
917 err_msg("IOC_MDC_GETFILEINFO ioctl failed");
923 st = ¶m->lmd->lmd_st;
924 snprintf(pathname, sizeof(pathname), "%s/%s", dname, fname);
926 /* libc chown() will do extra check, and if the real owner is
927 * the same as the ones to set, it won't fall into kernel, so
928 * invoke syscall directly. */
929 rc = syscall(SYS_chown, pathname, st->st_uid, st->st_gid);
931 fprintf(stderr, "chown %s (%u,%u) fail: %s\n",
932 pathname, st->st_uid, st->st_gid, strerror(errno));
936 int llapi_quotachown(char *path, int flag)
938 struct find_param param;
941 memset(¶m, 0, sizeof(param));
945 param.process_file = quotachown_process_file;
947 ret = prepare_find(¶m);
951 process_path(path, ¶m);
953 cleanup_find(¶m);