Whamcloud - gitweb
b=18452
[fs/lustre-release.git] / lustre / utils / liblustreapi.c
index f824151..9ef5f2c 100644 (file)
@@ -66,6 +66,7 @@
 #include <unistd.h>
 #endif
 
+#include <libcfs/libcfsutil.h>  /* l_ioctl */
 #include <liblustre.h>
 #include <lnet/lnetctl.h>
 #include <obd.h>
@@ -160,18 +161,25 @@ void llapi_printf(int level, char *fmt, ...)
         va_end(args);
 }
 
+/**
+ * size_units is unchanged if no specifier used
+ */
 int parse_size(char *optarg, unsigned long long *size,
-               unsigned long long *size_units)
+               unsigned long long *size_units, int bytes_spec)
 {
         char *end;
 
-        *size = strtoul(optarg, &end, 0);
+        *size = strtoull(optarg, &end, 0);
 
         if (*end != '\0') {
                 if ((*end == 'b') && *(end+1) == '\0' &&
-                    (*size & (~0ULL << (64 - 9))) == 0) {
+                    (*size & (~0ULL << (64 - 9))) == 0 &&
+                    !bytes_spec) {
                         *size <<= 9;
                         *size_units = 1 << 9;
+                } else if ((*end == 'b') && *(end+1) == '\0' &&
+                           bytes_spec) {
+                        *size_units = 1;
                 } else if ((*end == 'k' || *end == 'K') &&
                            *(end+1) == '\0' && (*size &
                            (~0ULL << (64 - 10))) == 0) {
@@ -232,16 +240,19 @@ int llapi_stripe_limit_check(unsigned long stripe_size, int stripe_offset,
                 return -EINVAL;
         }
         if (stripe_offset < -1 || stripe_offset > MAX_OBD_DEVICES) {
+                errno = -EINVAL;
                 llapi_err(LLAPI_MSG_ERROR, "error: bad stripe offset %d",
                           stripe_offset);
                 return -EINVAL;
         }
         if (stripe_count < -1 || stripe_count > LOV_MAX_STRIPE_COUNT) {
+                errno = -EINVAL;
                 llapi_err(LLAPI_MSG_ERROR, "error: bad stripe count %d",
                           stripe_count);
                 return -EINVAL;
         }
         if (stripe_count > 0 && (__u64)stripe_size * stripe_count > 0xffffffff){
+                errno = -EINVAL;
                 llapi_err(LLAPI_MSG_ERROR, "error: stripe_size %lu * "
                           "stripe_count %u exceeds 4GB", stripe_size,
                           stripe_count);
@@ -250,58 +261,6 @@ int llapi_stripe_limit_check(unsigned long stripe_size, int stripe_offset,
         return 0;
 }
 
-int llapi_file_open(const char *name, int flags, int mode,
-                    unsigned long stripe_size, int stripe_offset,
-                    int stripe_count, int stripe_pattern)
-{
-        struct lov_user_md lum = { 0 };
-        int fd, rc = 0;
-        int isdir = 0;
-
-        fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
-        if (fd < 0 && errno == EISDIR) {
-                fd = open(name, O_DIRECTORY | O_RDONLY);
-                isdir++;
-        }
-
-        if (fd < 0) {
-                rc = -errno;
-                llapi_err(LLAPI_MSG_ERROR, "unable to open '%s'", name);
-                return rc;
-        }
-
-        if ((rc = llapi_stripe_limit_check(stripe_size, stripe_offset,
-                                           stripe_count, stripe_pattern)) != 0) {
-                errno = rc;
-                goto out;
-        }
-
-        /*  Initialize IOCTL striping pattern structure */
-        lum.lmm_magic = LOV_USER_MAGIC;
-        lum.lmm_pattern = stripe_pattern;
-        lum.lmm_stripe_size = stripe_size;
-        lum.lmm_stripe_count = stripe_count;
-        lum.lmm_stripe_offset = stripe_offset;
-
-        if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
-                char *errmsg = "stripe already set";
-                rc = -errno;
-                if (errno != EEXIST && errno != EALREADY)
-                        errmsg = strerror(errno);
-
-                llapi_err_noerrno(LLAPI_MSG_ERROR,
-                                  "error on ioctl "LPX64" for '%s' (%d): %s",
-                                  (__u64)LL_IOC_LOV_SETSTRIPE, name, fd, errmsg);
-        }
-out:
-        if (rc) {
-                close(fd);
-                fd = rc;
-        }
-
-        return fd;
-}
-
 static int poolpath(char *fsname, char *pathname, char *pool_pathname);
 
 int llapi_file_open_pool(const char *name, int flags, int mode,
@@ -326,30 +285,35 @@ int llapi_file_open_pool(const char *name, int flags, int mode,
         }
 
         if ((rc = llapi_stripe_limit_check(stripe_size, stripe_offset,
-                                           stripe_count, stripe_pattern)) != 0) {
+                                           stripe_count, stripe_pattern)) != 0){
                 errno = rc;
                 goto out;
         }
 
-        /* in case user give the full pool name <fsname>.<poolname>, skip
-         * the fsname */
-        ptr = strchr(pool_name, '.');
-        if (ptr != NULL) {
-                strncpy(fsname, pool_name, ptr - pool_name);
-                fsname[ptr - pool_name] = '\0';
-                /* if fsname matches a fs skip it
-                 * if not keep the poolname as is */
-                if (poolpath(fsname, NULL, NULL) == 0)
-                        pool_name = ptr + 1;
-        }
-
         /*  Initialize IOCTL striping pattern structure */
         lum.lmm_magic = LOV_USER_MAGIC_V3;
         lum.lmm_pattern = stripe_pattern;
         lum.lmm_stripe_size = stripe_size;
         lum.lmm_stripe_count = stripe_count;
         lum.lmm_stripe_offset = stripe_offset;
-        strncpy(lum.lmm_pool_name, pool_name, MAXPOOLNAME);
+
+        /* in case user give the full pool name <fsname>.<poolname>, skip
+         * the fsname */
+        if (pool_name != NULL) {
+                ptr = strchr(pool_name, '.');
+                if (ptr != NULL) {
+                        strncpy(fsname, pool_name, ptr - pool_name);
+                        fsname[ptr - pool_name] = '\0';
+                        /* if fsname matches a filesystem skip it
+                         * if not keep the poolname as is */
+                        if (poolpath(fsname, NULL, NULL) == 0)
+                                pool_name = ptr + 1;
+                }
+                strncpy(lum.lmm_pool_name, pool_name, LOV_MAXPOOLNAME);
+        } else {
+                /* If no pool is specified at all, use V1 request */
+                lum.lmm_magic = LOV_USER_MAGIC_V1;
+        }
 
         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
                 char *errmsg = "stripe already set";
@@ -359,7 +323,7 @@ int llapi_file_open_pool(const char *name, int flags, int mode,
 
                 llapi_err_noerrno(LLAPI_MSG_ERROR,
                                   "error on ioctl "LPX64" for '%s' (%d): %s",
-                                  (__u64)LL_IOC_LOV_SETSTRIPE, name, fd, errmsg);
+                                  (__u64)LL_IOC_LOV_SETSTRIPE, name, fd,errmsg);
         }
 out:
         if (rc) {
@@ -370,13 +334,23 @@ out:
         return fd;
 }
 
+int llapi_file_open(const char *name, int flags, int mode,
+                    unsigned long stripe_size, int stripe_offset,
+                    int stripe_count, int stripe_pattern)
+{
+        return llapi_file_open_pool(name, flags, mode, stripe_size,
+                                    stripe_offset, stripe_count,
+                                    stripe_pattern, NULL);
+}
+
 int llapi_file_create(const char *name, unsigned long stripe_size,
                       int stripe_offset, int stripe_count, int stripe_pattern)
 {
         int fd;
 
-        fd = llapi_file_open(name, O_CREAT | O_WRONLY, 0644, stripe_size,
-                             stripe_offset, stripe_count, stripe_pattern);
+        fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
+                                  stripe_offset, stripe_count, stripe_pattern,
+                                  NULL);
         if (fd < 0)
                 return fd;
 
@@ -443,7 +417,8 @@ static int search_fsname(char *pathname, char *fsname)
                 if (llapi_is_lustre_mnt(mnt)) {
                         /* search by pathname */
                         if (strncmp(mnt->mnt_dir, pathname,
-                                    strlen(mnt->mnt_dir)) == 0) {
+                                    max(strlen(pathname),
+                                        strlen(mnt->mnt_dir))) == 0) {
                                 ptr = strchr(mnt->mnt_fsname, '/');
                                 if (ptr == NULL)
                                         return -EINVAL;
@@ -456,7 +431,6 @@ static int search_fsname(char *pathname, char *fsname)
         }
         endmntent(fp);
         return -ENOENT;
-
 }
 
 /*
@@ -573,7 +547,8 @@ int llapi_poollist(char *name)
                             !((pool->d_name[0] == '.') &&
                               (pool->d_name[1] == '.') &&
                               (pool->d_name[2] == '\0')))
-                        llapi_printf(LLAPI_MSG_NORMAL, " %s.%s\n", fsname, pool->d_name);
+                        llapi_printf(LLAPI_MSG_NORMAL, " %s.%s\n",
+                                     fsname, pool->d_name);
                 }
                 closedir(dir);
         }
@@ -684,6 +659,24 @@ int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
         return rc;
 }
 
+int llapi_get_obd_count(char *mnt, int *count, int is_mdt)
+{
+        DIR *root;
+        int rc;
+
+        root = opendir(mnt);
+        if (!root) {
+                llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
+                return -1;
+        }
+
+        *count = is_mdt;
+        rc = ioctl(dirfd(root), LL_IOC_GETOBDCOUNT, count);
+
+        closedir(root);
+        return rc;
+}
+
 /* Here, param->obduuid points to a single obduuid, the index of which is
  * returned in param->obdindex */
 static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
