From 1e40a57d1689b4943f67db5e249008d7f0969208 Mon Sep 17 00:00:00 2001 From: "Kaleb S. KEITHLEY" Date: Mon, 2 Dec 2013 10:47:26 -0500 Subject: gfapi: backport handles to 3.4 for nfs-ganesha nfs-ganesha-2.0 will ship shortly. It depends on the gfapi handle support, which won't otherwise be released until 3.5 sometime in 2014. Change-Id: I104d6fb275bb2c710790340fdc7d998446403026 Signed-off-by: Kaleb S. KEITHLEY Reviewed-on: http://review.gluster.org/6394 Tested-by: Gluster Build System Reviewed-by: Shyamsundar Ranganathan Reviewed-by: Vijay Bellur --- api/examples/glfsxmp.c | 1364 +++++++++++++++++++++++++++++++++++++++++- api/src/Makefile.am | 5 +- api/src/glfs-fops.c | 18 +- api/src/glfs-handleops.c | 1278 +++++++++++++++++++++++++++++++++++++++ api/src/glfs-handles.h | 143 +++++ api/src/glfs-internal.h | 59 ++ api/src/glfs-mem-types.h | 3 +- api/src/glfs-resolve.c | 67 ++- api/src/glfs.c | 14 + api/src/glfs.h | 26 + libglusterfs/src/globals.c | 57 +- libglusterfs/src/globals.h | 4 + libglusterfs/src/mem-types.h | 3 +- libglusterfs/src/syncop.c | 154 +++++ libglusterfs/src/syncop.h | 78 ++- 15 files changed, 3229 insertions(+), 44 deletions(-) create mode 100644 api/src/glfs-handleops.c create mode 100644 api/src/glfs-handles.h diff --git a/api/examples/glfsxmp.c b/api/examples/glfsxmp.c index 644793a4b..8231a3949 100644 --- a/api/examples/glfsxmp.c +++ b/api/examples/glfsxmp.c @@ -1,6 +1,8 @@ #include +#include #include #include "api/glfs.h" +#include "api/glfs-handles.h" #include #include @@ -133,11 +135,1357 @@ test_chdir (glfs_t *fs) return 0; } +#ifdef DEBUG +static void +peek_stat (struct stat *sb) +{ + printf ("Dumping stat information:\n"); + printf ("File type: "); + + switch (sb->st_mode & S_IFMT) { + case S_IFBLK: printf ("block device\n"); break; + case S_IFCHR: printf ("character device\n"); break; + case S_IFDIR: printf ("directory\n"); break; + case S_IFIFO: printf ("FIFO/pipe\n"); break; + case S_IFLNK: printf ("symlink\n"); break; + case S_IFREG: printf ("regular file\n"); break; + case S_IFSOCK: printf ("socket\n"); break; + default: printf ("unknown?\n"); break; + } + + printf ("I-node number: %ld\n", (long) sb->st_ino); + + printf ("Mode: %lo (octal)\n", + (unsigned long) sb->st_mode); + + printf ("Link count: %ld\n", (long) sb->st_nlink); + printf ("Ownership: UID=%ld GID=%ld\n", + (long) sb->st_uid, (long) sb->st_gid); + + printf ("Preferred I/O block size: %ld bytes\n", + (long) sb->st_blksize); + printf ("File size: %lld bytes\n", + (long long) sb->st_size); + printf ("Blocks allocated: %lld\n", + (long long) sb->st_blocks); + + printf ("Last status change: %s", ctime(&sb->st_ctime)); + printf ("Last file access: %s", ctime(&sb->st_atime)); + printf ("Last file modification: %s", ctime(&sb->st_mtime)); + + return; +} + +static void +peek_handle (unsigned char *glid) +{ + int i; + + for (i = 0; i < GFAPI_HANDLE_LENGTH; i++) + { + printf (":%02x:", glid[i]); + } + printf ("\n"); +} +#else /* DEBUG */ +static void +peek_stat (struct stat *sb) +{ + return; +} + +static void +peek_handle (unsigned char *id) +{ + return; +} +#endif /* DEBUG */ + +glfs_t *fs = NULL; +char *full_parent_name = "/testdir", *parent_name = "testdir"; + +void +test_h_unlink (void) +{ + char *my_dir = "unlinkdir"; + char *my_file = "file.txt"; + char *my_subdir = "dir1"; + struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL, + *subdir = NULL, *subleaf = NULL; + struct stat sb; + int ret; + + printf ("glfs_h_unlink tests: In Progress\n"); + + /* Prepare tests */ + parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror (errno)); + printf ("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + dir = glfs_h_mkdir (fs, parent, my_dir, 0644, &sb); + if (dir == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, parent, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + leaf = glfs_h_creat (fs, dir, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + subdir = glfs_h_mkdir (fs, dir, my_subdir, 0644, &sb); + if (subdir == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_subdir, dir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + subleaf = glfs_h_creat (fs, subdir, my_file, O_CREAT, 0644, &sb); + if (subleaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, subdir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink non empty directory */ + ret = glfs_h_unlink (fs, dir, my_subdir); + if ((ret && errno != ENOTEMPTY) || (ret == 0)) { + fprintf (stderr, "glfs_h_unlink: error unlinking %s: it is non empty: %s\n", + my_subdir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink regular file */ + ret = glfs_h_unlink (fs, subdir, my_file); + if (ret) { + fprintf (stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n", + my_file, subdir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink directory */ + ret = glfs_h_unlink (fs, dir, my_subdir); + if (ret) { + fprintf (stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n", + my_subdir, dir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink regular file */ + ret = glfs_h_unlink (fs, dir, my_file); + if (ret) { + fprintf (stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n", + my_file, dir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink non-existant regular file */ + ret = glfs_h_unlink (fs, dir, my_file); + if ((ret && errno != ENOENT) || (ret == 0)) { + fprintf (stderr, "glfs_h_unlink: error unlinking non-existant %s: invalid errno ,%d, %s\n", + my_file, ret, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink non-existant directory */ + ret = glfs_h_unlink (fs, dir, my_subdir); + if ((ret && errno != ENOENT) || (ret == 0)) { + fprintf (stderr, "glfs_h_unlink: error unlinking non-existant %s: invalid errno ,%d, %s\n", + my_subdir, ret, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink directory */ + ret = glfs_h_unlink (fs, parent, my_dir); + if (ret) { + fprintf (stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n", + my_dir, dir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + printf ("glfs_h_unlink tests: PASSED\n"); + +out: + if (dir) + glfs_h_close (dir); + if (leaf) + glfs_h_close (leaf); + if (subdir) + glfs_h_close (subdir); + if (subleaf) + glfs_h_close (subleaf); + if (parent) + glfs_h_close (parent); + + return; +} + +void +test_h_getsetattrs (void) +{ + char *my_dir = "attrdir", *full_dir_path="/testdir/attrdir"; + char *my_file = "attrfile.txt"; + struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL; + struct stat sb, retsb; + int ret, valid; + struct timespec timestamp; + + printf("glfs_h_getattrs and setattrs tests: In Progress\n"); + + /* Prepare tests */ + parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror (errno)); + printf ("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + dir = glfs_h_mkdir (fs, parent, my_dir, 0644, &sb); + if (dir == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, parent, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + leaf = glfs_h_creat (fs, dir, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dir, strerror (errno)); + printf ("glfs_h_unlink tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + ret = glfs_h_getattrs (fs, dir, &retsb); + if (ret != 0) { + fprintf (stderr, "glfs_h_getattrs: error %s: from (%p),%s\n", + my_dir, dir, strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + peek_stat (&retsb); + /* TODO: Compare stat information */ + + retsb.st_mode = 00666; + retsb.st_uid = 1000; + retsb.st_gid = 1001; + ret = clock_gettime (CLOCK_REALTIME, ×tamp); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + retsb.st_atim = timestamp; + retsb.st_mtim = timestamp; + valid = GFAPI_SET_ATTR_MODE | GFAPI_SET_ATTR_UID | GFAPI_SET_ATTR_GID | + GFAPI_SET_ATTR_ATIME | GFAPI_SET_ATTR_MTIME; + peek_stat (&retsb); + + ret = glfs_h_setattrs (fs, dir, &retsb, valid); + if (ret != 0) { + fprintf (stderr, "glfs_h_setattrs: error %s: from (%p),%s\n", + my_dir, dir, strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + memset(&retsb, 0, sizeof (struct stat)); + ret = glfs_h_stat (fs, dir, &retsb); + if (ret != 0) { + fprintf (stderr, "glfs_h_stat: error %s: from (%p),%s\n", + my_dir, dir, strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + peek_stat (&retsb); + + printf ("glfs_h_getattrs and setattrs tests: PASSED\n"); +out: + if (parent) + glfs_h_close (parent); + if (leaf) + glfs_h_close (leaf); + if (dir) + glfs_h_close (dir); + + return; +} + +void +test_h_truncate (void) +{ + char *my_dir = "truncatedir"; + char *my_file = "file.txt"; + struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL; + struct stat sb, retsb; + glfs_fd_t *fd = NULL; + char buf[32]; + off_t offset = 0; + int ret = 0; + + printf("glfs_h_truncate tests: In Progress\n"); + + /* Prepare tests */ + root = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (root == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + parent = glfs_h_mkdir (fs, root, my_dir, 0644, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, root, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + leaf = glfs_h_creat (fs, parent, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, parent, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + fd = glfs_h_open (fs, leaf, O_RDWR); + if (fd == NULL) { + fprintf (stderr, "glfs_h_open: error on open of %s: %s\n", + my_file, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + + memcpy (buf, "abcdefghijklmnopqrstuvwxyz012345", 32); + ret = glfs_write (fd, buf, 32, 0); + + /* run tests */ + /* truncate lower */ + offset = 30; + ret = glfs_h_truncate (fs, leaf, offset); + if (ret != 0) { + fprintf (stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n", + my_file, parent, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + ret = glfs_h_getattrs (fs, leaf, &sb); + if (ret != 0) { + fprintf (stderr, "glfs_h_getattrs: error for %s (%p),%s\n", + my_file, leaf, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + if (sb.st_size != offset) { + fprintf (stderr, "glfs_h_truncate: post size mismatch\n"); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + + /* truncate higher */ + offset = 32; + ret = glfs_h_truncate (fs, leaf, offset); + if (ret != 0) { + fprintf (stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n", + my_file, parent, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + ret = glfs_h_getattrs (fs, leaf, &sb); + if (ret != 0) { + fprintf (stderr, "glfs_h_getattrs: error for %s (%p),%s\n", + my_file, leaf, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + if (sb.st_size != offset) { + fprintf (stderr, "glfs_h_truncate: post size mismatch\n"); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + + /* truncate equal */ + offset = 30; + ret = glfs_h_truncate (fs, leaf, offset); + if (ret != 0) { + fprintf (stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n", + my_file, parent, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + ret = glfs_h_getattrs (fs, leaf, &sb); + if (ret != 0) { + fprintf (stderr, "glfs_h_getattrs: error for %s (%p),%s\n", + my_file, leaf, strerror (errno)); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + if (sb.st_size != offset) { + fprintf (stderr, "glfs_h_truncate: post size mismatch\n"); + printf ("glfs_h_truncate tests: FAILED\n"); + goto out; + } + + printf ("glfs_h_truncate tests: PASSED\n"); +out: + if (fd) + glfs_close (fd); + if (root) + glfs_h_close (root); + if (parent) + glfs_h_close (parent); + if (leaf) + glfs_h_close (leaf); + + return; +} + +void +test_h_links (void) +{ + char *my_dir = "linkdir", *full_dir_path="/testdir/linkdir"; + char *my_file = "file.txt"; + char *my_symlnk = "slnk.txt"; + char *my_lnk = "lnk.txt"; + char *linksrc_dir = "dir1"; + char *linktgt_dir = "dir2"; + struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL, + *dirsrc = NULL, *dirtgt = NULL, *dleaf = NULL; + struct glfs_object *ln1 = NULL; + struct stat sb, retsb; + int ret, valid; + char *buf = NULL; + + printf("glfs_h_link(s) tests: In Progress\n"); + + /* Prepare tests */ + root = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (root == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + parent = glfs_h_mkdir (fs, root, my_dir, 0644, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, root, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + leaf = glfs_h_creat (fs, parent, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, parent, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + dirsrc = glfs_h_mkdir (fs, parent, linksrc_dir, 0644, &sb); + if (dirsrc == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + linksrc_dir, parent, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + dirtgt = glfs_h_mkdir (fs, parent, linktgt_dir, 0644, &sb); + if (dirtgt == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + linktgt_dir, parent, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + dleaf = glfs_h_creat (fs, dirsrc, my_file, O_CREAT, 0644, &sb); + if (dleaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dirsrc, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + /* run tests */ + /* sym link: /testdir/linkdir/file.txt to ./slnk.txt */ + ln1 = glfs_h_symlink (fs, parent, my_symlnk, "./file.txt", &sb); + if (ln1 == NULL) { + fprintf (stderr, "glfs_h_symlink: error creating %s: from (%p),%s\n", + my_symlnk, parent, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + buf = calloc (1024, sizeof(char)); + if (buf == NULL) { + fprintf (stderr, "Error allocating memory\n"); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + + ret = glfs_h_readlink (fs, ln1, buf, 1024); + if (ret <= 0) { + fprintf (stderr, "glfs_h_readlink: error reading %s: from (%p),%s\n", + my_symlnk, ln1, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + if (!(strncmp (buf, my_symlnk, strlen (my_symlnk)))) { + fprintf (stderr, "glfs_h_readlink: error mismatch in link name: actual %s: retrieved %s\n", + my_symlnk, buf); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + + /* link: /testdir/linkdir/file.txt to ./lnk.txt */ + ret = glfs_h_link (fs, leaf, parent, my_lnk); + if (ret != 0) { + fprintf (stderr, "glfs_h_link: error creating %s: from (%p),%s\n", + my_lnk, parent, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + /* TODO: Should write content to a file and read from the link */ + + /* link: /testdir/linkdir/dir1/file.txt to ../dir2/slnk.txt */ + ret = glfs_h_link (fs, dleaf, dirtgt, my_lnk); + if (ret != 0) { + fprintf (stderr, "glfs_h_link: error creating %s: from (%p),%s\n", + my_lnk, dirtgt, strerror (errno)); + printf ("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + /* TODO: Should write content to a file and read from the link */ + + printf ("glfs_h_link(s) tests: PASSED\n"); + +out: + if (root) + glfs_h_close (root); + if (parent) + glfs_h_close (parent); + if (leaf) + glfs_h_close (leaf); + if (dirsrc) + glfs_h_close (dirsrc); + if (dirtgt) + glfs_h_close (dirtgt); + if (dleaf) + glfs_h_close (dleaf); + if (ln1) + glfs_h_close (ln1); + if (buf) + free (buf); + + return; +} + +void +test_h_rename (void) +{ + char *my_dir = "renamedir", + *full_dir_path="/testdir/renamedir"; + char *my_file = "file.txt"; + char *src_dir = "dir1"; + char *tgt_dir = "dir2"; + struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL, + *dirsrc = NULL, *dirtgt = NULL, *dleaf = NULL; + struct stat sb, retsb; + int ret, valid; + + printf("glfs_h_rename tests: In Progress\n"); + + /* Prepare tests */ + root = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (root == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + parent = glfs_h_mkdir (fs, root, my_dir, 0644, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, root, strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + leaf = glfs_h_creat (fs, parent, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, parent, strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + dirsrc = glfs_h_mkdir (fs, parent, src_dir, 0644, &sb); + if (dirsrc == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + src_dir, parent, strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + dirtgt = glfs_h_mkdir (fs, parent, tgt_dir, 0644, &sb); + if (dirtgt == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + tgt_dir, parent, strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + dleaf = glfs_h_creat (fs, dirsrc, my_file, O_CREAT, 0644, &sb); + if (dleaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dirsrc, strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + /* run tests */ + /* Rename file.txt -> file1.txt */ + ret = glfs_h_rename (fs, parent, "file.txt", parent, "file1.txt"); + if (ret != 0) { + fprintf (stderr, "glfs_h_rename: error renaming %s to %s (%s)\n", + "file.txt", "file1.txt", strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename dir1/file.txt -> file.txt */ + ret = glfs_h_rename (fs, dirsrc, "file.txt", parent, "file.txt"); + if (ret != 0) { + fprintf (stderr, "glfs_h_rename: error renaming %s/%s to %s (%s)\n", + src_dir, "file.txt", "file.txt", strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename file1.txt -> file.txt (exists) */ + ret = glfs_h_rename (fs, parent, "file1.txt", parent, "file.txt"); + if (ret != 0) { + fprintf (stderr, "glfs_h_rename: error renaming %s to %s (%s)\n", + "file.txt", "file.txt", strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename dir1 -> dir3 */ + ret = glfs_h_rename (fs, parent, "dir1", parent, "dir3"); + if (ret != 0) { + fprintf (stderr, "glfs_h_rename: error renaming %s to %s (%s)\n", + "dir1", "dir3", strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename dir2 ->dir3 (exists) */ + ret = glfs_h_rename (fs, parent, "dir2", parent, "dir3"); + if (ret != 0) { + fprintf (stderr, "glfs_h_rename: error renaming %s to %s (%s)\n", + "dir2", "dir3", strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename file.txt -> dir3 (fail) */ + ret = glfs_h_rename (fs, parent, "file.txt", parent, "dir3"); + if (ret == 0) { + fprintf (stderr, "glfs_h_rename: NO error renaming %s to %s (%s)\n", + "file.txt", "dir3", strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename dir3 -> file.txt (fail) */ + ret = glfs_h_rename (fs, parent, "dir3", parent, "file.txt"); + if (ret == 0) { + fprintf (stderr, "glfs_h_rename: NO error renaming %s to %s (%s)\n", + "dir3", "file.txt", strerror (errno)); + printf ("glfs_h_rename tests: FAILED\n"); + goto out; + } + + printf ("glfs_h_rename tests: PASSED\n"); + +out: + if (root) + glfs_h_close (root); + if (parent) + glfs_h_close (parent); + if (leaf) + glfs_h_close (leaf); + if (dirsrc) + glfs_h_close (dirsrc); + if (dirtgt) + glfs_h_close (dirtgt); + if (dleaf) + glfs_h_close (dleaf); + + return; +} + +void +assimilatetime (struct timespec *ts, struct timespec ts_st, + struct timespec ts_ed) +{ + if ((ts_ed.tv_nsec - ts_st.tv_nsec) < 0) { + ts->tv_sec += ts_ed.tv_sec - ts_st.tv_sec - 1; + ts->tv_nsec += 1000000000 + ts_ed.tv_nsec - ts_st.tv_nsec; + } else { + ts->tv_sec += ts_ed.tv_sec - ts_st.tv_sec; + ts->tv_nsec += ts_ed.tv_nsec - ts_st.tv_nsec; + } + + if (ts->tv_nsec > 1000000000) { + ts->tv_nsec = ts->tv_nsec - 1000000000; + ts->tv_sec += 1; + } + + return; +} + +#define MAX_FILES_CREATE 10 +#define MAXPATHNAME 512 +void +test_h_performance (void) +{ + char *my_dir = "perftest", + *full_dir_path="/testdir/perftest"; + char *my_file = "file_", my_file_name[MAXPATHNAME]; + struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL; + struct stat sb, retsb; + int ret, valid, i; + struct glfs_fd *fd; + struct timespec c_ts = {0, 0}, c_ts_st, c_ts_ed; + struct timespec o_ts = {0, 0}, o_ts_st, o_ts_ed; + + printf("glfs_h_performance tests: In Progress\n"); + + /* Prepare tests */ + parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror (errno)); + printf ("glfs_h_performance tests: FAILED\n"); + goto out; + } + + dir = glfs_h_mkdir (fs, parent, my_dir, 0644, &sb); + if (dir == NULL) { + fprintf (stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, parent, strerror (errno)); + printf ("glfs_h_performance tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + /* create performance */ + ret = clock_gettime (CLOCK_REALTIME, &o_ts_st); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + for (i = 0; i < MAX_FILES_CREATE; i++) { + sprintf (my_file_name, "%s%d", my_file, i); + + ret = clock_gettime (CLOCK_REALTIME, &c_ts_st); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", + strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + leaf = glfs_h_lookupat (fs, dir, my_file_name, &sb); + if (leaf != NULL) { + fprintf (stderr, "glfs_h_lookup: exists %s\n", + my_file_name); + printf ("glfs_h_performance tests: FAILED\n"); + goto out; + } + + leaf = glfs_h_creat (fs, dir, my_file_name, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dir, strerror (errno)); + printf ("glfs_h_performance tests: FAILED\n"); + goto out; + } + + ret = clock_gettime (CLOCK_REALTIME, &c_ts_ed); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", + strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + assimilatetime (&c_ts, c_ts_st, c_ts_ed); + glfs_h_close (leaf); leaf = NULL; + } + + ret = clock_gettime (CLOCK_REALTIME, &o_ts_ed); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + assimilatetime (&o_ts, o_ts_st, o_ts_ed); + + printf ("Creation performance (handle based):\n\t# empty files:%d\n", + MAX_FILES_CREATE); + printf ("\tOverall time:\n\t\tSecs:%d\n\t\tnSecs:%d\n", + o_ts.tv_sec, o_ts.tv_nsec); + printf ("\tcreate call time time:\n\t\tSecs:%d\n\t\tnSecs:%d\n", + c_ts.tv_sec, c_ts.tv_nsec); + + /* create using path */ + c_ts.tv_sec = o_ts.tv_sec = 0; + c_ts.tv_nsec = o_ts.tv_nsec = 0; + + sprintf (my_file_name, "%s1", full_dir_path); + ret = glfs_mkdir (fs, my_file_name, 0644); + if (ret != 0) { + fprintf (stderr, "glfs_mkdir: error creating %s: from (%p),%s\n", + my_dir, parent, strerror (errno)); + printf ("glfs_h_performance tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + ret = clock_gettime (CLOCK_REALTIME, &o_ts_st); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + for (i = 0; i < MAX_FILES_CREATE; i++) { + sprintf (my_file_name, "%s1/%sn%d", full_dir_path, my_file, i); + + ret = clock_gettime (CLOCK_REALTIME, &c_ts_st); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", + strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + ret = glfs_stat (fs, my_file_name, &sb); + if (ret == 0) { + fprintf (stderr, "glfs_stat: exists %s\n", + my_file_name); + printf ("glfs_h_performance tests: FAILED\n"); + goto out; + } + + fd = glfs_creat (fs, my_file_name, O_CREAT, 0644); + if (fd == NULL) { + fprintf (stderr, "glfs_creat: error creating %s: from (%p),%s\n", + my_file, dir, strerror (errno)); + printf ("glfs_h_performance tests: FAILED\n"); + goto out; + } + + ret = clock_gettime (CLOCK_REALTIME, &c_ts_ed); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", + strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + assimilatetime (&c_ts, c_ts_st, c_ts_ed); + glfs_close (fd); + } + + ret = clock_gettime (CLOCK_REALTIME, &o_ts_ed); + if(ret != 0) { + fprintf (stderr, "clock_gettime: error %s\n", strerror (errno)); + printf ("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + assimilatetime (&o_ts, o_ts_st, o_ts_ed); + + printf ("Creation performance (path based):\n\t# empty files:%d\n", + MAX_FILES_CREATE); + printf ("\tOverall time:\n\t\tSecs:%d\n\t\tnSecs:%d\n", + o_ts.tv_sec, o_ts.tv_nsec); + printf ("\tcreate call time time:\n\t\tSecs:%d\n\t\tnSecs:%d\n", + c_ts.tv_sec, c_ts.tv_nsec); +out: + return; +} + +int +test_handleops (int argc, char *argv[]) +{ + int ret = 0; + glfs_fd_t *fd = NULL; + struct stat sb = {0, }; + struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL, + *tmp = NULL; + char readbuf[32], writebuf[32]; + unsigned char leaf_handle[GFAPI_HANDLE_LENGTH]; + + char *full_leaf_name = "/testdir/testfile.txt", + *leaf_name = "testfile.txt", + *relative_leaf_name = "testdir/testfile.txt"; + char *leaf_name1 = "testfile1.txt"; + char *full_newparent_name = "/testdir/dir1", + *newparent_name = "dir1"; + char *full_newnod_name = "/testdir/nod1", + *newnod_name = "nod1"; + + /* Initialize test area */ + ret = glfs_mkdir (fs, full_parent_name, 0644); + if (ret != 0 && errno != EEXIST) { + fprintf (stderr, "%s: (%p) %s\n", full_parent_name, fd, + strerror (errno)); + printf ("Test initialization failed on volume %s\n", argv[1]); + goto out; + } + else if (ret != 0) { + printf ("Found test directory %s to be existing\n", + full_parent_name); + printf ("Cleanup test directory and restart tests\n"); + goto out; + } + + fd = glfs_creat (fs, full_leaf_name, O_CREAT, 0644); + if (fd == NULL) { + fprintf (stderr, "%s: (%p) %s\n", full_leaf_name, fd, + strerror (errno)); + printf ("Test initialization failed on volume %s\n", argv[1]); + goto out; + } + glfs_close (fd); + + printf ("Initialized the test area, within volume %s\n", argv[1]); + + /* Handle based APIs test area */ + + /* glfs_lookupat test */ + printf ("glfs_h_lookupat tests: In Progress\n"); + /* start at root of the volume */ + root = glfs_h_lookupat (fs, NULL, "/", &sb); + if (root == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + "/", NULL, strerror (errno)); + printf ("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + /* lookup a parent within root */ + parent = glfs_h_lookupat (fs, root, parent_name, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + parent_name, root, strerror (errno)); + printf ("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + /* lookup a leaf/child within the parent */ + leaf = glfs_h_lookupat (fs, parent, leaf_name, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + leaf_name, parent, strerror (errno)); + printf ("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + /* reset */ + glfs_h_close (root); root = NULL; + glfs_h_close (leaf); leaf = NULL; + glfs_h_close (parent); parent = NULL; + + /* check absolute paths */ + root = glfs_h_lookupat (fs, NULL, "/", &sb); + if (root == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + "/", NULL, strerror (errno)); + printf ("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, root, strerror (errno)); + printf ("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + leaf = glfs_h_lookupat (fs, NULL, full_leaf_name, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_leaf_name, parent, strerror (errno)); + printf ("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + /* reset */ + glfs_h_close (leaf); leaf = NULL; + + /* check multiple component paths */ + leaf = glfs_h_lookupat (fs, root, relative_leaf_name, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + relative_leaf_name, parent, strerror (errno)); + goto out; + } + peek_stat (&sb); + + /* reset */ + glfs_h_close (root); root = NULL; + glfs_h_close (parent); parent = NULL; + + /* check symlinks in path */ + + /* TODO: -ve test cases */ + /* parent invalid + * path invalid + * path does not exist after some components + * no parent, but relative path + * parent and full path? -ve? + */ + + printf ("glfs_h_lookupat tests: PASSED\n"); + + /* glfs_openat test */ + printf ("glfs_h_open tests: In Progress\n"); + fd = glfs_h_open (fs, leaf, O_RDWR); + if (fd == NULL) { + fprintf (stderr, "glfs_h_open: error on open of %s: %s\n", + full_leaf_name, strerror (errno)); + printf ("glfs_h_open tests: FAILED\n"); + goto out; + } + + /* test read/write based on fd */ + memcpy (writebuf, "abcdefghijklmnopqrstuvwxyz012345", 32); + ret = glfs_write (fd, writebuf, 32, 0); + + glfs_lseek (fd, 0, SEEK_SET); + + ret = glfs_read (fd, readbuf, 32, 0); + if (memcmp (readbuf, writebuf, 32)) { + printf ("Failed to read what I wrote: %s %s\n", readbuf, + writebuf); + glfs_close (fd); + printf ("glfs_h_open tests: FAILED\n"); + goto out; + } + + glfs_h_close (leaf); leaf = NULL; + glfs_close (fd); + + printf ("glfs_h_open tests: PASSED\n"); + + /* Create tests */ + printf ("glfs_h_creat tests: In Progress\n"); + parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, root, strerror (errno)); + printf ("glfs_h_creat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + leaf = glfs_h_creat (fs, parent, leaf_name1, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_creat: error on create of %s: from (%p),%s\n", + leaf_name1, parent, strerror (errno)); + printf ("glfs_h_creat tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + glfs_h_close (leaf); leaf = NULL; + + leaf = glfs_h_creat (fs, parent, leaf_name1, O_CREAT | O_EXCL, 0644, + &sb); + if (leaf != NULL || errno != EEXIST) { + fprintf (stderr, "glfs_h_creat: existing file, leaf = (%p), errno = %s\n", + leaf, strerror (errno)); + printf ("glfs_h_creat tests: FAILED\n"); + if (leaf != NULL) { + glfs_h_close (leaf); leaf = NULL; + } + } + + tmp = glfs_h_creat (fs, root, parent_name, O_CREAT, 0644, &sb); + if (tmp != NULL || !(errno == EISDIR || errno == EINVAL)) { + fprintf (stderr, "glfs_h_creat: dir create, tmp = (%p), errno = %s\n", + leaf, strerror (errno)); + printf ("glfs_h_creat tests: FAILED\n"); + if (tmp != NULL) { + glfs_h_close (tmp); tmp = NULL; + } + } + + /* TODO: Other combinations and -ve cases as applicable */ + printf ("glfs_h_creat tests: PASSED\n"); + + /* extract handle and create from handle test */ + printf ("glfs_h_extract_handle and glfs_h_create_from_handle tests: In Progress\n"); + /* TODO: Change the lookup to creat below for a GIFD recovery falure, + * that needs to be fixed */ + leaf = glfs_h_lookupat (fs, parent, leaf_name1, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + leaf_name1, parent, strerror (errno)); + printf ("glfs_h_extract_handle tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + ret = glfs_h_extract_handle (leaf, leaf_handle, + GFAPI_HANDLE_LENGTH); + if (ret < 0) { + fprintf (stderr, "glfs_h_extract_handle: error extracting handle of %s: %s\n", + full_leaf_name, strerror (errno)); + printf ("glfs_h_extract_handle tests: FAILED\n"); + goto out; + } + peek_handle (leaf_handle); + + glfs_h_close (leaf); leaf = NULL; + + leaf = glfs_h_create_from_handle (fs, leaf_handle, GFAPI_HANDLE_LENGTH, + &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_create_from_handle: error on create of %s: from (%p),%s\n", + leaf_name1, leaf_handle, strerror (errno)); + printf ("glfs_h_create_from_handle tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + fd = glfs_h_open (fs, leaf, O_RDWR); + if (fd == NULL) { + fprintf (stderr, "glfs_h_open: error on open of %s: %s\n", + full_leaf_name, strerror (errno)); + printf ("glfs_h_create_from_handle tests: FAILED\n"); + goto out; + } + + /* test read/write based on fd */ + memcpy (writebuf, "abcdefghijklmnopqrstuvwxyz012345", 32); + ret = glfs_write (fd, writebuf, 32, 0); + + glfs_lseek (fd, 0, SEEK_SET); + + ret = glfs_read (fd, readbuf, 32, 0); + if (memcmp (readbuf, writebuf, 32)) { + printf ("Failed to read what I wrote: %s %s\n", writebuf, + writebuf); + printf ("glfs_h_create_from_handle tests: FAILED\n"); + glfs_close (fd); + goto out; + } + + glfs_close (fd); + glfs_h_close (leaf); leaf = NULL; + glfs_h_close (parent); parent = NULL; + + printf ("glfs_h_extract_handle and glfs_h_create_from_handle tests: PASSED\n"); + + /* Mkdir tests */ + printf ("glfs_h_mkdir tests: In Progress\n"); + + ret = glfs_rmdir (fs, full_newparent_name); + if (ret && errno != ENOENT) { + fprintf (stderr, "glfs_rmdir: Failed for %s: %s\n", + full_newparent_name, strerror (errno)); + printf ("glfs_h_mkdir tests: FAILED\n"); + goto out; + } + + parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, root, strerror (errno)); + printf ("glfs_h_mkdir tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + leaf = glfs_h_mkdir (fs, parent, newparent_name, 0644, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_mkdir: error on mkdir of %s: from (%p),%s\n", + newparent_name, parent, strerror (errno)); + printf ("glfs_h_mkdir tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + glfs_h_close (leaf); leaf = NULL; + + leaf = glfs_h_mkdir (fs, parent, newparent_name, 0644, &sb); + if (leaf != NULL || errno != EEXIST) { + fprintf (stderr, "glfs_h_mkdir: existing directory, leaf = (%p), errno = %s\n", + leaf, strerror (errno)); + printf ("glfs_h_mkdir tests: FAILED\n"); + if (leaf != NULL) { + glfs_h_close (leaf); leaf = NULL; + } + } + + glfs_h_close (parent); parent = NULL; + + printf ("glfs_h_mkdir tests: PASSED\n"); + + /* Mknod tests */ + printf ("glfs_h_mknod tests: In Progress\n"); + ret = glfs_unlink (fs, full_newnod_name); + if (ret && errno != ENOENT) { + fprintf (stderr, "glfs_unlink: Failed for %s: %s\n", + full_newnod_name, strerror (errno)); + printf ("glfs_h_mknod tests: FAILED\n"); + goto out; + } + + parent = glfs_h_lookupat (fs, NULL, full_parent_name, &sb); + if (parent == NULL) { + fprintf (stderr, "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, root, strerror (errno)); + printf ("glfs_h_mknod tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + leaf = glfs_h_mknod (fs, parent, newnod_name, S_IFIFO, 0, &sb); + if (leaf == NULL) { + fprintf (stderr, "glfs_h_mkdir: error on mkdir of %s: from (%p),%s\n", + newnod_name, parent, strerror (errno)); + printf ("glfs_h_mknod tests: FAILED\n"); + goto out; + } + peek_stat (&sb); + + /* TODO: creat op on a FIFO node hangs, need to check and fix + tmp = glfs_h_creat (fs, parent, newnod_name, O_CREAT, 0644, &sb); + if (tmp != NULL || errno != EINVAL) { + fprintf (stderr, "glfs_h_creat: node create, tmp = (%p), errno = %s\n", + tmp, strerror (errno)); + printf ("glfs_h_creat/mknod tests: FAILED\n"); + if (tmp != NULL) { + glfs_h_close(tmp); tmp = NULL; + } + } */ + + glfs_h_close (leaf); leaf = NULL; + + leaf = glfs_h_mknod (fs, parent, newnod_name, 0644, 0, &sb); + if (leaf != NULL || errno != EEXIST) { + fprintf (stderr, "glfs_h_mknod: existing node, leaf = (%p), errno = %s\n", + leaf, strerror (errno)); + printf ("glfs_h_mknod tests: FAILED\n"); + if (leaf != NULL) { + glfs_h_close (leaf); leaf = NULL; + } + } + + glfs_h_close (parent); parent = NULL; + + printf ("glfs_h_mknod tests: PASSED\n"); + + /* unlink tests */ + test_h_unlink (); + + /* TODO: opendir tests */ + + /* getattr tests */ + test_h_getsetattrs (); + + /* TODO: setattr tests */ + + /* truncate tests */ + test_h_truncate(); + + /* link tests */ + test_h_links (); + + /* rename tests */ + test_h_rename (); + + /* performance tests */ + test_h_performance (); + + /* END: New APIs test area */ + +out: + /* Cleanup glfs handles */ + if (root) + glfs_h_close (root); + if (parent) + glfs_h_close (parent); + if (leaf) + glfs_h_close (leaf); + + return ret; +} int main (int argc, char *argv[]) { - glfs_t *fs = NULL; glfs_t *fs2 = NULL; int ret = 0; glfs_fd_t *fd = NULL; @@ -148,7 +1496,12 @@ main (int argc, char *argv[]) char *filename = "/filename2"; - fs = glfs_new ("fsync"); + if (argc != 3) { + printf ("Expect following args\n\t%s \n", argv[0]); + return -1; + } + + fs = glfs_new (argv[1]); if (!fs) { fprintf (stderr, "glfs_new: returned NULL\n"); return 1; @@ -156,7 +1509,7 @@ main (int argc, char *argv[]) // ret = glfs_set_volfile (fs, "/tmp/posix.vol"); - ret = glfs_set_volfile_server (fs, "tcp", "localhost", 24007); + ret = glfs_set_volfile_server (fs, "tcp", argv[2], 24007); // ret = glfs_set_volfile_server (fs, "unix", "/tmp/gluster.sock", 0); @@ -168,7 +1521,7 @@ main (int argc, char *argv[]) sleep (2); - fs2 = glfs_new ("fsync"); + fs2 = glfs_new (argv[1]); if (!fs2) { fprintf (stderr, "glfs_new: returned NULL\n"); return 1; @@ -177,7 +1530,7 @@ main (int argc, char *argv[]) // ret = glfs_set_volfile (fs2, "/tmp/posix.vol"); - ret = glfs_set_volfile_server (fs2, "tcp", "localhost", 24007); + ret = glfs_set_volfile_server (fs2, "tcp", argv[2], 24007); ret = glfs_set_logging (fs2, "/dev/stderr", 7); @@ -238,6 +1591,7 @@ main (int argc, char *argv[]) test_chdir (fs); + test_handleops (argc, argv); // done glfs_fini (fs); diff --git a/api/src/Makefile.am b/api/src/Makefile.am index 0782435e0..7c5df3e20 100644 --- a/api/src/Makefile.am +++ b/api/src/Makefile.am @@ -1,9 +1,10 @@ lib_LTLIBRARIES = libgfapi.la noinst_HEADERS = glfs-mem-types.h glfs-internal.h -libgfapi_HEADERS = glfs.h +libgfapi_HEADERS = glfs.h glfs-handles.h libgfapidir = $(includedir)/glusterfs/api -libgfapi_la_SOURCES = glfs.c glfs-mgmt.c glfs-fops.c glfs-resolve.c +libgfapi_la_SOURCES = glfs.c glfs-mgmt.c glfs-fops.c glfs-resolve.c \ + glfs-handleops.c libgfapi_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \ $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la \ $(top_builddir)/rpc/xdr/src/libgfxdr.la \ diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c index 3fd3cef2a..bda7e9e46 100644 --- a/api/src/glfs-fops.c +++ b/api/src/glfs-fops.c @@ -14,20 +14,8 @@ #include "syncop.h" #include "glfs.h" -#define DEFAULT_REVAL_COUNT 1 -#define ESTALE_RETRY(ret,errno,reval,loc,label) do { \ - if (ret == -1 && errno == ESTALE) { \ - if (reval < DEFAULT_REVAL_COUNT) { \ - reval++; \ - loc_wipe (loc); \ - goto label; \ - } \ - } \ - } while (0) - - -static int +int glfs_loc_link (loc_t *loc, struct iatt *iatt) { int ret = -1; @@ -52,7 +40,7 @@ glfs_loc_link (loc_t *loc, struct iatt *iatt) } -static void +void glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat) { iatt_to_stat (iatt, stat); @@ -60,7 +48,7 @@ glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat) } -static int +int glfs_loc_unlink (loc_t *loc) { inode_unlink (loc->inode, loc->parent, loc->name); diff --git a/api/src/glfs-handleops.c b/api/src/glfs-handleops.c new file mode 100644 index 000000000..9c707a619 --- /dev/null +++ b/api/src/glfs-handleops.c @@ -0,0 +1,1278 @@ +/* + * Copyright (c) 2013 Red Hat, Inc. + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + + +#include "glfs-internal.h" +#include "glfs-mem-types.h" +#include "syncop.h" +#include "glfs.h" +#include "glfs-handles.h" + +static void +glfs_iatt_from_stat (struct stat *stat, int valid, struct iatt *iatt, + int *glvalid) +{ + /* validate in args */ + if ((stat == NULL) || (iatt == NULL) || (glvalid == NULL)) { + errno = EINVAL; + return; + } + + *glvalid = 0; + + if (valid & GFAPI_SET_ATTR_MODE) { + iatt->ia_prot = ia_prot_from_st_mode (stat->st_mode); + *glvalid |= GF_SET_ATTR_MODE; + } + + if (valid & GFAPI_SET_ATTR_UID) { + iatt->ia_uid = stat->st_uid; + *glvalid |= GF_SET_ATTR_UID; + } + + if (valid & GFAPI_SET_ATTR_GID) { + iatt->ia_gid = stat->st_gid; + *glvalid |= GF_SET_ATTR_GID; + } + + if (valid & GFAPI_SET_ATTR_ATIME) { + iatt->ia_atime = stat->st_atime; + iatt->ia_atime_nsec = ST_ATIM_NSEC (stat); + *glvalid |= GF_SET_ATTR_ATIME; + } + + if (valid & GFAPI_SET_ATTR_MTIME) { + iatt->ia_mtime = stat->st_mtime; + iatt->ia_mtime_nsec = ST_MTIM_NSEC (stat); + *glvalid |= GF_SET_ATTR_MTIME; + } + + return; +} + +struct glfs_object * +glfs_h_lookupat (struct glfs *fs, struct glfs_object *parent, + const char *path, struct stat *stat) +{ + int ret = 0; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + struct iatt iatt = {0, }; + struct glfs_object *object = NULL; + loc_t loc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (path == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + if (parent) { + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + goto out; + } + } + + /* fop/op */ + ret = glfs_resolve_at (fs, subvol, inode, path, &loc, &iatt, + 0 /*TODO: links? */, 0); + + /* populate out args */ + if (!ret) { + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return object; +} + +int +glfs_h_stat (struct glfs *fs, struct glfs_object *object, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + /* populate loc */ + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_stat (subvol, &loc, &iatt); + + /* populate out args */ + if (!ret && stat) { + glfs_iatt_to_stat (fs, &iatt, stat); + } +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +int +glfs_h_getattrs (struct glfs *fs, struct glfs_object *object, struct stat *stat) +{ + int ret = 0; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + struct iatt iatt = {0, }; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + /* fop/op */ + ret = glfs_resolve_base (fs, subvol, inode, &iatt); + + /* populate out args */ + if (!ret && stat) { + glfs_iatt_to_stat (fs, &iatt, stat); + } + +out: + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +int +glfs_h_setattrs (struct glfs *fs, struct glfs_object *object, struct stat *stat, + int valid) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + int glvalid = 0; + + /* validate in args */ + if ((fs == NULL) || (object == NULL) || (stat == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + /* map valid masks from in args */ + glfs_iatt_from_stat (stat, valid, &iatt, &glvalid); + + /* populate loc */ + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_setattr (subvol, &loc, &iatt, glvalid, 0, 0); +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +struct glfs_fd * +glfs_h_open (struct glfs *fs, struct glfs_object *object, int flags) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + /* check types to open */ + if (IA_ISDIR (inode->ia_type)) { + ret = -1; + errno = EISDIR; + goto out; + } + + if (!IA_ISREG (inode->ia_type)) { + ret = -1; + errno = EINVAL; + goto out; + } + + glfd = glfs_fd_new (fs); + if (!glfd) { + errno = ENOMEM; + goto out; + } + + glfd->fd = fd_create (inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + /* populate loc */ + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_open (subvol, &loc, flags, glfd->fd); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + if (ret && glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } else { + glfd->fd->flags = flags; + fd_bind (glfd->fd); + glfs_fd_bind (glfd); + } + + glfs_subvol_done (fs, subvol); + + return glfd; +} + +struct glfs_object * +glfs_h_creat (struct glfs *fs, struct glfs_object *parent, const char *path, + int flags, mode_t mode, struct stat *stat) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (path == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + goto out; + } + + xattr_req = dict_new (); + if (!xattr_req) { + ret = -1; + errno = ENOMEM; + goto out; + } + + uuid_generate (gfid); + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + ret = -1; + errno = ENOMEM; + goto out; + } + + GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path); + + glfd = glfs_fd_new (fs); + if (!glfd) + goto out; + + glfd->fd = fd_create (loc.inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + /* fop/op */ + ret = syncop_create (subvol, &loc, flags, mode, glfd->fd, + xattr_req, &iatt); + + /* populate out args */ + if (ret == 0) { + /* TODO: If the inode existed in the cache (say file already + exists), then the glfs_loc_link will not update the + loc.inode, as a result we will have a 0000 GFID that we + would copy out to the object, this needs to be fixed. + */ + ret = glfs_loc_link (&loc, &iatt); + if (ret != 0) { + goto out; + } + + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } + +out: + if (ret && object != NULL) { + glfs_h_close (object); + object = NULL; + } + + loc_wipe(&loc); + + if (inode) + inode_unref (inode); + + if (xattr_req) + dict_unref (xattr_req); + + if (glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } + + glfs_subvol_done (fs, subvol); + + return object; +} + +struct glfs_object * +glfs_h_mkdir (struct glfs *fs, struct glfs_object *parent, const char *path, + mode_t mode, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (path == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + goto out; + } + + xattr_req = dict_new (); + if (!xattr_req) { + ret = -1; + errno = ENOMEM; + goto out; + } + + uuid_generate (gfid); + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + ret = -1; + errno = ENOMEM; + goto out; + } + + GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path); + + /* fop/op */ + ret = syncop_mkdir (subvol, &loc, mode, xattr_req, &iatt); + + /* populate out args */ + if ( ret == 0 ) { + ret = glfs_loc_link (&loc, &iatt); + if (ret != 0) { + goto out; + } + + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } + +out: + if (ret && object != NULL) { + glfs_h_close (object); + object = NULL; + } + + loc_wipe(&loc); + + if (inode) + inode_unref (inode); + + if (xattr_req) + dict_unref (xattr_req); + + glfs_subvol_done (fs, subvol); + + return object; +} + +struct glfs_object * +glfs_h_mknod (struct glfs *fs, struct glfs_object *parent, const char *path, + mode_t mode, dev_t dev, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (path == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + goto out; + } + + xattr_req = dict_new (); + if (!xattr_req) { + ret = -1; + errno = ENOMEM; + goto out; + } + + uuid_generate (gfid); + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + ret = -1; + errno = ENOMEM; + goto out; + } + + GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, path); + + /* fop/op */ + ret = syncop_mknod (subvol, &loc, mode, dev, xattr_req, &iatt); + + /* populate out args */ + if (ret == 0) { + ret = glfs_loc_link (&loc, &iatt); + if (ret != 0) { + goto out; + } + + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } +out: + if (ret && object != NULL) { + glfs_h_close (object); + object = NULL; + } + + loc_wipe(&loc); + + if (inode) + inode_unref (inode); + + if (xattr_req) + dict_unref (xattr_req); + + glfs_subvol_done (fs, subvol); + + return object; +} + +int +glfs_h_unlink (struct glfs *fs, struct glfs_object *parent, const char *path) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (path == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if ( !subvol ) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + goto out; + } + + ret = glfs_resolve_at (fs, subvol, inode, path, &loc, NULL, 0 , 0); + if (ret != 0) { + goto out; + } + + if (!IA_ISDIR(loc.inode->ia_type)) { + ret = syncop_unlink (subvol, &loc); + if (ret != 0) { + goto out; + } + } else { + ret = syncop_rmdir (subvol, &loc); + if (ret != 0) { + goto out; + } + } + + if (ret == 0) + ret = glfs_loc_unlink (&loc); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +struct glfs_fd * +glfs_h_opendir (struct glfs *fs, struct glfs_object *object) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + if (!IA_ISDIR (inode->ia_type)) { + ret = -1; + errno = ENOTDIR; + goto out; + } + + glfd = glfs_fd_new (fs); + if (!glfd) + goto out; + + INIT_LIST_HEAD (&glfd->entries); + + glfd->fd = fd_create (inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_opendir (subvol, &loc, glfd->fd); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + if (ret && glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } else { + fd_bind (glfd->fd); + glfs_fd_bind (glfd); + } + + glfs_subvol_done (fs, subvol); + + return glfd; +} + +ssize_t +glfs_h_extract_handle (struct glfs_object *object, unsigned char *handle, + int len) +{ + ssize_t ret = -1; + + /* validate in args */ + if (object == NULL) { + errno = EINVAL; + goto out; + } + + if (!handle || !len) { + ret = GFAPI_HANDLE_LENGTH; + goto out; + } + + if (len < GFAPI_HANDLE_LENGTH) + { + errno = ERANGE; + goto out; + } + + memcpy (handle, object->gfid, GFAPI_HANDLE_LENGTH); + + ret = GFAPI_HANDLE_LENGTH; + +out: + return ret; +} + +struct glfs_object * +glfs_h_create_from_handle (struct glfs *fs, unsigned char *handle, int len, + struct stat *stat) +{ + loc_t loc = {0, }; + int ret = -1; + struct iatt iatt = {0, }; + inode_t *newinode = NULL; + xlator_t *subvol = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (handle == NULL) || (len != GFAPI_HANDLE_LENGTH)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + errno = EIO; + goto out; + } + + memcpy (loc.gfid, handle, GFAPI_HANDLE_LENGTH); + + newinode = inode_find (subvol->itable, loc.gfid); + if (newinode) + loc.inode = newinode; + else { + loc.inode = inode_new (subvol->itable); + if (!loc.inode) { + errno = ENOMEM; + goto out; + } + } + + ret = syncop_lookup (subvol, &loc, 0, &iatt, 0, 0); + if (ret) { + gf_log (subvol->name, GF_LOG_WARNING, + "inode refresh of %s failed: %s", + uuid_utoa (loc.gfid), strerror (errno)); + goto out; + } + + newinode = inode_link (loc.inode, 0, 0, &iatt); + if (newinode) + inode_lookup (newinode); + else { + gf_log (subvol->name, GF_LOG_WARNING, + "inode linking of %s failed: %s", + uuid_utoa (loc.gfid), strerror (errno)); + errno = EINVAL; + goto out; + } + + /* populate stat */ + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + object = GF_CALLOC (1, sizeof(struct glfs_object), + glfs_mt_glfs_object_t); + if (object == NULL) { + errno = ENOMEM; + ret = -1; + goto out; + } + + /* populate the return object */ + object->inode = newinode; + uuid_copy (object->gfid, object->inode->gfid); + +out: + /* TODO: Check where the inode ref is being held? */ + loc_wipe (&loc); + + glfs_subvol_done (fs, subvol); + + return object; +} + +int +glfs_h_close (struct glfs_object *object) +{ + /* Release the held reference */ + inode_unref (object->inode); + GF_FREE (object); + + return 0; +} + +int +glfs_h_truncate (struct glfs *fs, struct glfs_object *object, off_t offset) +{ + loc_t loc = {0, }; + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + + /* validate in args */ + if ((fs == NULL) || (object == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_truncate (subvol, &loc, (off_t)offset); + + /* populate out args */ + if (ret == 0) + ret = glfs_loc_unlink (&loc); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +struct glfs_object * +glfs_h_symlink (struct glfs *fs, struct glfs_object *parent, const char *name, + const char *data, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + struct glfs_object *object = NULL; + + /* validate in args */ + if ((fs == NULL) || (parent == NULL) || (name == NULL) || + (data == NULL)) { + errno = EINVAL; + return NULL; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, parent); + if (!inode) { + errno = ESTALE; + goto out; + } + + xattr_req = dict_new (); + if (!xattr_req) { + ret = -1; + errno = ENOMEM; + goto out; + } + + uuid_generate (gfid); + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + ret = -1; + errno = ENOMEM; + goto out; + } + + GLFS_LOC_FILL_PINODE (inode, loc, ret, errno, out, name); + + /* fop/op */ + ret = syncop_symlink (subvol, &loc, data, xattr_req, &iatt); + + /* populate out args */ + if (ret == 0) { + /* TODO: If the inode existed in the cache (say file already + * exists), then the glfs_loc_link will not update the + * loc.inode, as a result we will have a 0000 GFID that we + * would copy out to the object, this needs to be fixed. + */ + ret = glfs_loc_link (&loc, &iatt); + if (ret != 0) { + goto out; + } + + if (stat) + glfs_iatt_to_stat (fs, &iatt, stat); + + ret = glfs_create_object (&loc, &object); + } + +out: + if (ret && object != NULL) { + glfs_h_close (object); + object = NULL; + } + + loc_wipe(&loc); + + if (inode) + inode_unref (inode); + + if (xattr_req) + dict_unref (xattr_req); + + glfs_subvol_done (fs, subvol); + + return object; +} + +int +glfs_h_readlink (struct glfs *fs, struct glfs_object *object, char *buf, + size_t bufsiz) +{ + loc_t loc = {0, }; + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + char *linkval = NULL; + + /* validate in args */ + if ((fs == NULL) || (object == NULL) || (buf == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, object); + if (!inode) { + errno = ESTALE; + goto out; + } + + GLFS_LOC_FILL_INODE (inode, loc, out); + + /* fop/op */ + ret = syncop_readlink (subvol, &loc, &linkval, bufsiz); + + /* populate out args */ + if (ret > 0) + memcpy (buf, linkval, ret); + +out: + loc_wipe (&loc); + + if (inode) + inode_unref (inode); + + if (linkval) + GF_FREE (linkval); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +int +glfs_h_link (struct glfs *fs, struct glfs_object *linksrc, + struct glfs_object *parent, const char *name) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *inode = NULL; + inode_t *pinode = NULL; + loc_t oldloc = {0, }; + loc_t newloc = {0, }; + + /* validate in args */ + if ((fs == NULL) || (linksrc == NULL) || (parent == NULL) || + (name == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + inode = glfs_resolve_inode (fs, subvol, linksrc); + if (!inode) { + errno = ESTALE; + goto out; + } + + if (inode->ia_type == IA_IFDIR) { + ret = -1; + errno = EISDIR; + goto out; + } + + GLFS_LOC_FILL_INODE (inode, oldloc, out); + + /* get/refresh the in arg objects inode in correlation to the xlator */ + pinode = glfs_resolve_inode (fs, subvol, parent); + if (!pinode) { + errno = ESTALE; + goto out; + } + + /* setup newloc based on parent */ + newloc.parent = inode_ref (pinode); + newloc.name = name; + ret = glfs_loc_touchup (&newloc); + if (ret != 0) { + errno = EINVAL; + goto out; + } + + /* Filling the inode of the hard link to be same as that of the + * original file + */ + newloc.inode = inode_ref (inode); + + /* fop/op */ + ret = syncop_link (subvol, &oldloc, &newloc); + + if (ret == 0) + /* TODO: No iatt to pass as there has been no lookup */ + ret = glfs_loc_link (&newloc, NULL); +out: + loc_wipe (&oldloc); + loc_wipe (&newloc); + + if (inode) + inode_unref (inode); + + if (pinode) + inode_unref (pinode); + + glfs_subvol_done (fs, subvol); + + return ret; +} + +int +glfs_h_rename (struct glfs *fs, struct glfs_object *olddir, const char *oldname, + struct glfs_object *newdir, const char *newname) +{ + int ret = -1; + xlator_t *subvol = NULL; + inode_t *oldpinode = NULL; + inode_t *newpinode = NULL; + loc_t oldloc = {0, }; + loc_t newloc = {0, }; + struct iatt oldiatt = {0, }; + struct iatt newiatt = {0, }; + + /* validate in args */ + if ((fs == NULL) || (olddir == NULL) || (oldname == NULL) || + (newdir == NULL) || (newname == NULL)) { + errno = EINVAL; + return -1; + } + + __glfs_entry_fs (fs); + + /* get the active volume */ + subvol = glfs_active_subvol (fs); + if ( !subvol ) { + ret = -1; + errno = EIO; + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + oldpinode = glfs_resolve_inode (fs, subvol, olddir); + if (!oldpinode) { + errno = ESTALE; + goto out; + } + + ret = glfs_resolve_at (fs, subvol, oldpinode, oldname, &oldloc, + &oldiatt, 0 , 0); + if (ret != 0) { + goto out; + } + + /* get/refresh the in arg objects inode in correlation to the xlator */ + newpinode = glfs_resolve_inode (fs, subvol, newdir); + if (!newpinode) { + errno = ESTALE; + goto out; + } + + ret = glfs_resolve_at (fs, subvol, newpinode, newname, &newloc, + &newiatt, 0, 0); + + if (ret && errno != ENOENT && newloc.parent) + goto out; + + if (newiatt.ia_type != IA_INVAL) { + if ((oldiatt.ia_type == IA_IFDIR) != + (newiatt.ia_type == IA_IFDIR)) { + /* Either both old and new must be dirs, + * or both must be non-dirs. Else, fail. + */ + ret = -1; + errno = EISDIR; + goto out; + } + } + + /* TODO: check if new or old is a prefix of the other, and fail EINVAL */ + + ret = syncop_rename (subvol, &oldloc, &newloc); + + if (ret == 0) + inode_rename (oldloc.parent->table, oldloc.parent, oldloc.name, + newloc.parent, newloc.name, oldloc.inode, + &oldiatt); + +out: + loc_wipe (&oldloc); + loc_wipe (&newloc); + + if (oldpinode) + inode_unref (oldpinode); + + if (newpinode) + inode_unref (newpinode); + + glfs_subvol_done (fs, subvol); + + return ret; +} diff --git a/api/src/glfs-handles.h b/api/src/glfs-handles.h new file mode 100644 index 000000000..437f2cbc8 --- /dev/null +++ b/api/src/glfs-handles.h @@ -0,0 +1,143 @@ +/* + Copyright (c) 2013 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _GLFS_HANDLES_H +#define _GLFS_HANDLES_H + +#include "glfs.h" + +/* GLFS OBJECT BASED OPERATIONS + * + * The following APIs are introduced to provide an API framework that can work + * with gluster objects (files and directories), instead of absolute paths. + * + * The following API set can be related to the POSIX *at interfaces (like + * openat (2)). The intention of these APIs is to be able to operate based + * on parent object and looking up or creating child objects within, OR to be + * used on the actual object thus looked up or created, and retrieve information + * regarding the same. + * + * The APIs also provide for generating an opaque invariant handle to the + * object, that can later be used to lookup the object, instead of the regular + * glfs_h_* variants. The APIs that provide this behaviour are, + * glfs_h_extract_handle and glfs_h_create_from_handle. + * + * The object handles can be transitioned to fd based operations as supported + * by glfs.h calls, using the glfs_h_open call. This provides a way to move + * from objects to fd's akin to moving from path to fd for required operations. + * + * NOTE: The opaque invariant handle is the GFID of the object in reality, but + * maintained as an opaque data value, for potential internal changes to the + * same without impacting the caller. + * + * NOTE: Currently looking up an object can create multiple object handles to + * the same, i.e distinct glfs_object *. Hence each such looked up or received + * handle from other calls, would need to be closed. In the future, for a given + * object these pointers would be the same, and an ease of use API to forget all + * instances of this bject would be provided (instead of a per lookup close). + * This should not change the APIs in their current form. + * + */ + +/* Values for valid falgs to be used when using XXXsetattr, to set multiple + attribute values passed via the related stat structure. + */ +#define GFAPI_SET_ATTR_MODE 0x1 +#define GFAPI_SET_ATTR_UID 0x2 +#define GFAPI_SET_ATTR_GID 0x4 +#define GFAPI_SET_ATTR_SIZE 0x8 +#define GFAPI_SET_ATTR_ATIME 0x10 +#define GFAPI_SET_ATTR_MTIME 0x20 + +/* Handle length for object handles returned from glfs_h_extract_handle or + * glfs_h_create_from_handle */ +#define GFAPI_HANDLE_LENGTH 16 + +__BEGIN_DECLS + +/* + * Notes: + * + * The file object handle. One per looked up, created file/directory + * + * This had been introduced to facilitate gfid/inode based gfapi + * - a requirement introduced by nfs-ganesha + */ +struct glfs_object; +typedef struct glfs_object glfs_object_t; + +/* Handle based operations */ +/* Operations that generate handles */ +struct glfs_object *glfs_h_lookupat (struct glfs *fs, + struct glfs_object *parent, + const char *path, struct stat *stat); + +struct glfs_object *glfs_h_creat (struct glfs *fs, struct glfs_object *parent, + const char *path, int flags, mode_t mode, + struct stat *sb); + +struct glfs_object *glfs_h_mkdir (struct glfs *fs, struct glfs_object *parent, + const char *path, mode_t flags, + struct stat *sb); + +struct glfs_object *glfs_h_mknod (struct glfs *fs, struct glfs_object *parent, + const char *path, mode_t mode, dev_t dev, + struct stat *sb); + +struct glfs_object *glfs_h_symlink (struct glfs *fs, struct glfs_object *parent, + const char *name, const char *data, + struct stat *stat); + +/* Operations on the actual objects */ +int glfs_h_unlink (struct glfs *fs, struct glfs_object *parent, + const char *path); + +int glfs_h_close (struct glfs_object *object); + +int glfs_caller_specific_init (void *uid_caller_key, void *gid_caller_key, + void *future); + +int glfs_h_truncate (struct glfs *fs, struct glfs_object *object, off_t offset); + +int glfs_h_stat(struct glfs *fs, struct glfs_object *object, struct stat *stat); + +int glfs_h_getattrs (struct glfs *fs, struct glfs_object *object, + struct stat *stat); + +int glfs_h_setattrs (struct glfs *fs, struct glfs_object *object, + struct stat *sb, int valid); + +int glfs_h_readlink (struct glfs *fs, struct glfs_object *object, char *buf, + size_t bufsiz); + +int glfs_h_link (struct glfs *fs, struct glfs_object *linktgt, + struct glfs_object *parent, const char *name); + +int glfs_h_rename (struct glfs *fs, struct glfs_object *olddir, + const char *oldname, struct glfs_object *newdir, + const char *newname); + +/* Operations enabling opaque invariant handle to object transitions */ +ssize_t glfs_h_extract_handle (struct glfs_object *object, + unsigned char *handle, int len); + +struct glfs_object *glfs_h_create_from_handle (struct glfs *fs, + unsigned char *handle, int len, + struct stat *stat); + +/* Operations enabling object handles to fd transitions */ +struct glfs_fd *glfs_h_opendir (struct glfs *fs, struct glfs_object *object); + +struct glfs_fd *glfs_h_open (struct glfs *fs, struct glfs_object *object, + int flags); + +__END_DECLS + +#endif /* !_GLFS_HANDLES_H */ \ No newline at end of file diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index c7fdf75f5..1b1c1c7f6 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -16,6 +16,44 @@ #define GLFS_SYMLINK_MAX_FOLLOW 2048 +#define DEFAULT_REVAL_COUNT 1 + +#define ESTALE_RETRY(ret,errno,reval,loc,label) do { \ + if (ret == -1 && errno == ESTALE) { \ + if (reval < DEFAULT_REVAL_COUNT) { \ + reval++; \ + loc_wipe (loc); \ + goto label; \ + } \ + } \ + } while (0) + +#define GLFS_LOC_FILL_INODE(oinode, loc, label) do { \ + loc.inode = inode_ref (oinode); \ + uuid_copy (loc.gfid, oinode->gfid); \ + ret = glfs_loc_touchup (&loc); \ + if (ret != 0) { \ + errno = EINVAL; \ + goto label; \ + } \ + } while (0) + +#define GLFS_LOC_FILL_PINODE(pinode, loc, ret, errno, label, path) do { \ + loc.inode = inode_new (pinode->table); \ + if (!loc.inode) { \ + ret = -1; \ + errno = ENOMEM; \ + goto label; \ + } \ + loc.parent = inode_ref (pinode); \ + loc.name = path; \ + ret = glfs_loc_touchup (&loc); \ + if (ret != 0) { \ + errno = EINVAL; \ + goto label; \ + } \ + } while (0) + struct glfs; typedef int (*glfs_init_cbk) (struct glfs *fs, int ret); @@ -59,6 +97,14 @@ struct glfs_fd { gf_dirent_t *next; }; +/* glfs object handle introduced for the alternate gfapi implementation based + on glfs handles/gfid/inode +*/ +struct glfs_object { + inode_t *inode; + uuid_t gfid; +}; + #define DEFAULT_EVENT_POOL_SIZE 16384 #define GF_MEMPOOL_COUNT_OF_DICT_T 4096 #define GF_MEMPOOL_COUNT_OF_DATA_T (GF_MEMPOOL_COUNT_OF_DICT_T * 4) @@ -135,6 +181,19 @@ inode_t * glfs_refresh_inode (xlator_t *subvol, inode_t *inode); inode_t *glfs_cwd_get (struct glfs *fs); int glfs_cwd_set (struct glfs *fs, inode_t *inode); +inode_t *glfs_resolve_inode (struct glfs *fs, xlator_t *subvol, + struct glfs_object *object); +int glfs_create_object (loc_t *loc, struct glfs_object **retobject); int __glfs_cwd_set (struct glfs *fs, inode_t *inode); +int glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode, + struct iatt *iatt); +int glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at, + const char *origpath, loc_t *loc, struct iatt *iatt, + int follow, int reval); +int glfs_loc_touchup (loc_t *loc); +void glfs_iatt_to_stat (struct glfs *fs, struct iatt *iatt, struct stat *stat); +int glfs_loc_link (loc_t *loc, struct iatt *iatt); +int glfs_loc_unlink (loc_t *loc); + #endif /* !_GLFS_INTERNAL_H */ diff --git a/api/src/glfs-mem-types.h b/api/src/glfs-mem-types.h index 590acd03f..ae4791511 100644 --- a/api/src/glfs-mem-types.h +++ b/api/src/glfs-mem-types.h @@ -23,7 +23,8 @@ enum glfs_mem_types_ { glfs_mt_glfs_io_t, glfs_mt_volfile_t, glfs_mt_xlator_cmdline_option_t, - glfs_mt_end + glfs_mt_glfs_object_t, + glfs_mt_end }; #endif diff --git a/api/src/glfs-resolve.c b/api/src/glfs-resolve.c index 9d64883d7..4ca2eb6fc 100644 --- a/api/src/glfs-resolve.c +++ b/api/src/glfs-resolve.c @@ -193,7 +193,7 @@ out: } -void +int glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode, struct iatt *iatt) { @@ -212,6 +212,8 @@ glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode, ret = syncop_lookup (subvol, &loc, NULL, iatt, NULL, NULL); out: loc_wipe (&loc); + + return ret; } @@ -359,7 +361,8 @@ glfs_resolve_at (struct glfs *fs, xlator_t *subvol, inode_t *at, component, as the caller wants proper iatt filled */ - (reval || !next_component)); + (reval || (!next_component && + iatt))); if (!inode) break; @@ -904,3 +907,63 @@ glfs_cwd_get (struct glfs *fs) return cwd; } + +inode_t * +__glfs_resolve_inode (struct glfs *fs, xlator_t *subvol, + struct glfs_object *object) +{ + inode_t *inode = NULL; + + if (object->inode->table->xl == subvol) + return inode_ref (object->inode); + + inode = __glfs_refresh_inode (fs, fs->active_subvol, + object->inode); + if (!inode) + return NULL; + + if (subvol == fs->active_subvol) { + inode_unref (object->inode); + object->inode = inode_ref (inode); + } + + return inode; +} + +inode_t * +glfs_resolve_inode (struct glfs *fs, xlator_t *subvol, + struct glfs_object *object) +{ + inode_t *inode = NULL; + + glfs_lock (fs); + { + inode = __glfs_resolve_inode(fs, subvol, object); + } + glfs_unlock (fs); + + return inode; +} + +int +glfs_create_object (loc_t *loc, struct glfs_object **retobject) +{ + struct glfs_object *object = NULL; + + object = GF_CALLOC (1, sizeof(struct glfs_object), + glfs_mt_glfs_object_t); + if (object == NULL) { + errno = ENOMEM; + return -1; + } + + object->inode = loc->inode; + uuid_copy (object->gfid, object->inode->gfid); + + /* we hold the reference */ + loc->inode = NULL; + + *retobject = object; + + return 0; +} diff --git a/api/src/glfs.c b/api/src/glfs.c index da090abae..e1f6bbcda 100644 --- a/api/src/glfs.c +++ b/api/src/glfs.c @@ -317,6 +317,20 @@ enomem: return -1; } +int glfs_setfsuid (uid_t fsuid) +{ + return syncopctx_setfsuid (&fsuid); +} + +int glfs_setfsgid (gid_t fsgid) +{ + return syncopctx_setfsgid (&fsgid); +} + +int glfs_setfsgroups (size_t size, const gid_t *list) +{ + return syncopctx_setfsgroups(size, list); +} struct glfs * glfs_from_glfd (struct glfs_fd *glfd) diff --git a/api/src/glfs.h b/api/src/glfs.h index 460edf1d0..bf34ec6bf 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -269,6 +269,32 @@ int glfs_fini (glfs_t *fs); struct glfs_fd; typedef struct glfs_fd glfs_fd_t; +/* + * PER THREAD IDENTITY MODIFIERS + * + * The following operations enable to set a per thread identity context + * for the glfs APIs to perform operations as. The calls here are kept as close + * to POSIX equivalents as possible. + * + * NOTES: + * + * - setgroups is a per thread setting, hence this is named as fsgroups to be + * close in naming to the fs(u/g)id APIs + * - Typical mode of operation is to set the IDs as required, with the + * supplementary groups being optionally set, make the glfs call and post the + * glfs operation set them back to eu/gid or uid/gid as appropriate to the + * caller + * - The groups once set, need to be unset by setting the size to 0 (in which + * case the list argument is a do not care) + * - Once a process for a thread of operation choses to set the IDs, all glfs + * calls made from that thread would default to the IDs set for the thread. + * As a result use these APIs with care and ensure that the set IDs are + * reverted to global process defaults as required. + * + */ +int glfs_setfsuid (uid_t fsuid); +int glfs_setfsgid (gid_t fsgid); +int glfs_setfsgroups (size_t size, const gid_t *list); /* SYNOPSIS diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c index 05ff52c2c..8009fb00c 100644 --- a/libglusterfs/src/globals.c +++ b/libglusterfs/src/globals.c @@ -19,6 +19,7 @@ #include "globals.h" #include "xlator.h" #include "mem-pool.h" +#include "syncop.h" const char *gf_fop_list[GF_FOP_MAXVALUE] = { [GF_FOP_NULL] = "NULL", @@ -164,6 +165,54 @@ glusterfs_this_set (xlator_t *this) return 0; } +/* SYNCOPCTX */ +static pthread_key_t syncopctx_key; + +static void +syncopctx_key_destroy (void *ptr) +{ + struct syncopctx *opctx = ptr; + + if (opctx) { + if (opctx->groups) + GF_FREE (opctx->groups); + + GF_FREE (opctx); + } + + return; +} + +void * +syncopctx_getctx () +{ + void *opctx = NULL; + + opctx = pthread_getspecific (syncopctx_key); + + return opctx; +} + +int +syncopctx_setctx (void *ctx) +{ + int ret = 0; + + ret = pthread_setspecific (syncopctx_key, ctx); + + return ret; +} + +static int +syncopctx_init (void) +{ + int ret; + + ret = pthread_key_create (&syncopctx_key, syncopctx_key_destroy); + + return ret; +} + /* SYNCTASK */ int @@ -176,7 +225,6 @@ synctask_init () return ret; } - void * synctask_get () { @@ -300,6 +348,13 @@ glusterfs_globals_init (glusterfs_ctx_t *ctx) "ERROR: glusterfs synctask init failed"); goto out; } + + ret = syncopctx_init (); + if (ret) { + gf_log ("", GF_LOG_CRITICAL, + "ERROR: glusterfs syncopctx init failed"); + goto out; + } out: return ret; } diff --git a/libglusterfs/src/globals.h b/libglusterfs/src/globals.h index 709121b51..cf52e8e59 100644 --- a/libglusterfs/src/globals.h +++ b/libglusterfs/src/globals.h @@ -40,6 +40,10 @@ xlator_t **__glusterfs_this_location (); xlator_t *glusterfs_this_get (); int glusterfs_this_set (xlator_t *); +/* syncopctx */ +void *syncopctx_getctx (); +int syncopctx_setctx (void *ctx); + /* task */ void *synctask_get (); int synctask_set (void *); diff --git a/libglusterfs/src/mem-types.h b/libglusterfs/src/mem-types.h index 7d9186a41..c1164f96a 100644 --- a/libglusterfs/src/mem-types.h +++ b/libglusterfs/src/mem-types.h @@ -110,6 +110,7 @@ enum gf_common_mem_types_ { gf_common_mt_iov_base_t = 94, gf_common_mt_groups_t = 95, gf_common_mt_auxgids = 96, - gf_common_mt_end = 97 + gf_common_mt_syncopctx = 97, + gf_common_mt_end = 98 }; #endif diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c index ba8c84f26..6c2e8e48e 100644 --- a/libglusterfs/src/syncop.c +++ b/libglusterfs/src/syncop.c @@ -15,6 +15,160 @@ #include "syncop.h" +int +syncopctx_setfsuid (void *uid) +{ + struct syncopctx *opctx = NULL; + int ret = 0; + + /* In args check */ + if (!uid) { + ret = -1; + errno = EINVAL; + goto out; + } + + opctx = syncopctx_getctx (); + + /* alloc for this thread the first time */ + if (!opctx) { + opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx); + if (!opctx) { + ret = -1; + goto out; + } + + ret = syncopctx_setctx (opctx); + if (ret != 0) { + GF_FREE (opctx); + opctx = NULL; + goto out; + } + } + +out: + if (opctx && uid) { + opctx->uid = *(uid_t *)uid; + opctx->valid |= SYNCOPCTX_UID; + } + + return ret; +} + +int +syncopctx_setfsgid (void *gid) +{ + struct syncopctx *opctx = NULL; + int ret = 0; + + /* In args check */ + if (!gid) { + ret = -1; + errno = EINVAL; + goto out; + } + + opctx = syncopctx_getctx (); + + /* alloc for this thread the first time */ + if (!opctx) { + opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx); + if (!opctx) { + ret = -1; + goto out; + } + + ret = syncopctx_setctx (opctx); + if (ret != 0) { + GF_FREE (opctx); + opctx = NULL; + goto out; + } + } + +out: + if (opctx && gid) { + opctx->gid = *(gid_t *)gid; + opctx->valid |= SYNCOPCTX_GID; + } + + return ret; +} + +int +syncopctx_setfsgroups (int count, const void *groups) +{ + struct syncopctx *opctx = NULL; + gid_t *tmpgroups = NULL; + int ret = 0; + + /* In args check */ + if (count != 0 && !groups) { + ret = -1; + errno = EINVAL; + goto out; + } + + opctx = syncopctx_getctx (); + + /* alloc for this thread the first time */ + if (!opctx) { + opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx); + if (!opctx) { + ret = -1; + goto out; + } + + ret = syncopctx_setctx (opctx); + if (ret != 0) { + GF_FREE (opctx); + opctx = NULL; + goto out; + } + } + + /* resize internal groups as required */ + if (count && opctx->grpsize < count) { + if (opctx->groups) { + tmpgroups = GF_REALLOC (opctx->groups, + (sizeof (gid_t) * count)); + /* NOTE: Not really required to zero the reallocation, + * as ngrps controls the validity of data, + * making a note irrespective */ + if (tmpgroups == NULL) { + opctx->grpsize = 0; + GF_FREE (opctx->groups); + opctx->groups = NULL; + ret = -1; + goto out; + } + } + else { + tmpgroups = GF_CALLOC (count, sizeof (gid_t), + gf_common_mt_syncopctx); + if (tmpgroups == NULL) { + opctx->grpsize = 0; + ret = -1; + goto out; + } + } + + opctx->groups = tmpgroups; + opctx->grpsize = count; + } + + /* copy out the groups passed */ + if (count) + memcpy (opctx->groups, groups, (sizeof (gid_t) * count)); + + /* set/reset the ngrps, this is where reset of groups is handled */ + opctx->ngrps = count; + opctx->valid |= SYNCOPCTX_GROUPS; + +out: + return ret; +} + static void __run (struct synctask *task) { diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h index d0417b260..4e14dc353 100644 --- a/libglusterfs/src/syncop.h +++ b/libglusterfs/src/syncop.h @@ -25,6 +25,13 @@ #define SYNCENV_PROC_MIN 2 #define SYNCPROC_IDLE_TIME 600 +/* + * Flags for syncopctx valid elements + */ +#define SYNCOPCTX_UID 0x00000001 +#define SYNCOPCTX_GID 0x00000002 +#define SYNCOPCTX_GROUPS 0x00000004 + struct synctask; struct syncproc; struct syncenv; @@ -146,6 +153,14 @@ struct syncargs { int done; }; +struct syncopctx { + unsigned int valid; /* valid flags for elements that are set */ + uid_t uid; + gid_t gid; + int grpsize; + int ngrps; + gid_t *groups; +}; #define __yawn(args) do { \ args->task = synctask_get (); \ @@ -234,34 +249,63 @@ void synctask_waitfor (struct synctask *task, int count); int synctask_setid (struct synctask *task, uid_t uid, gid_t gid); #define SYNCTASK_SETID(uid, gid) synctask_setid (synctask_get(), uid, gid); +int syncopctx_setfsuid (void *uid); +int syncopctx_setfsgid (void *gid); +int syncopctx_setfsgroups (int count, const void *groups); static inline call_frame_t * syncop_create_frame (xlator_t *this) { - call_frame_t *frame = NULL; - int ngrps = -1; + call_frame_t *frame = NULL; + int ngrps = -1; + struct syncopctx *opctx = NULL; frame = create_frame (this, this->ctx->pool); if (!frame) return NULL; - frame->root->pid = getpid(); - frame->root->uid = geteuid (); - frame->root->gid = getegid (); - ngrps = getgroups (0, 0); - if (ngrps < 0) { - STACK_DESTROY (frame->root); - return NULL; - } + frame->root->pid = getpid (); - if (call_stack_alloc_groups (frame->root, ngrps) != 0) { - STACK_DESTROY (frame->root); - return NULL; - } + opctx = syncopctx_getctx (); + if (opctx && (opctx->valid & SYNCOPCTX_UID)) + frame->root->uid = opctx->uid; + else + frame->root->uid = geteuid (); - if (getgroups (ngrps, frame->root->groups) < 0) { - STACK_DESTROY (frame->root); - return NULL; + if (opctx && (opctx->valid & SYNCOPCTX_GID)) + frame->root->gid = opctx->gid; + else + frame->root->gid = getegid (); + + if (opctx && (opctx->valid & SYNCOPCTX_GROUPS)) { + ngrps = opctx->ngrps; + + if (ngrps != 0 && opctx->groups != NULL) { + if (call_stack_alloc_groups (frame->root, ngrps) != 0) { + STACK_DESTROY (frame->root); + return NULL; + } + + memcpy (frame->root->groups, opctx->groups, + (sizeof (gid_t) * ngrps)); + } + } + else { + ngrps = getgroups (0, 0); + if (ngrps < 0) { + STACK_DESTROY (frame->root); + return NULL; + } + + if (call_stack_alloc_groups (frame->root, ngrps) != 0) { + STACK_DESTROY (frame->root); + return NULL; + } + + if (getgroups (ngrps, frame->root->groups) < 0) { + STACK_DESTROY (frame->root); + return NULL; + } } return frame; -- cgit