diff --git a/osd-initiator/drivelist.c b/osd-initiator/drivelist.c
index f9865a3..583ea44 100644
--- a/osd-initiator/drivelist.c
+++ b/osd-initiator/drivelist.c
@@ -152,7 +152,7 @@ int osd_get_drive_list(struct osd_drive_description **drives, int *num_drives)
++count;
}
- /* grab the hostname from the fs.conf file */
+ /* For PVFS - grab the hostname from the fs.conf file */
int i=0, j;
int condition=1;
char *string[200];
@@ -165,7 +165,7 @@ int osd_get_drive_list(struct osd_drive_description **drives, int *num_drives)
file = fopen(conf_path, "r");
line = (char *) malloc(120);
- while(condition != EOF)
+ while(file && condition != EOF)
{
condition = fscanf(file, "%s", line);
if(condition != EOF)
@@ -183,7 +183,7 @@ int osd_get_drive_list(struct osd_drive_description **drives, int *num_drives)
}
}
- fclose(file);
+ if (file) fclose(file);
out:
if (toplevel)
diff --git a/osd-initiator/sync.c b/osd-initiator/sync.c
index bc73e66..11ac9f3 100644
--- a/osd-initiator/sync.c
+++ b/osd-initiator/sync.c
@@ -44,6 +44,7 @@ static int check_response(int ret, struct osd_command *command,
command->status, command->sense_len, command->inlen);
osd_error("%s ", osd_sense_as_string(command->sense,
command->sense_len));
+ return 1;
} else if (command->inlen > 0) {
osd_debug("Successfully performed task. BUF: <<%s>>", buf);
@@ -79,7 +80,7 @@ static int submit_command(int fd, struct osd_command *command,
ret = osd_submit_and_wait(fd, command);
osd_debug("....retrieving response");
}
- check_response(ret, &command, buf);
+ ret = check_response(ret, command, buf);
return ret;
}
@@ -87,7 +88,6 @@ static int submit_command(int fd, struct osd_command *command,
int inquiry(int fd)
{
const int INQUIRY_RSP_LEN = 80;
- int ret;
uint8_t inquiry_rsp[INQUIRY_RSP_LEN];
struct osd_command command;
@@ -140,7 +140,7 @@ int query(int fd, uint64_t pid, uint64_t cid, const uint8_t *query)
}
int create_osd(int fd, uint64_t pid, uint64_t requested_oid,
- uint16_t num_user_objects)
+ uint16_t num_user_objects, uint64_t *assigned_oid)
{
struct osd_command command;
@@ -154,6 +154,12 @@ int create_osd(int fd, uint64_t pid, uint64_t requested_oid,
submit_command(fd, &command, NULL);
+ if (assigned_oid != NULL) {
+ osd_command_attr_resolve(&command);
+ *assigned_oid = get_ntohll(command.attr[0].val);
+ osd_command_attr_free(&command);
+ }
+
return 0;
}
@@ -248,9 +254,17 @@ int remove_member_objects(int fd, uint64_t pid, uint64_t cid)
}
int create_and_write_osd(int fd, uint64_t pid, uint64_t requested_oid,
- const uint8_t *buf, uint64_t len, uint64_t offset)
+ const uint8_t *buf, uint64_t len, uint64_t offset,
+ uint64_t *assigned_oid)
{
struct osd_command command;
+ struct attribute_list attr = {
+ .type = ATTR_GET,
+ .page = CUR_CMD_ATTR_PG,
+ .number = CCAP_OID,
+ .len = 8,
+ };
+ int ret;
osd_debug("****** CREATE / WRITE ******");
osd_debug("PID: %llu OID: %llu BUF: %s", llu(pid), llu(requested_oid),
@@ -269,9 +283,18 @@ int create_and_write_osd(int fd, uint64_t pid, uint64_t requested_oid,
command.outdata = buf;
command.outlen = len;
- submit_command(fd, &command, NULL);
+ if (assigned_oid != NULL)
+ osd_command_attr_build(&command, &attr, 1);
+
+ ret = submit_command(fd, &command, NULL);
- return 0;
+ if (ret == 0 && assigned_oid != NULL) {
+ osd_command_attr_resolve(&command);
+ *assigned_oid = get_ntohll(command.attr[0].val);
+ osd_command_attr_free(&command);
+ }
+
+ return ret;
}
int create_and_write_sgl_osd(int fd, uint64_t pid, uint64_t requested_oid,
@@ -559,9 +582,7 @@ int read_osd(int fd, uint64_t pid, uint64_t oid, uint8_t *buf, uint64_t len,
command.indata = buf;
command.inlen_alloc = len;
- submit_command(fd, &command, buf);
-
- return 0;
+ return submit_command(fd, &command, buf);
}
int read_sgl_osd(int fd, uint64_t pid, uint64_t oid, uint8_t *ddt_buf,
diff --git a/osd-initiator/sync.h b/osd-initiator/sync.h
index 68be07f..19d58aa 100644
--- a/osd-initiator/sync.h
+++ b/osd-initiator/sync.h
@@ -27,11 +27,12 @@ int inquiry(int fd);
int query(int fd, uint64_t pid, uint64_t cid, const uint8_t *query);
/* Create */
int create_osd(int fd, uint64_t pid, uint64_t requested_oid,
- uint16_t num_user_objects);
+ uint16_t num_user_objects, uint64_t *assigned_oid);
int create_partition(int fd, uint64_t requested_pid);
int create_collection(int fd, uint64_t pid, uint64_t requested_cid);
int create_and_write_osd(int fd, uint64_t pid, uint64_t requested_oid,
- const uint8_t *buf, uint64_t len, uint64_t offset);
+ const uint8_t *buf, uint64_t len, uint64_t offset,
+ uint64_t *assigned_oid);
int create_and_write_sgl_osd(int fd, uint64_t pid, uint64_t requested_oid,
const uint8_t *buf, uint64_t len, uint64_t offset);
int create_and_write_vec_osd(int fd, uint64_t pid, uint64_t requested_oid,
diff --git a/osd-initiator/tests/Makefile b/osd-initiator/tests/Makefile
index 84ced0a..e03ec89 100644
--- a/osd-initiator/tests/Makefile
+++ b/osd-initiator/tests/Makefile
@@ -3,7 +3,7 @@
#
PROGSRC := sgio.c generic_iface_test.c iovec.c iospeed.c latency.c atomic.c \
- attr-all.c iospeed-ddt.c
+ attr-all.c iospeed-ddt.c cli.c
PROGSRC += blk-iospeed.c sgl_test.c alignment.c alignment-rdma.c
PROGOBJ := $(PROGSRC:.c=.o)
PROGEXE := $(PROGSRC:.c=)
@@ -41,7 +41,7 @@ CFLAGS += -Dsg_io_v4=sg_io_v4_v2624
all:: $(LIB) $(PROGEXE) $(MPIEXE)
$(PROGEXE): %: %.o $(LIB)
- $(CC) -o $@ $^ $(LIB) -lm
+ $(CC) -o $@ $^ $(LIB) -lm -lreadline
$(MPIEXE): %: %.o $(LIB)
$(MPICC) -o $@ $^ $(MPILIB) $(LIB) -lm
diff --git a/osd-initiator/tests/cli.c b/osd-initiator/tests/cli.c
new file mode 100644
index 0000000..596fd57
--- /dev/null
+++ b/osd-initiator/tests/cli.c
@@ -0,0 +1,515 @@
+/*
+ * cli.c -- Command Line Interface to an OSD
+ * derived from readline FileMan sample code
+ *
+ * Copyright (C) 2014 University of Connecticut. All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "osd-util/osd-util.h"
+#include "osd-util/osd-defs.h"
+#include "command.h"
+#include "sync.h"
+#include "drivelist.h"
+
+extern char *getwd ();
+extern char *xmalloc ();
+
+/* The names of functions that actually do the manipulation. */
+int com_cat(char *), com_create(char *), com_get(char *), com_help(char *);
+int com_ls(char *), com_part(char *), com_put(char *), com_quit(char *);
+int com_rm(char *), com_stat(char *);
+
+/* A structure which contains information on the commands this program
+ can understand. */
+
+typedef struct {
+ const char *name; /* User printable name of the function. */
+ Function *func; /* Function to call to do the job. */
+ const char *usage; /* Usage for this function. */
+ const char *doc; /* Documentation for this function. */
+} COMMAND;
+
+COMMAND commands[] = {
+ { "cat", com_cat, "oid", "View the contents of object oid" },
+ { "create", com_create, "pid", "Create partition" },
+ { "get", com_get, "oid filename [size]", "Copy OSD object to local file\n\tDefault size is 1M" },
+ { "help", com_help, "", "Documentation for CLI" },
+ { "ls", com_ls, "", "List objects in current partition" },
+ { "part", com_part, "pid", "Change current partition" },
+ { "put", com_put, "filename [oid]", "Copy local file to OSD" },
+ { "quit", com_quit, "", "Quit using CLI" },
+ { "rm", com_rm, "oid", "Delete object oid" },
+ { "stat", com_stat, "oid", "Print out statistics on object oid" },
+ { (char *)NULL, (Function *)NULL, (char *)NULL, (char *)NULL }
+};
+
+/* Forward declarations. */
+char *stripwhite (char *);
+COMMAND *find_command (char *);
+int execute_line(char *line);
+void initialize_readline (void);
+
+/* The name of this program, as taken from argv[0]. */
+char *progname;
+
+/* When non-zero, this global means the user is done using this program. */
+int done;
+
+static char *
+dupstr (s)
+ char *s;
+{
+ char *r;
+
+ r = xmalloc (strlen (s) + 1);
+ strcpy (r, s);
+ return (r);
+}
+
+static int connect_to_osd(void)
+{
+ int num_drives;
+ struct osd_drive_description *drives;
+ int ret = osd_get_drive_list(&drives, &num_drives);
+ if (ret < 0) {
+ printf("Could not get OSD drive list");
+ return 0;
+ }
+ if (num_drives == 0) {
+ printf("no OSD drives available\n");
+ return 0;
+ }
+
+ int i = 0;
+ printf("drive %s name %s\n", drives[i].chardev, drives[i].targetname);
+ int fd = open(drives[i].chardev, O_RDWR);
+ if (fd < 0) {
+ printf("Could not open %s", drives[i].chardev);
+ return 0;
+ }
+ osd_free_drive_list(drives, num_drives);
+
+ inquiry(fd);
+
+ return fd;
+}
+
+int osdfd;
+
+int main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *line, *s;
+
+ progname = argv[0];
+ argc--;
+
+ if ((osdfd = connect_to_osd()) == 0)
+ return -1;
+
+ initialize_readline (); /* Bind our completer. */
+
+ /* Loop reading and executing lines until the user quits. */
+ for ( ; done == 0; )
+ {
+ line = readline ("CLI> ");
+
+ if (!line)
+ break;
+
+ /* Remove leading and trailing whitespace from the line.
+ Then, if there is anything left, add it to the history list
+ and execute it. */
+ s = stripwhite (line);
+
+ if (*s)
+ {
+ add_history (s);
+ execute_line (s);
+ }
+
+ free (line);
+ }
+ return 0;
+}
+
+/* Execute a command line. */
+int
+execute_line (char *line)
+{
+ register int i;
+ COMMAND *command;
+ char *word;
+
+ /* Isolate the command word. */
+ i = 0;
+ while (line[i] && whitespace (line[i]))
+ i++;
+ word = line + i;
+
+ while (line[i] && !whitespace (line[i]))
+ i++;
+
+ if (line[i])
+ line[i++] = '\0';
+
+ command = find_command (word);
+
+ if (!command)
+ {
+ fprintf (stderr, "%s: No such command for OSD CLI.\n", word);
+ return (-1);
+ }
+
+ /* Get argument to command, if any. */
+ while (whitespace (line[i]))
+ i++;
+
+ word = line + i;
+
+ /* Call the function. */
+ return ((*(command->func)) (word));
+}
+
+/* Look up NAME as the name of a command, and return a pointer to that
+ command. Return a NULL pointer if NAME isn't a command name. */
+COMMAND *
+find_command (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; commands[i].name; i++)
+ if (strcmp (name, commands[i].name) == 0)
+ return (&commands[i]);
+
+ return ((COMMAND *)NULL);
+}
+
+/* Strip whitespace from the start and end of STRING. Return a pointer
+ into STRING. */
+char *
+stripwhite (string)
+ char *string;
+{
+ register char *s, *t;
+
+ for (s = string; whitespace (*s); s++)
+ ;
+
+ if (*s == 0)
+ return (s);
+
+ t = s + strlen (s) - 1;
+ while (t > s && whitespace (*t))
+ t--;
+ *++t = '\0';
+
+ return s;
+}
+
+/* **************************************************************** */
+/* */
+/* Interface to Readline Completion */
+/* */
+/* **************************************************************** */
+
+char *command_generator (char *, int);
+char **cli_completion (char *, int, int);
+
+/* Tell the GNU Readline library how to complete. We want to try to complete
+ on command names if this is the first word in the line, or on filenames
+ if not. */
+void initialize_readline ()
+{
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = "CLI";
+
+ /* Tell the completer that we want a crack first. */
+ rl_attempted_completion_function = (CPPFunction *)cli_completion;
+}
+
+/* Attempt to complete on the contents of TEXT. START and END bound the
+ region of rl_line_buffer that contains the word to complete. TEXT is
+ the word to complete. We can use the entire contents of rl_line_buffer
+ in case we want to do some simple parsing. Return the array of matches,
+ or NULL if there aren't any. */
+char **
+cli_completion (text, start, end)
+ char *text;
+ int start, end;
+{
+ char **matches;
+
+ matches = (char **)NULL;
+
+ /* If this word is at the start of the line, then it is a command
+ to complete. Otherwise it is the name of a file in the current
+ directory. */
+ if (start == 0)
+ matches = completion_matches (text, command_generator);
+
+ return (matches);
+}
+
+/* Generator function for command completion. STATE lets us know whether
+ to start from scratch; without any state (i.e. STATE == 0), then we
+ start at the top of the list. */
+char *
+command_generator (text, state)
+ char *text;
+ int state;
+{
+ static int list_index, len;
+ const char *name;
+
+ /* If this is a new word to complete, initialize now. This includes
+ saving the length of TEXT for efficiency, and initializing the index
+ variable to 0. */
+ if (!state)
+ {
+ list_index = 0;
+ len = strlen (text);
+ }
+
+ /* Return the next name which partially matches from the command list. */
+ while ((name = commands[list_index].name))
+ {
+ list_index++;
+
+ if (strncmp (name, text, len) == 0)
+ return (dupstr(name));
+ }
+
+ /* If no names matched, then return NULL. */
+ return ((char *)NULL);
+}
+
+/* Return non-zero if ARG is a valid argument for CALLER, else print
+ an error message and return zero. */
+static int
+valid_argument (caller, arg)
+ char *caller, *arg;
+{
+ if (!arg || !*arg)
+ {
+ fprintf (stderr, "%s: Argument required.\n", caller);
+ return (0);
+ }
+
+ return (1);
+}
+
+/* Function which tells you that you can't do this. */
+static void unimplemented (const char *cmd)
+{
+ fprintf (stderr, "%s command is unimplemented.\n", cmd);
+}
+
+/* **************************************************************** */
+/* */
+/* OSD CLI Commands */
+/* */
+/* **************************************************************** */
+
+static uint64_t current_pid = PARTITION_PID_INVALID;
+
+/* List the object(s) named in arg. */
+int com_ls (arg)
+ char *arg;
+{
+ unimplemented ("ls");
+ return 1;
+}
+
+int com_cat (arg)
+ char *arg;
+{
+ unimplemented ("cat");
+ return 1;
+}
+
+int com_get (arg)
+ char *arg;
+{
+ char *arg1, *arg2, *arg3;
+ for(;*arg==' ';arg++);
+ arg1 = arg;
+ for(;*arg!=' ';arg++);
+ arg2 = arg;
+ for(;*arg2==' ';arg2++);
+ *arg = 0;
+ arg = arg2;
+ for(;*arg && *arg!=' ';arg++);
+ arg3 = arg;
+ for(;*arg3 && *arg3==' ';arg3++);
+ *arg = 0;
+
+ uint64_t oid;
+ sscanf(arg1, "%" PRIx64, &oid);
+
+ uint64_t bufsize = 1024*1024;
+ if (*arg3)
+ sscanf(arg3, "%" PRId64, &bufsize);
+ unsigned char *buf = malloc(bufsize);
+ if (current_pid == PARTITION_PID_INVALID) {
+ printf("Current partition is not set. Use part command\n");
+ return 0;
+ }
+ int ret = read_osd(osdfd, current_pid, oid, buf, bufsize, 0);
+
+ int fd = open(arg2, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+ write(fd, buf, bufsize);
+ free(buf);
+
+ if (ret == 0)
+ printf(" Copied object 0x%llx to %s\n", llu(oid), arg2 );
+
+ return 1;
+}
+
+int com_put (arg)
+ char *arg;
+{
+ struct stat stat;
+ char *arg1, *arg2;
+ for(;*arg==' ';arg++);
+ arg1 = arg;
+ for(;*arg && *arg!=' ';arg++);
+ arg2 = arg;
+ for(;*arg2 && *arg2==' ';arg2++);
+ *arg = 0;
+
+ if (current_pid == PARTITION_PID_INVALID) {
+ printf("current pid is not set\n");
+ return 0;
+ }
+
+ int fd = open(arg1, O_RDONLY);
+ fstat(fd, &stat);
+
+ unsigned char *buf = malloc(stat.st_size);
+ read(fd, buf, stat.st_size);
+
+ uint64_t requested_oid=0, assigned_oid;
+ if (*arg2)
+ sscanf(arg2, "%" PRIx64, &requested_oid);
+
+ int ret = create_and_write_osd(osdfd, current_pid, requested_oid, buf,
+ stat.st_size, 0, &assigned_oid);
+ if (ret == 0)
+ printf(" Copied %s to object 0x%llx\n", arg1, llu(assigned_oid));
+
+ free(buf);
+
+ return 1;
+}
+
+int com_part (arg)
+ char *arg;
+{
+ uint64_t pid;
+ sscanf(arg, "%" PRIx64, &pid);
+ current_pid = pid;
+ return (1);
+}
+
+int com_stat (arg)
+ char *arg;
+{
+ if (!valid_argument ("stat", arg))
+ return (1);
+ return 0;
+}
+
+int com_rm (arg)
+ char *arg;
+{
+ unimplemented ("rm");
+ return (1);
+}
+
+int com_create (arg)
+ char *arg;
+{
+ uint64_t pid;
+ sscanf(arg, "%" PRIx64, &pid);
+ create_partition(osdfd, pid);
+ current_pid = pid;
+ return (1);
+}
+
+/* Print out help for ARG, or for all of the commands if ARG is
+ not present. */
+int com_help (arg)
+ char *arg;
+{
+ register int i;
+ int printed = 0;
+
+ /* set tab at position 24 */
+ printf("\r\t\033[0g\t\033[0g\r");
+ for (i = 0; commands[i].name; i++)
+ {
+ if (!*arg || (strcmp (arg, commands[i].name) == 0))
+ {
+ printf ("\033[1m%s\033[0m %s\t%s.\n", commands[i].name, commands[i].usage, commands[i].doc);
+ printed++;
+ }
+ }
+ /* reset tabs */
+ printf("\r\033[8C\033H\033[8C\033H\r");
+
+ if (!printed)
+ {
+ printf ("No commands match `%s'. Possibilties are:\n", arg);
+
+ for (i = 0; commands[i].name; i++)
+ {
+ /* Print in six columns. */
+ if (printed == 6)
+ {
+ printed = 0;
+ printf ("\n");
+ }
+
+ printf ("%s\t", commands[i].name);
+ printed++;
+ }
+
+ if (printed)
+ printf ("\n");
+ }
+ return (0);
+}
+
+/* The user wishes to quit using this program. Just set DONE non-zero. */
+int com_quit (arg)
+ char *arg;
+{
+ done = 1;
+ return (0);
+}
diff --git a/osd-initiator/tests/sgio.c b/osd-initiator/tests/sgio.c
index 9bfa31e..03a9fc3 100644
--- a/osd-initiator/tests/sgio.c
+++ b/osd-initiator/tests/sgio.c
@@ -400,9 +400,9 @@ int main(int argc, char *argv[])
#if 1 /* Basic read / write seems to work */
- create_osd(fd, PID, OID, NUM_USER_OBJ);
- create_osd(fd, PID, OID+1, NUM_USER_OBJ);
- create_osd(fd, PID, OID+2, NUM_USER_OBJ);
+ create_osd(fd, PID, OID, NUM_USER_OBJ, NULL);
+ create_osd(fd, PID, OID+1, NUM_USER_OBJ, NULL);
+ create_osd(fd, PID, OID+2, NUM_USER_OBJ, NULL);
remove_osd(fd, PID, OID+1);
write_osd(fd, PID, OID, WRITEDATA, sizeof(WRITEDATA), OFFSET);
@@ -419,8 +419,8 @@ int main(int argc, char *argv[])
#endif
#if 1 /* Testing iovec list. */
- create_osd(fd, PID, OID+3, 1);
- create_osd(fd, PID, OID+4, 1);
+ create_osd(fd, PID, OID+3, 1, NULL);
+ create_osd(fd, PID, OID+4, 1, NULL);
iovec_write_test(fd, PID, OID+3);
iovec_read_test(fd, PID, OID+4);
@@ -430,28 +430,28 @@ int main(int argc, char *argv[])
#endif
#if 1 /* Testing bidirectional operations. */
- create_osd(fd, PID, OID+5, 1);
+ create_osd(fd, PID, OID+5, 1, NULL);
write_osd(fd, PID, OID+5, (const uint8_t *) "sixty-seven", 12, 0);
bidi_test(fd, PID, OID+5);
remove_osd(fd, PID, OID+5);
#endif
#if 1 /* Testing attribute API */
- create_osd(fd, PID, OID+6, 1);
+ create_osd(fd, PID, OID+6, 1, NULL);
attr_test(fd, PID, OID+6);
remove_osd(fd, PID, OID+6);
#endif
#if 1 /* Testing all-attribute API (listing attributes in a page */
- create_osd(fd, PID, OID+7, 1);
+ create_osd(fd, PID, OID+7, 1, NULL);
all_attr_test(fd, PID, OID+7);
remove_osd(fd, PID, OID+7);
#endif
#if 1 /* Testing stuff */
- create_osd(fd, PID, OID+10, NUM_USER_OBJ);
- create_osd(fd, PID, OID+11, NUM_USER_OBJ);
+ create_osd(fd, PID, OID+10, NUM_USER_OBJ, NULL);
+ create_osd(fd, PID, OID+11, NUM_USER_OBJ, NULL);
write_osd(fd, PID, OID, WRITEDATA, sizeof(WRITEDATA), OFFSET);
read_osd(fd, PID, OID, outbuf, sizeof(WRITEDATA), OFFSET);
#endif
diff --git a/osd-initiator/tests/sgl_test.c b/osd-initiator/tests/sgl_test.c
index 3f3e6ac..a856a84 100644
--- a/osd-initiator/tests/sgl_test.c
+++ b/osd-initiator/tests/sgl_test.c
@@ -209,7 +209,7 @@ static void basic_test_sgl(int fd, uint64_t pid, uint64_t oid)
xbuf = malloc(100);
memset(xbuf, 'Y', 100);
- ret = create_and_write_osd(fd, pid, oid+1, xbuf, 100, 0);
+ ret = create_and_write_osd(fd, pid, oid+1, xbuf, 100, 0, NULL);
assert(ret == 0);
free(xbuf);
@@ -368,7 +368,7 @@ static void basic_test_vec(int fd, uint64_t pid, uint64_t oid)
xbuf = malloc(100);
memset(xbuf, 'Y', 100);
- ret = create_and_write_osd(fd, pid, oid+1, xbuf, 100, 0);
+ ret = create_and_write_osd(fd, pid, oid+1, xbuf, 100, 0, NULL);
assert(ret == 0);
free(xbuf);
diff --git a/osd-util/osd-defs.h b/osd-util/osd-defs.h
index a896abe..d0c9826 100644
--- a/osd-util/osd-defs.h
+++ b/osd-util/osd-defs.h
@@ -96,6 +96,7 @@
#define ROOT_PID 0LLU
#define ROOT_OID 0LLU
#define PARTITION_PID_LB 0x10000LLU
+#define PARTITION_PID_INVALID 0xFFFFLLU
#define PARTITION_OID 0x0LLU
#define OBJECT_PID_LB 0x10000LLU
#define SPONTANEOUS_COLLECTION_PID_LB 0x10000LLU