@@ -854,21 +847,21 @@ void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
         }
 
         if (header && (obdstripe == 1)) {
-                llapi_printf(LLAPI_MSG_NORMAL,
-                             "lmm_magic:          0x%08X\n",  lum->lmm_magic);
-                llapi_printf(LLAPI_MSG_NORMAL,
-                             "lmm_object_gr:      "LPX64"\n", lum->lmm_object_gr);
-                llapi_printf(LLAPI_MSG_NORMAL,
-                             "lmm_object_id:      "LPX64"\n", lum->lmm_object_id);
-                llapi_printf(LLAPI_MSG_NORMAL,
-                             "lmm_stripe_count:   %u\n", (int)lum->lmm_stripe_count);
-                llapi_printf(LLAPI_MSG_NORMAL,
-                             "lmm_stripe_size:    %u\n",      lum->lmm_stripe_size);
-                llapi_printf(LLAPI_MSG_NORMAL,
-                             "lmm_stripe_pattern: %x\n",      lum->lmm_pattern);
+                llapi_printf(LLAPI_MSG_NORMAL, "lmm_magic:          0x%08X\n",
+                             lum->lmm_magic);
+                llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_gr:      "LPX64"\n",
+                             lum->lmm_object_gr);
+                llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_id:      "LPX64"\n",
+                             lum->lmm_object_id);
+                llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_count:   %u\n",
+                             (int)lum->lmm_stripe_count);
+                llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_size:    %u\n",
+                             lum->lmm_stripe_size);
+                llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_pattern: %x\n",
+                             lum->lmm_pattern);
                 if (pool_name != NULL)
                         llapi_printf(LLAPI_MSG_NORMAL,
-                                     "lmm_pool_name:      %s\n",      pool_name);
+                             "lmm_pool_name:      %s\n", pool_name);
         }
 
         if (body) {
@@ -882,9 +875,9 @@ void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
                         long long gr = objects[i].l_object_gr;
                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
                                 llapi_printf(LLAPI_MSG_NORMAL,
-                                             "\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
-                                             idx, oid, oid, gr,
-                                             obdindex == idx ? " *" : "");
+                                           "\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
+                                           idx, oid, oid, gr,
+                                           obdindex == idx ? " *" : "");
                 }
                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
         }
