diff options
| -rw-r--r-- | api/examples/glfsxmp.c | 1364 | ||||
| -rw-r--r-- | api/src/Makefile.am | 5 | ||||
| -rw-r--r-- | api/src/glfs-fops.c | 18 | ||||
| -rw-r--r-- | api/src/glfs-handleops.c | 1278 | ||||
| -rw-r--r-- | api/src/glfs-handles.h | 143 | ||||
| -rw-r--r-- | api/src/glfs-internal.h | 59 | ||||
| -rw-r--r-- | api/src/glfs-mem-types.h | 3 | ||||
| -rw-r--r-- | api/src/glfs-resolve.c | 67 | ||||
| -rw-r--r-- | api/src/glfs.c | 14 | ||||
| -rw-r--r-- | api/src/glfs.h | 26 | ||||
| -rw-r--r-- | libglusterfs/src/globals.c | 57 | ||||
| -rw-r--r-- | libglusterfs/src/globals.h | 4 | ||||
| -rw-r--r-- | libglusterfs/src/mem-types.h | 5 | ||||
| -rw-r--r-- | libglusterfs/src/syncop.c | 154 | ||||
| -rw-r--r-- | libglusterfs/src/syncop.h | 78 | 
15 files changed, 3230 insertions, 45 deletions
diff --git a/api/examples/glfsxmp.c b/api/examples/glfsxmp.c index 644793a4b1a..8231a3949f0 100644 --- a/api/examples/glfsxmp.c +++ b/api/examples/glfsxmp.c @@ -1,6 +1,8 @@  #include <stdio.h> +#include <stdlib.h>  #include <errno.h>  #include "api/glfs.h" +#include "api/glfs-handles.h"  #include <string.h>  #include <time.h> @@ -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 <volname> <hostname>\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 0782435e065..7c5df3e2029 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 8119cc4f693..9070661b99e 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 00000000000..9c707a619a5 --- /dev/null +++ b/api/src/glfs-handleops.c @@ -0,0 +1,1278 @@ +/* + *  Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> + *  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 00000000000..437f2cbc8a5 --- /dev/null +++ b/api/src/glfs-handles.h @@ -0,0 +1,143 @@ +/* +  Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> +  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 c7fdf75f541..1b1c1c7f624 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 590acd03f11..ae47915111d 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 3179af22c2d..98ef6a946f8 100644 --- a/api/src/glfs-resolve.c +++ b/api/src/glfs-resolve.c @@ -191,7 +191,7 @@ out:  } -void +int  glfs_resolve_base (struct glfs *fs, xlator_t *subvol, inode_t *inode,  		   struct iatt *iatt)  { @@ -210,6 +210,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;  } @@ -356,7 +358,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; @@ -900,3 +903,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 7b056b5167b..2f58b61852e 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 fd44c2fc885..c2fb26505d5 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -271,6 +271,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 459291b3309..1e4cbf0edeb 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 857965bb458..3085db21c1a 100644 --- a/libglusterfs/src/globals.h +++ b/libglusterfs/src/globals.h @@ -41,6 +41,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 3b0f7d27667..9aadbcaec2a 100644 --- a/libglusterfs/src/mem-types.h +++ b/libglusterfs/src/mem-types.h @@ -115,7 +115,8 @@ enum gf_common_mem_types_ {          gf_common_mt_client_ctx           = 99,          gf_common_mt_lock_table           = 100,          gf_common_mt_locker               = 101, -	gf_common_mt_auxgids              = 102, -        gf_common_mt_end                  = 103 +        gf_common_mt_auxgids              = 102, +        gf_common_mt_syncopctx            = 103, +        gf_common_mt_end                  = 104  };  #endif diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c index cd267cacc57..866dca50ea4 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 64350030e56..0fc9e14ba0f 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; @@ -150,6 +157,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 ();                           \ @@ -242,34 +257,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;  | 