@@ -931,8 +924,8 @@ void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *path,
                 unsigned long long start = -1, end = 0;
                 if (!quiet && obdstripe == 1)
                         llapi_printf(LLAPI_MSG_NORMAL,
-                                     "joined\tobdidx\t\t objid\t\tobjid\t\t group"
-                                     "\t\tstart\t\tend\n");
+                                     "joined\tobdidx\t\t objid\t\tobjid\t\t "
+                                     "group\t\tstart\t\tend\n");
                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
                         int idx = lumj->lmm_objects[i].l_ost_idx;
                         long long oid = lumj->lmm_objects[i].l_object_id;
@@ -945,7 +938,7 @@ void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *path,
                         if (start != lumj->lmm_objects[i].l_extent_start ||
                             end != lumj->lmm_objects[i].l_extent_end) {
                                 start = lumj->lmm_objects[i].l_extent_start;
-                                llapi_printf(LLAPI_MSG_NORMAL, "\t%14llu", start);
+                                llapi_printf(LLAPI_MSG_NORMAL,"\t%14llu",start);
                                 end = lumj->lmm_objects[i].l_extent_end;
                                 if (end == (unsigned long long)-1)
                                         llapi_printf(LLAPI_MSG_NORMAL,
@@ -980,19 +973,18 @@ void llapi_lov_dump_user_lmm(struct find_param *param,
                                        (param->verbose || !param->obduuid));
                 break;
         case LOV_USER_MAGIC_V3: {
-                char pool_name[MAXPOOLNAME + 1];
+                char pool_name[LOV_MAXPOOLNAME + 1];
                 struct lov_user_ost_data_v1 *objects;
+                struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
 
-                strncpy(pool_name,
-                        ((struct lov_user_md_v3 *)(&param->lmd->lmd_lmm))->lmm_pool_name,
-                        MAXPOOLNAME);
-                pool_name[MAXPOOLNAME] = '\0';
-                objects = ((struct lov_user_md_v3 *)(&param->lmd->lmd_lmm))->lmm_objects;
+                strncpy(pool_name, lmmv3->lmm_pool_name, LOV_MAXPOOLNAME);
+                pool_name[LOV_MAXPOOLNAME] = '\0';
+                objects = lmmv3->lmm_objects;
                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, pool_name,
-                                      objects, path, is_dir,
-                                      param->obdindex, param->quiet,
-                                      param->verbose,
-                                      (param->verbose || !param->obduuid));
+                                       objects, path, is_dir,
+                                       param->obdindex, param->quiet,
+                                       param->verbose,
+                                       (param->verbose || !param->obduuid));
                 break;
         }
         default:
@@ -1107,8 +1099,8 @@ int llapi_mds_getfileinfo(char *path, DIR *parent,
                         return -ENOENT;
                 } else {
                         llapi_err(LLAPI_MSG_ERROR,
-                                  "error: %s: IOC_MDC_GETFILEINFO failed for %s",
-                                  __FUNCTION__, path);
+                                 "error: %s: IOC_MDC_GETFILEINFO failed for %s",
+                                 __FUNCTION__, path);
                         return ret;
                 }
         }
@@ -1169,6 +1161,10 @@ static int llapi_semantic_traverse(char *path, int size, DIR *parent,
                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
                         continue;
 
+                /* Don't traverse .lustre directory */
+                if (!(strcmp(dent->d_name, mdd_dot_lustre_name)))
+                        continue;
+
                 path[len] = 0;
                 if ((len + dent->d_reclen + 2) > size) {
                         llapi_err(LLAPI_MSG_ERROR,
@@ -1186,8 +1182,9 @@ static int llapi_semantic_traverse(char *path, int size, DIR *parent,
                                              ((struct find_param *)data)->lmd);
                         if (ret == 0) {
                                 ((struct find_param *)data)->have_fileinfo = 1;
-                                dent->d_type = llapi_filetype_dir_table[st->st_mode &
-                                                                        S_IFMT];
+                                dent->d_type =
+                                        llapi_filetype_dir_table[st->st_mode &
+                                                                 S_IFMT];
                         }
                         if (ret == -ENOENT)
                                 continue;
@@ -1234,7 +1231,7 @@ err:
  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
  *
  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
- * The table bolow gives the answers for the specified parameters (value and
+ * The table below gives the answers for the specified parameters (value and
  * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
  * --------------------------------------
  * 1 | file > limit; sign > 0 | -1 / -1 |
@@ -1401,7 +1398,7 @@ static int cb_find_init(char *path, DIR *parent, DIR *dir,
                                   __FUNCTION__, path);
                         goto decided;
                 } else {
-                        llapi_err(LLAPI_MSG_ERROR, "error: %s: %s failed for %s",
+                        llapi_err(LLAPI_MSG_ERROR,"error: %s: %s failed for %s",
                                   __FUNCTION__, dir ? "LL_IOC_MDC_GETINFO" :
                                   "IOC_MDC_GETFILEINFO", path);
                         return ret;
@@ -1460,8 +1457,10 @@ static int cb_find_init(char *path, DIR *parent, DIR *dir,
 
                         if (param->lmd->lmd_lmm.lmm_magic ==
                             LOV_USER_MAGIC_V3) {
-                                lmm_objects =
-                                 ((struct lov_user_md_v3 *)(&(param->lmd->lmd_lmm)))->lmm_objects;
+                                struct lov_user_md_v3 *lmmv3 =
+                                        (void *)&param->lmd->lmd_lmm;
+
+                                lmm_objects = lmmv3->lmm_objects;
                         } else {
                                 lmm_objects = param->lmd->lmd_lmm.lmm_objects;
                         }
@@ -1501,12 +1500,14 @@ static int cb_find_init(char *path, DIR *parent, DIR *dir,
         }
 
         if (param->check_pool) {
+                struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
+
                 /* empty requested pool is taken as no pool search => V1 */
                 if (((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V1) &&
                      (param->poolname[0] == '\0')) ||
                     ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3) &&
-                     (strncmp(((struct lov_user_md_v3 *)(&(param->lmd->lmd_lmm)))->lmm_pool_name,
-                              param->poolname, MAXPOOLNAME) == 0)) ||
+                     (strncmp(lmmv3->lmm_pool_name,
+                              param->poolname, LOV_MAXPOOLNAME) == 0)) ||
                     ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3) &&
                      (strcmp(param->poolname, "*") == 0))) {
                         if (param->exclude_pool)
@@ -1528,8 +1529,8 @@ static int cb_find_init(char *path, DIR *parent, DIR *dir,
         }
 
 obd_matches:
-        /* If file still fits the request, ask osd for updated info.
-           The regulat stat is almost of the same speed as some new
+        /* If file still fits the request, ask ost for updated info.
+           The regular stat is almost of the same speed as some new
            'glimpse-size-ioctl'. */
         if (!decision && S_ISREG(st->st_mode) &&
             (param->lmd->lmd_lmm.lmm_stripe_count || param->size)) {
@@ -1812,7 +1813,7 @@ int llapi_ping(char *obd_type, char *obd_name)
         return rc;
 }
 
-int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb)
+int llapi_target_iterate(int type_num, char **obd_type,void *args,llapi_cb_t cb)
 {
         char buf[MAX_STRING_SIZE];
         FILE *fp = fopen(DEVICES_LIST, "r");
@@ -1828,8 +1829,6 @@ int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t c
                 char *obd_type_name = NULL;
                 char *obd_name = NULL;
                 char *obd_uuid = NULL;
-                char rawbuf[OBD_MAX_IOCTL_BUFFER];
-                char *bufl = rawbuf;
                 char *bufp = buf;
                 struct obd_ioctl_data datal = { 0, };
                 struct obd_statfs osfs_buffer;
@@ -1845,7 +1844,6 @@ int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t c
 
                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
 
-                memset(bufl, 0, sizeof(rawbuf));
                 datal.ioc_pbuf1 = (char *)&osfs_buffer;
                 datal.ioc_plen1 = sizeof(osfs_buffer);
 
@@ -2050,7 +2048,8 @@ static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data,
 
         rc = chmod(path, st->st_mode);
         if (rc)
-                llapi_err(LLAPI_MSG_ERROR,"error: chmod %s (%hu)", path, st->st_mode);
+                llapi_err(LLAPI_MSG_ERROR, "error: chmod %s (%hu)",
+                          path, st->st_mode);
 
         return rc;
 }
@@ -2126,7 +2125,7 @@ static int rmtacl_notify(int ops)
                 if (rc < 0) {
                         perror("ioctl");
                 return -1;
-        }
+                }
 
                 found++;
         }
@@ -2379,3 +2378,181 @@ int llapi_ls(int argc, char *argv[])
 
         exit(execvp(argv[0], argv));
 }
+
+/* format must have %s%s, buf must be > 16 */
+static int get_mdtname(const char *name, char *format, char *buf)
+{
+        char suffix[]="-MDT0000";
+        int len = strlen(name);
+
+        if (len > 16) {
+                llapi_err(LLAPI_MSG_ERROR, "bad MDT name |%s|\n", name);
+                return -EINVAL;
+        }
+
+        if ((len > 8) && (strncmp(name + len - 8, "-MDT", 4) == 0))
+                suffix[0] = '\0';
+
+        return sprintf(buf, format, name, suffix);
+}
+
+#define CHANGELOG_FILE "/proc/fs/lustre/mdd/%s%s/changelog"
+
+/* return a file desc to readable changelog */
+int llapi_changelog_open(const char *mdtname, long long startrec)
+{
+        char path[256];
+        int rc, fd;
+
+        if (get_mdtname(mdtname, CHANGELOG_FILE, path) <0)
+                return -EINVAL;
+
+        if ((fd = open(path, O_RDONLY)) < 0) {
+                llapi_err(LLAPI_MSG_ERROR, "error: can't open |%s|\n", path);
+                return -errno;
+        }
+
+        rc = lseek(fd, (off_t)startrec, SEEK_SET);
+        if (rc < 0) {
+                llapi_err(LLAPI_MSG_ERROR, "can't seek rc=%d\n", rc);
+                return -errno;
+        }
+
+        return fd;
+}
+
+int llapi_changelog_clear(const char *mdtname, long long endrec)
+{
+        char path[256];
+        char val[20];
+        int fd, len;
+
+        if (endrec < 0) {
+                llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
+                          "can't purge negative records\n");
+                return -EINVAL;
+        }
+
+        if (get_mdtname(mdtname, CHANGELOG_FILE, path) <0)
+                return -EINVAL;
+
+        if ((fd = open(path, O_WRONLY)) < 0) {
+                llapi_err(LLAPI_MSG_ERROR, "error: can't open |%s|\n", path);
+                return errno;
+        }
+
+        snprintf(val, sizeof(val), "%llu", endrec);
+        len = write(fd, val, strlen(val));
+        close(fd);
+        if (len != strlen(val)) {
+                llapi_err(LLAPI_MSG_ERROR, "purge err\n");
+                return errno;
+        }
+
+        return 0;
+}
+
+static int dev_ioctl(struct obd_ioctl_data *data, int dev, int cmd)
+{
+        int rc;
+        static char rawbuf[8192];
+        static char *buf = rawbuf;
+
+        data->ioc_dev = dev;
+        memset(buf, 0, sizeof(rawbuf));
+
+        if ((rc = obd_ioctl_pack(data, &buf, sizeof(rawbuf)))) {
+                llapi_err(LLAPI_MSG_ERROR,
+                          "error: ioctl pack (%d) failed: rc %d", cmd, rc);
+                return rc;
+        }
+
+        rc = l_ioctl(OBD_DEV_ID, cmd, buf);
+        if (rc < 0) {
+                /* ioctl returns -1 with errno set */
+                rc = -errno;
+                return rc;
+        }
+
+        if (obd_ioctl_unpack(data, buf, sizeof(rawbuf))) {
+                llapi_err(LLAPI_MSG_ERROR,
+                          "error: invalid reply\n");
+                return -EPROTO;
+        }
+        return rc;
+}
+
+/* should we just grep it from proc? */
+static int dev_name2dev(char *name)
+{
+        struct obd_ioctl_data data;
+        int rc;
+
+        memset(&data, 0, sizeof(data));
+        data.ioc_inllen1 = strlen(name) + 1;
+        data.ioc_inlbuf1 = name;
+        rc = dev_ioctl(&data, -1, OBD_IOC_NAME2DEV);
+
+        if (rc < 0) {
+                llapi_err(LLAPI_MSG_ERROR, "Device %s not found %d\n", name,rc);
+                return rc;
+        }
+        return data.ioc_dev;
+}
+
+int llapi_fid2path(char *device, char *fidstr, char *buf, int buflen,
+                   __u64 recno, int *linkno)
+{
+        struct lu_fid fid;
+        struct obd_ioctl_data data;
+        int dev, rc;
+
+        while (*fidstr == '[')
+                fidstr++;
+
+        sscanf(fidstr, "0x%llx:0x%x:0x%x", &(fid.f_seq), &(fid.f_oid),
+               &(fid.f_ver));
+        if (!fid_is_sane(&fid)) {
+                llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
+                          "bad FID format [%s], should be "DFID"\n",
+                          fidstr, (__u64)1, 2, 0);
+                return -EINVAL;
+        }
+
+        dev = dev_name2dev(device);
+        if (dev < 0)
+                return dev;
+
+        memset(&data, 0, sizeof(data));
+        data.ioc_inlbuf1 = (char *)&fid;
+        data.ioc_inllen1 = sizeof(fid);
+        data.ioc_inlbuf2 = (char *)&recno;
+        data.ioc_inllen2 = sizeof(__u64);
+        data.ioc_inlbuf3 = (char *)linkno;
+        data.ioc_inllen3 = sizeof(int);
+        data.ioc_plen1 = buflen;
+        data.ioc_pbuf1 = buf;
+        rc = dev_ioctl(&data, dev, OBD_IOC_FID2PATH);
+
+        return rc;
+}
+
+int llapi_path2fid(const char *path, unsigned long long *seq,
+                   unsigned long *oid, unsigned long *ver)
+{
+        struct lu_fid fid;
+        int fd, rc;
+
+        fd = open(path, O_RDONLY);
+        if (fd < 0)
+                return -errno;
+
+        rc = ioctl(fd, LL_IOC_PATH2FID, &fid);
+        *seq = fid_seq(&fid);
+        *oid = fid_oid(&fid);
+        *ver = fid_ver(&fid);
+
+        close(fd);
+        return rc;
+}
+