diff options
Diffstat (limited to 'xlators/nfs/server/src/nfs3-helpers.c')
| -rw-r--r-- | xlators/nfs/server/src/nfs3-helpers.c | 3881 |
1 files changed, 3881 insertions, 0 deletions
diff --git a/xlators/nfs/server/src/nfs3-helpers.c b/xlators/nfs/server/src/nfs3-helpers.c new file mode 100644 index 000000000..9059fc341 --- /dev/null +++ b/xlators/nfs/server/src/nfs3-helpers.c @@ -0,0 +1,3881 @@ +/* + Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.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 _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> + +#include "xlator.h" +#include "nfs3.h" +#include "nfs3-fh.h" +#include "msg-nfs3.h" +#include "rbthash.h" +#include "nfs-fops.h" +#include "nfs-inodes.h" +#include "nfs-generics.h" +#include "nfs3-helpers.h" +#include "nfs-mem-types.h" +#include "iatt.h" +#include "common-utils.h" +#include <string.h> + +extern int +nfs3_set_root_looked_up (struct nfs3_state *nfs3, struct nfs3_fh *rootfh); + +extern int +nfs3_is_root_looked_up (struct nfs3_state *nfs3, struct nfs3_fh *rootfh); + + +#define nfs3_call_resume(cst) \ + do { \ + if (((cst)) && (cst)->resume_fn) \ + (cst)->resume_fn (cst); \ + } while (0) \ + +#define nfs3_call_resume_estale(csta) \ + do { \ + (csta)->resolve_ret = -1; \ + (csta)->resolve_errno = ESTALE; \ + nfs3_call_resume (csta); \ + } while (0) \ + +struct nfs3stat_strerror { + nfsstat3 stat; + char strerror[100]; +}; + + +struct nfs3stat_strerror nfs3stat_strerror_table[] = { + { NFS3_OK, "Call completed successfully." }, + { NFS3ERR_PERM, "Not owner" }, + { NFS3ERR_NOENT, "No such file or directory" }, + { NFS3ERR_IO, "I/O error" }, + { NFS3ERR_NXIO, "I/O error" }, + { NFS3ERR_ACCES, "Permission denied" }, + { NFS3ERR_EXIST, "File exists" }, + { NFS3ERR_XDEV, "Attempt to do a cross-device hard link"}, + { NFS3ERR_NODEV, "No such device" }, + { NFS3ERR_NOTDIR, "Not a directory" }, + { NFS3ERR_ISDIR, "Is a directory" }, + { NFS3ERR_INVAL, "Invalid argument for operation" }, + { NFS3ERR_FBIG, "File too large" }, + { NFS3ERR_NOSPC, "No space left on device" }, + { NFS3ERR_ROFS, "Read-only file system" }, + { NFS3ERR_MLINK, "Too many hard links" }, + { NFS3ERR_NAMETOOLONG, "Filename in operation was too long" }, + { NFS3ERR_NOTEMPTY, "Directory not empty" }, + { NFS3ERR_DQUOT, "Resource (quota) hard limit exceeded" }, + { NFS3ERR_STALE, "Invalid file handle" }, + { NFS3ERR_REMOTE, "Too many levels of remote in path" }, + { NFS3ERR_BADHANDLE, "Illegal NFS file handle" }, + { NFS3ERR_NOT_SYNC, "Update synchronization mismatch detected" }, + { NFS3ERR_BAD_COOKIE, "READDIR or READDIRPLUS cookie is stale"}, + { NFS3ERR_NOTSUPP, "Operation is not supported" }, + { NFS3ERR_TOOSMALL, "Buffer or request is too small" }, + { NFS3ERR_SERVERFAULT, "Error occurred on the server or IO Error" }, + { NFS3ERR_BADTYPE, "Type not supported by the server" }, + { NFS3ERR_JUKEBOX, "Cannot complete server initiated request" }, + { -1, "IO Error" }, + +}; + + +uint64_t +nfs3_iatt_gfid_to_ino (struct iatt *buf) +{ + uint64_t ino = 0; + + if (!buf) + return 0; + + if (gf_nfs_enable_ino32()) { + ino = (uint32_t )nfs_hash_gfid (buf->ia_gfid); + goto hashout; + } + + /* from posix its guaranteed to send unique ino */ + ino = buf->ia_ino; + +hashout: + return ino; +} + + +void +nfs3_map_deviceid_to_statdev (struct iatt *ia, uint64_t deviceid) +{ + if (!ia) + return; + + ia->ia_dev = deviceid; +} + + +struct nfs3_fh +nfs3_extract_nfs3_fh (nfs_fh3 fh) +{ + struct nfs3_fh gfh; + + memcpy (&gfh, fh.data.data_val, fh.data.data_len); + return gfh; +} + + +struct nfs3_fh +nfs3_extract_lookup_fh (lookup3args *args) +{ + return nfs3_extract_nfs3_fh(args->what.dir); +} + + +char * +nfs3_extract_lookup_name (lookup3args *args) +{ + return args->what.name; +} + + +nfsstat3 +nfs3_errno_to_nfsstat3 (int errnum) +{ + nfsstat3 stat = NFS3_OK; + + switch (errnum) { + + case 0: + stat = NFS3_OK; + break; + + case EPERM: + stat = NFS3ERR_PERM; + break; + + case ENOENT: + stat = NFS3ERR_NOENT; + break; + + case EACCES: + stat = NFS3ERR_ACCES; + break; + + case EEXIST: + stat = NFS3ERR_EXIST; + break; + + case EXDEV: + stat = NFS3ERR_XDEV; + break; + + case ENODEV: + stat = NFS3ERR_NODEV; + break; + + case EIO: + stat = NFS3ERR_IO; + break; + + case ENXIO: + stat = NFS3ERR_NXIO; + break; + + case ENOTDIR: + stat = NFS3ERR_NOTDIR; + break; + + case EISDIR: + stat = NFS3ERR_ISDIR; + break; + + case EINVAL: + stat = NFS3ERR_INVAL; + break; + + case ENOSPC: + stat = NFS3ERR_NOSPC; + break; + + case EROFS: + stat = NFS3ERR_ROFS; + break; + + case EFBIG: + stat = NFS3ERR_FBIG; + break; + + case EMLINK: + stat = NFS3ERR_MLINK; + break; + + case ENAMETOOLONG: + stat = NFS3ERR_NAMETOOLONG; + break; + + case ENOTEMPTY: + stat = NFS3ERR_NOTEMPTY; + break; + + case EFAULT: + stat = NFS3ERR_SERVERFAULT; + break; + + case ENOSYS: + stat = NFS3ERR_NOTSUPP; + break; + + case EBADF: + stat = NFS3ERR_BADTYPE; + break; + + case ESTALE: + stat = NFS3ERR_STALE; + break; + + case ENOTCONN: + stat = NFS3ERR_IO; + break; + + case EDQUOT: + stat = NFS3ERR_DQUOT; + break; + + default: + stat = NFS3ERR_SERVERFAULT; + break; + } + + return stat; +} + +/* + * Special case: If op_ret is -1, it's very unusual op_errno being + * 0 which means something came wrong from upper layer(s). If it + * happens by any means, then set NFS3 status to NFS3ERR_SERVERFAULT. + */ +inline nfsstat3 +nfs3_cbk_errno_status (int32_t op_ret, int32_t op_errno) +{ + if ((op_ret == -1) && (op_errno == 0)) { + return NFS3ERR_SERVERFAULT; + } + + return nfs3_errno_to_nfsstat3 (op_errno); +} + +void +nfs3_fill_lookup3res_error (lookup3res *res, nfsstat3 stat, + struct iatt *dirstat) +{ + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (!dirstat) { + res->lookup3res_u.resfail.dir_attributes.attributes_follow = FALSE; + } + +} + +fattr3 +nfs3_stat_to_fattr3 (struct iatt *buf) +{ + fattr3 fa = {0, }; + + if (buf == NULL) + goto out; + + if (IA_ISDIR (buf->ia_type)) + fa.type = NF3DIR; + else if (IA_ISREG (buf->ia_type)) + fa.type = NF3REG; + else if (IA_ISCHR (buf->ia_type)) + fa.type = NF3CHR; + else if (IA_ISBLK (buf->ia_type)) + fa.type = NF3BLK; + else if (IA_ISFIFO (buf->ia_type)) + fa.type = NF3FIFO; + else if (IA_ISLNK (buf->ia_type)) + fa.type = NF3LNK; + else if (IA_ISSOCK (buf->ia_type)) + fa.type = NF3SOCK; + + if (IA_PROT_RUSR (buf->ia_prot)) + fa.mode |= NFS3MODE_ROWNER; + if (IA_PROT_WUSR (buf->ia_prot)) + fa.mode |= NFS3MODE_WOWNER; + if (IA_PROT_XUSR (buf->ia_prot)) + fa.mode |= NFS3MODE_XOWNER; + + if (IA_PROT_RGRP (buf->ia_prot)) + fa.mode |= NFS3MODE_RGROUP; + if (IA_PROT_WGRP (buf->ia_prot)) + fa.mode |= NFS3MODE_WGROUP; + if (IA_PROT_XGRP (buf->ia_prot)) + fa.mode |= NFS3MODE_XGROUP; + + if (IA_PROT_ROTH (buf->ia_prot)) + fa.mode |= NFS3MODE_ROTHER; + if (IA_PROT_WOTH (buf->ia_prot)) + fa.mode |= NFS3MODE_WOTHER; + if (IA_PROT_XOTH (buf->ia_prot)) + fa.mode |= NFS3MODE_XOTHER; + + if (IA_PROT_SUID (buf->ia_prot)) + fa.mode |= NFS3MODE_SETXUID; + if (IA_PROT_SGID (buf->ia_prot)) + fa.mode |= NFS3MODE_SETXGID; + if (IA_PROT_STCKY (buf->ia_prot)) + fa.mode |= NFS3MODE_SAVESWAPTXT; + + fa.nlink = buf->ia_nlink; + fa.uid = buf->ia_uid; + fa.gid = buf->ia_gid; + fa.size = buf->ia_size; + fa.used = (buf->ia_blocks * 512); + + if ((IA_ISCHR (buf->ia_type) || IA_ISBLK (buf->ia_type))) { + fa.rdev.specdata1 = ia_major (buf->ia_rdev); + fa.rdev.specdata2 = ia_minor (buf->ia_rdev); + } else { + fa.rdev.specdata1 = 0; + fa.rdev.specdata2 = 0; + } + + fa.fsid = buf->ia_dev; + fa.fileid = nfs3_iatt_gfid_to_ino (buf); + + fa.atime.seconds = buf->ia_atime; + fa.atime.nseconds = buf->ia_atime_nsec; + + fa.ctime.seconds = buf->ia_ctime; + fa.ctime.nseconds = buf->ia_ctime_nsec; + + fa.mtime.seconds = buf->ia_mtime; + fa.mtime.nseconds = buf->ia_mtime_nsec; + +out: + return fa; +} + + +post_op_attr +nfs3_stat_to_post_op_attr (struct iatt *buf) +{ + post_op_attr attr = {0, }; + if (!buf) + return attr; + + /* Some performance translators return zero-filled stats when they + * do not have up-to-date attributes. Need to handle this by not + * returning these zeroed out attrs. + */ + attr.attributes_follow = FALSE; + if (nfs_zero_filled_stat (buf)) + goto out; + + attr.post_op_attr_u.attributes = nfs3_stat_to_fattr3 (buf); + attr.attributes_follow = TRUE; + +out: + return attr; +} + + +pre_op_attr +nfs3_stat_to_pre_op_attr (struct iatt *pre) +{ + pre_op_attr poa = {0, }; + + /* Some performance translators return zero-filled stats when they + * do not have up-to-date attributes. Need to handle this by not + * returning these zeroed out attrs. + */ + poa.attributes_follow = FALSE; + if (nfs_zero_filled_stat (pre)) + goto out; + + poa.attributes_follow = TRUE; + poa.pre_op_attr_u.attributes.size = pre->ia_size; + poa.pre_op_attr_u.attributes.mtime.seconds = pre->ia_mtime; + poa.pre_op_attr_u.attributes.mtime.nseconds = pre->ia_mtime_nsec; + poa.pre_op_attr_u.attributes.ctime.seconds = pre->ia_ctime; + poa.pre_op_attr_u.attributes.ctime.nseconds = pre->ia_ctime_nsec; + +out: + return poa; +} + +void +nfs3_fill_lookup3res_success (lookup3res *res, nfsstat3 stat, + struct nfs3_fh *fh, struct iatt *buf, + struct iatt *postparent) +{ + post_op_attr obj, dir; + uint32_t fhlen = 0; + + res->status = stat; + if (fh) { + res->lookup3res_u.resok.object.data.data_val = (void *)fh; + fhlen = nfs3_fh_compute_size (fh); + res->lookup3res_u.resok.object.data.data_len = fhlen; + } + + obj.attributes_follow = FALSE; + dir.attributes_follow = FALSE; + obj = nfs3_stat_to_post_op_attr (buf); + dir = nfs3_stat_to_post_op_attr (postparent); + + res->lookup3res_u.resok.obj_attributes = obj; + res->lookup3res_u.resok.dir_attributes = dir; +} + + +void +nfs3_fill_lookup3res (lookup3res *res, nfsstat3 stat, struct nfs3_fh *newfh, + struct iatt *buf, struct iatt *postparent, + uint64_t deviceid) +{ + + memset (res, 0, sizeof (*res)); + nfs3_map_deviceid_to_statdev (buf, deviceid); + nfs3_map_deviceid_to_statdev (postparent, deviceid); + if (stat != NFS3_OK) + nfs3_fill_lookup3res_error (res, stat, postparent); + else + nfs3_fill_lookup3res_success (res, stat, newfh, buf, + postparent); +} + +struct nfs3_fh +nfs3_extract_getattr_fh (getattr3args *args) +{ + return nfs3_extract_nfs3_fh(args->object); +} + + +void +nfs3_fill_getattr3res (getattr3res *res, nfsstat3 stat, struct iatt *buf, + uint64_t deviceid) +{ + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (buf, deviceid); + res->getattr3res_u.resok.obj_attributes = nfs3_stat_to_fattr3 (buf); + +} + + +struct nfs3_fh +nfs3_extract_fsinfo_fh (fsinfo3args *args) +{ + return nfs3_extract_nfs3_fh (args->fsroot); +} + + +void +nfs3_fill_fsinfo3res (struct nfs3_state *nfs3, fsinfo3res *res, + nfsstat3 status, struct iatt *fsroot, uint64_t deviceid) +{ + fsinfo3resok resok = {{0}, }; + nfstime3 tdelta = GF_NFS3_TIMEDELTA_SECS; + + memset (res, 0, sizeof (*res)); + res->status = status; + if (status != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (fsroot, deviceid); + resok.obj_attributes = nfs3_stat_to_post_op_attr (fsroot); + resok.rtmax = nfs3->readsize; + resok.rtpref = nfs3->readsize; + resok.rtmult = GF_NFS3_RTMULT; + resok.wtmax = nfs3->writesize; + resok.wtpref = nfs3->writesize; + resok.wtmult = GF_NFS3_WTMULT; + resok.dtpref = nfs3->readdirsize; + resok.maxfilesize = GF_NFS3_MAXFILESIZE; + resok.time_delta = tdelta; + resok.properties = GF_NFS3_FS_PROP; + + res->fsinfo3res_u.resok = resok; + +} + + +void +nfs3_prep_lookup3args (lookup3args *args, struct nfs3_fh *fh, char *name) +{ + memset (args, 0, sizeof (*args)); + args->what.dir.data.data_val = (void *)fh; + args->what.name = name; +} + + +void +nfs3_prep_getattr3args (getattr3args *args, struct nfs3_fh *fh) +{ + memset (args, 0, sizeof (*args)); + args->object.data.data_val = (void *)fh; +} + + +void +nfs3_prep_fsinfo3args (fsinfo3args *args, struct nfs3_fh *root) +{ + memset (args, 0, sizeof (*args)); + args->fsroot.data.data_val = (void *)root; +} + + +char * +nfsstat3_strerror(int stat) +{ + int i; + for(i = 0; nfs3stat_strerror_table[i].stat != -1; i++) { + if (nfs3stat_strerror_table[i].stat == stat) + return nfs3stat_strerror_table[i].strerror; + } + + return nfs3stat_strerror_table[i].strerror; +} + + + +void +nfs3_prep_access3args (access3args *args, struct nfs3_fh *fh) +{ + memset (args, 0, sizeof (*args)); + args->object.data.data_val = (void *)fh; +} + +#define POSIX_READ 4 +#define POSIX_WRITE 2 +#define POSIX_EXEC 1 + +uint32_t +nfs3_accessbits (int32_t accbits) +{ + uint32_t accresult = 0; + + if (accbits & POSIX_READ) + accresult |= ACCESS3_READ; + + if (accbits & POSIX_WRITE) + accresult |= (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE); + + /* lookup on directory allowed only in case of execute permission */ + if (accbits & POSIX_EXEC) + accresult |= (ACCESS3_EXECUTE | ACCESS3_LOOKUP); + + return accresult; +} + +uint32_t +nfs3_request_to_accessbits (int32_t accbits) +{ + uint32_t acc_request = 0; + + if (accbits & ACCESS3_READ) + acc_request |= POSIX_READ; + + if (accbits & (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE)) + acc_request |= POSIX_WRITE; + + /* For lookup on directory check for execute permission */ + if (accbits & (ACCESS3_EXECUTE | ACCESS3_LOOKUP)) + acc_request |= POSIX_EXEC; + + return acc_request; +} +void +nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits, + int32_t reqaccbits) +{ + uint32_t accres = 0; + + memset (res, 0, sizeof (*res)); + res->status = status; + if (status != NFS3_OK) + return; + + accres = nfs3_accessbits (accbits); + + /* do not answer what was not asked */ + res->access3res_u.resok.access = accres & reqaccbits; +} + +void +nfs3_prep_readdir3args (readdir3args *ra, struct nfs3_fh *fh) +{ + memset (ra, 0, sizeof (*ra)); + ra->dir.data.data_val = (void *)fh; +} + + +int +nfs3_is_dot_entry (char *entry) +{ + int ret = 0; + + if (!entry) + return 0; + + if (strcmp (entry, ".") == 0) + ret = 1; + + return ret; +} + + +int +nfs3_is_parentdir_entry (char *entry) +{ + int ret = 0; + + if (!entry) + return 0; + + if (strcmp (entry, "..") == 0) + ret = 1; + + return ret; +} + + +void +nfs3_funge_root_dotdot_dirent (gf_dirent_t *ent, struct nfs3_fh *dfh) +{ + if ((!ent) || (!dfh)) + return; + + if (nfs3_fh_is_root_fh (dfh) && + nfs3_is_parentdir_entry (ent->d_name)) { + ent->d_ino = 1; + ent->d_stat.ia_ino = 1; + } + + if (nfs3_fh_is_root_fh (dfh) && + nfs3_is_dot_entry (ent->d_name)) { + ent->d_ino = 1; + ent->d_stat.ia_ino = 1; + } + +} + + +entry3 * +nfs3_fill_entry3 (gf_dirent_t *entry, struct nfs3_fh *dfh) +{ + entry3 *ent = NULL; + if ((!entry) || (!dfh)) + return NULL; + + ent = GF_CALLOC (1, sizeof (*ent), gf_nfs_mt_entry3); + if (!ent) + return NULL; + + gf_log (GF_NFS3, GF_LOG_TRACE, "Entry: %s", entry->d_name); + + /* If the entry is . or .., we need to replace the physical ino and gen + * with 1 and 0 respectively if the directory is root. This funging is + * needed because there is no parent directory of the root. In that + * sense the behavior we provide is similar to the output of the + * command: "stat /.." + */ + entry->d_ino = nfs3_iatt_gfid_to_ino (&entry->d_stat); + nfs3_funge_root_dotdot_dirent (entry, dfh); + ent->fileid = entry->d_ino; + ent->cookie = entry->d_off; + ent->name = GF_CALLOC ((strlen (entry->d_name) + 1), sizeof (char), + gf_nfs_mt_char); + if (!ent->name) { + GF_FREE (ent); + ent = NULL; + goto err; + } + strcpy (ent->name, entry->d_name); + +err: + return ent; +} + + +void +nfs3_fill_post_op_fh3 (struct nfs3_fh *fh, post_op_fh3 *pfh) +{ + uint32_t fhlen = 0; + + if ((!fh) || (!pfh)) + return; + + pfh->handle_follows = 1; + fhlen = nfs3_fh_compute_size (fh); + pfh->post_op_fh3_u.handle.data.data_val = (void *)fh; + pfh->post_op_fh3_u.handle.data.data_len = fhlen; +} + + +post_op_fh3 +nfs3_fh_to_post_op_fh3 (struct nfs3_fh *fh) +{ + post_op_fh3 pfh = {0, }; + char *fhp = NULL; + + if (!fh) + return pfh; + + pfh.handle_follows = 1; + + fhp = GF_CALLOC (1, sizeof (*fh), gf_nfs_mt_char); + if (!fhp) + return pfh; + + memcpy (fhp, fh, sizeof (*fh)); + nfs3_fill_post_op_fh3 ((struct nfs3_fh *)fhp, &pfh); + return pfh; +} + + +entryp3 * +nfs3_fill_entryp3 (gf_dirent_t *entry, struct nfs3_fh *dirfh, uint64_t devid) +{ + entryp3 *ent = NULL; + struct nfs3_fh newfh = {{0}, }; + + if ((!entry) || (!dirfh)) + return NULL; + + /* If the entry is . or .., we need to replace the physical ino and gen + * with 1 and 0 respectively if the directory is root. This funging is + * needed because there is no parent directory of the root. In that + * sense the behavior we provide is similar to the output of the + * command: "stat /.." + */ + entry->d_ino = nfs3_iatt_gfid_to_ino (&entry->d_stat); + nfs3_funge_root_dotdot_dirent (entry, dirfh); + gf_log (GF_NFS3, GF_LOG_TRACE, "Entry: %s, ino: %"PRIu64, + entry->d_name, entry->d_ino); + ent = GF_CALLOC (1, sizeof (*ent), gf_nfs_mt_entryp3); + if (!ent) + return NULL; + + ent->fileid = entry->d_ino; + ent->cookie = entry->d_off; + ent->name = GF_CALLOC ((strlen (entry->d_name) + 1), sizeof (char), + gf_nfs_mt_char); + if (!ent->name) { + GF_FREE (ent); + ent = NULL; + goto err; + } + strcpy (ent->name, entry->d_name); + + nfs3_fh_build_child_fh (dirfh, &entry->d_stat, &newfh); + nfs3_map_deviceid_to_statdev (&entry->d_stat, devid); + ent->name_attributes = nfs3_stat_to_post_op_attr (&entry->d_stat); + ent->name_handle = nfs3_fh_to_post_op_fh3 (&newfh); +err: + return ent; +} + + +void +nfs3_fill_readdir3res (readdir3res *res, nfsstat3 stat, struct nfs3_fh *dirfh, + uint64_t cverf, struct iatt *dirstat, + gf_dirent_t *entries, count3 count, int is_eof, + uint64_t deviceid) +{ + post_op_attr dirattr; + entry3 *ent = NULL; + entry3 *headentry = NULL; + entry3 *preventry = NULL; + count3 filled = 0; + gf_dirent_t *listhead = NULL; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (dirstat, deviceid); + dirattr = nfs3_stat_to_post_op_attr (dirstat); + res->readdir3res_u.resok.dir_attributes = dirattr; + res->readdir3res_u.resok.reply.eof = (bool_t)is_eof; + memcpy (res->readdir3res_u.resok.cookieverf, &cverf, sizeof (cverf)); + + filled = NFS3_READDIR_RESOK_SIZE; + /* First entry is just the list head */ + listhead = entries; + entries = entries->next; + while (((entries) && (entries != listhead)) && (filled < count)) { + /* + if ((strcmp (entries->d_name, ".") == 0) || + (strcmp (entries->d_name, "..") == 0)) + goto nextentry; + */ + ent = nfs3_fill_entry3 (entries, dirfh); + if (!ent) + break; + + if (!headentry) + headentry = ent; + + if (preventry) { + preventry->nextentry = ent; + preventry = ent; + } else + preventry = ent; + + filled += NFS3_ENTRY3_FIXED_SIZE + strlen (ent->name); +//nextentry: + entries = entries->next; + } + + res->readdir3res_u.resok.reply.entries = headentry; + + return; +} + + +void +nfs3_fill_readdirp3res (readdirp3res *res, nfsstat3 stat, + struct nfs3_fh *dirfh, uint64_t cverf, + struct iatt *dirstat, gf_dirent_t *entries, + count3 dircount, count3 maxcount, int is_eof, + uint64_t deviceid) +{ + post_op_attr dirattr; + entryp3 *ent = NULL; + entryp3 *headentry = NULL; + entryp3 *preventry = NULL; + count3 filled = 0; + gf_dirent_t *listhead = NULL; + int fhlen = 0; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (dirstat, deviceid); + dirattr = nfs3_stat_to_post_op_attr (dirstat); + res->readdirp3res_u.resok.dir_attributes = dirattr; + res->readdirp3res_u.resok.reply.eof = (bool_t)is_eof; + memcpy (res->readdirp3res_u.resok.cookieverf, &cverf, sizeof (cverf)); + + filled = NFS3_READDIR_RESOK_SIZE; + /* First entry is just the list head */ + listhead = entries; + entries = entries->next; + while (((entries) && (entries != listhead)) && (filled < maxcount)) { + /* Linux does not display . and .. entries unless we provide + * these entries here. + */ +/* if ((strcmp (entries->d_name, ".") == 0) || + (strcmp (entries->d_name, "..") == 0)) + goto nextentry; + */ + ent = nfs3_fill_entryp3 (entries, dirfh, deviceid); + if (!ent) + break; + + if (!headentry) + headentry = ent; + + if (preventry) { + preventry->nextentry = ent; + preventry = ent; + } else + preventry = ent; + + fhlen = ent->name_handle.post_op_fh3_u.handle.data.data_len; + filled += NFS3_ENTRYP3_FIXED_SIZE + fhlen + strlen (ent->name); +//nextentry: + entries = entries->next; + } + + res->readdirp3res_u.resok.reply.entries = headentry; + + return; +} + + +void +nfs3_prep_readdirp3args (readdirp3args *ra, struct nfs3_fh *fh) +{ + memset (ra, 0, sizeof (*ra)); + ra->dir.data.data_val = (void *)fh; +} + +void +nfs3_free_readdirp3res (readdirp3res *res) +{ + entryp3 *ent = NULL; + entryp3 *next = NULL; + + if (!res) + return; + + ent = res->readdirp3res_u.resok.reply.entries; + while (ent) { + + next = ent->nextentry; + GF_FREE (ent->name); + GF_FREE (ent->name_handle.post_op_fh3_u.handle.data.data_val); + GF_FREE (ent); + ent = next; + } + + return; +} + + +void +nfs3_free_readdir3res (readdir3res *res) +{ + entry3 *ent = NULL; + entry3 *next = NULL; + + if (!res) + return; + + ent = res->readdir3res_u.resok.reply.entries; + while (ent) { + + next = ent->nextentry; + GF_FREE (ent->name); + GF_FREE (ent); + ent = next; + } + + return; +} + +void +nfs3_prep_fsstat3args (fsstat3args *args, struct nfs3_fh *fh) +{ + memset (args, 0, sizeof (*args)); + args->fsroot.data.data_val = (char *)fh; +} + + +void +nfs3_fill_fsstat3res (fsstat3res *res, nfsstat3 stat, struct statvfs *fsbuf, + struct iatt *postbuf, uint64_t deviceid) +{ + post_op_attr poa; + fsstat3resok resok; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (postbuf, deviceid); + poa = nfs3_stat_to_post_op_attr (postbuf); + resok.tbytes = (size3)(fsbuf->f_frsize * fsbuf->f_blocks); + resok.fbytes = (size3)(fsbuf->f_frsize * fsbuf->f_bfree); + resok.abytes = (size3)(fsbuf->f_frsize * fsbuf->f_bavail); + resok.tfiles = (size3)(fsbuf->f_files); + resok.ffiles = (size3)(fsbuf->f_ffree); + resok.afiles = (size3)(fsbuf->f_favail); + resok.invarsec = 0; + + resok.obj_attributes = poa; + res->fsstat3res_u.resok = resok; +} + + +int32_t +nfs3_sattr3_to_setattr_valid (sattr3 *sattr, struct iatt *buf, mode_t *omode) +{ + int32_t valid = 0; + ia_prot_t prot = {0, }; + mode_t mode = 0; + + if (!sattr) + return 0; + + if (sattr->mode.set_it) { + valid |= GF_SET_ATTR_MODE; + + if (sattr->mode.set_mode3_u.mode & NFS3MODE_ROWNER) { + mode |= S_IRUSR; + prot.owner.read = 1; + } + if (sattr->mode.set_mode3_u.mode & NFS3MODE_WOWNER) { + mode |= S_IWUSR; + prot.owner.write = 1; + } + if (sattr->mode.set_mode3_u.mode & NFS3MODE_XOWNER) { + mode |= S_IXUSR; + prot.owner.exec = 1; + } + + if (sattr->mode.set_mode3_u.mode & NFS3MODE_RGROUP) { + mode |= S_IRGRP; + prot.group.read = 1; + } + if (sattr->mode.set_mode3_u.mode & NFS3MODE_WGROUP) { + mode |= S_IWGRP; + prot.group.write = 1; + } + if (sattr->mode.set_mode3_u.mode & NFS3MODE_XGROUP) { + mode |= S_IXGRP; + prot.group.exec = 1; + } + + if (sattr->mode.set_mode3_u.mode & NFS3MODE_ROTHER) { + mode |= S_IROTH; + prot.other.read = 1; + } + if (sattr->mode.set_mode3_u.mode & NFS3MODE_WOTHER) { + mode |= S_IWOTH; + prot.other.write = 1; + } + if (sattr->mode.set_mode3_u.mode & NFS3MODE_XOTHER) { + mode |= S_IXOTH; + prot.other.exec = 1; + } + + if (sattr->mode.set_mode3_u.mode & NFS3MODE_SETXUID) { + mode |= S_ISUID; + prot.suid = 1; + } + if (sattr->mode.set_mode3_u.mode & NFS3MODE_SETXGID) { + mode |= S_ISGID; + prot.sgid = 1; + } + if (sattr->mode.set_mode3_u.mode & NFS3MODE_SAVESWAPTXT) { + mode |= S_ISVTX; + prot.sticky = 1; + } + + if (buf) + buf->ia_prot = prot; + /* Create fop still requires the old mode_t style argument. */ + if (omode) + *omode = mode; + } + + if (sattr->uid.set_it) { + valid |= GF_SET_ATTR_UID; + if (buf) + buf->ia_uid = sattr->uid.set_uid3_u.uid; + } + + if (sattr->gid.set_it) { + valid |= GF_SET_ATTR_GID; + if (buf) + buf->ia_gid = sattr->gid.set_gid3_u.gid; + } + + if (sattr->size.set_it) { + valid |= GF_SET_ATTR_SIZE; + if (buf) + buf->ia_size = sattr->size.set_size3_u.size; + } + + if (sattr->atime.set_it == SET_TO_CLIENT_TIME) { + valid |= GF_SET_ATTR_ATIME; + if (buf) + buf->ia_atime = sattr->atime.set_atime_u.atime.seconds; + } + + if (sattr->atime.set_it == SET_TO_SERVER_TIME) { + valid |= GF_SET_ATTR_ATIME; + if (buf) + buf->ia_atime = time (NULL); + } + + if (sattr->mtime.set_it == SET_TO_CLIENT_TIME) { + valid |= GF_SET_ATTR_MTIME; + if (buf) + buf->ia_mtime = sattr->mtime.set_mtime_u.mtime.seconds; + } + + if (sattr->mtime.set_it == SET_TO_SERVER_TIME) { + valid |= GF_SET_ATTR_MTIME; + if (buf) + buf->ia_mtime = time (NULL); + } + + return valid; +} + + +wcc_data +nfs3_stat_to_wcc_data (struct iatt *pre, struct iatt *post) +{ + wcc_data wd = {{0}, }; + + if (post) + wd.after = nfs3_stat_to_post_op_attr (post); + if (pre) + wd.before = nfs3_stat_to_pre_op_attr (pre); + + return wd; +} + +void +nfs3_fill_create3res (create3res *res, nfsstat3 stat, struct nfs3_fh *newfh, + struct iatt *newbuf, struct iatt *preparent, + struct iatt *postparent, uint64_t deviceid) +{ + post_op_attr poa = {0, }; + wcc_data dirwcc = {{0}, }; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_fill_post_op_fh3 (newfh, &res->create3res_u.resok.obj); + nfs3_map_deviceid_to_statdev (newbuf, deviceid); + poa = nfs3_stat_to_post_op_attr (newbuf); + res->create3res_u.resok.obj_attributes = poa; + nfs3_map_deviceid_to_statdev (preparent, deviceid); + nfs3_map_deviceid_to_statdev (postparent, deviceid); + dirwcc = nfs3_stat_to_wcc_data (preparent, postparent); + + res->create3res_u.resok.dir_wcc = dirwcc; +} + +void +nfs3_prep_create3args (create3args *args, struct nfs3_fh *fh, char *name) +{ + + memset (args, 0, sizeof (*args)); + args->where.dir.data.data_val = (void *)fh; + args->where.name = name; +} + +void +nfs3_prep_setattr3args (setattr3args *args, struct nfs3_fh *fh) +{ + memset (args, 0, sizeof (*args)); + args->object.data.data_val = (void *)fh; +} + + +void +nfs3_fill_setattr3res (setattr3res *res, nfsstat3 stat, struct iatt *preop, + struct iatt *postop, uint64_t deviceid) +{ + wcc_data wcc; + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (preop, deviceid); + nfs3_map_deviceid_to_statdev (postop, deviceid); + wcc = nfs3_stat_to_wcc_data (preop, postop); + res->setattr3res_u.resok.obj_wcc = wcc; +} + + +void +nfs3_prep_mkdir3args (mkdir3args *args, struct nfs3_fh *dirfh, char *name) +{ + + memset (args, 0, sizeof (*args)); + args->where.dir.data.data_val = (void *)dirfh; + args->where.name = name; +} + + +void +nfs3_fill_mkdir3res (mkdir3res *res, nfsstat3 stat, struct nfs3_fh *fh, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, uint64_t deviceid) +{ + wcc_data dirwcc; + post_op_attr poa; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_fill_post_op_fh3 (fh, &res->mkdir3res_u.resok.obj); + nfs3_map_deviceid_to_statdev (buf, deviceid); + poa = nfs3_stat_to_post_op_attr (buf); + nfs3_map_deviceid_to_statdev (preparent, deviceid); + nfs3_map_deviceid_to_statdev (postparent, deviceid); + dirwcc = nfs3_stat_to_wcc_data (preparent, postparent); + res->mkdir3res_u.resok.obj_attributes = poa; + res->mkdir3res_u.resok.dir_wcc = dirwcc; + +} + + +void +nfs3_prep_symlink3args (symlink3args *args, struct nfs3_fh *dirfh, char *name, + char *target) +{ + memset (args, 0, sizeof (*args)); + args->where.dir.data.data_val = (void *)dirfh; + args->where.name = name; + args->symlink.symlink_data = target; +} + + +void +nfs3_fill_symlink3res (symlink3res *res, nfsstat3 stat, struct nfs3_fh *fh, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, uint64_t deviceid) +{ + wcc_data dirwcc; + post_op_attr poa; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_fill_post_op_fh3 (fh, &res->symlink3res_u.resok.obj); + nfs3_map_deviceid_to_statdev (buf, deviceid); + poa = nfs3_stat_to_post_op_attr (buf); + nfs3_map_deviceid_to_statdev (postparent, deviceid); + nfs3_map_deviceid_to_statdev (preparent, deviceid); + dirwcc = nfs3_stat_to_wcc_data (preparent, postparent); + res->symlink3res_u.resok.obj_attributes = poa; + res->symlink3res_u.resok.dir_wcc = dirwcc; + +} + + +void +nfs3_prep_readlink3args (readlink3args *args, struct nfs3_fh *fh) +{ + + memset (args, 0, sizeof (*args)); + args->symlink.data.data_val = (void *)fh; +} + + +void +nfs3_fill_readlink3res (readlink3res *res, nfsstat3 stat, char *path, + struct iatt *buf, uint64_t deviceid) +{ + post_op_attr poa; + + memset (res, 0, sizeof (*res)); + res->status = stat; + + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (buf, deviceid); + poa = nfs3_stat_to_post_op_attr (buf); + res->readlink3res_u.resok.data = (void *)path; + res->readlink3res_u.resok.symlink_attributes = poa; +} + + +void +nfs3_prep_mknod3args (mknod3args *args, struct nfs3_fh *fh, char *name) +{ + memset (args, 0, sizeof (*args)); + args->where.dir.data.data_val = (void *)fh; + args->where.name = name; + +} + +void +nfs3_fill_mknod3res (mknod3res *res, nfsstat3 stat, struct nfs3_fh *fh, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, uint64_t deviceid) +{ + post_op_attr poa; + wcc_data wccdir; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_fill_post_op_fh3 (fh, &res->mknod3res_u.resok.obj); + nfs3_map_deviceid_to_statdev (buf, deviceid); + poa = nfs3_stat_to_post_op_attr (buf); + nfs3_map_deviceid_to_statdev (preparent, deviceid); + nfs3_map_deviceid_to_statdev (postparent, deviceid); + wccdir = nfs3_stat_to_wcc_data (preparent, postparent); + res->mknod3res_u.resok.obj_attributes = poa; + res->mknod3res_u.resok.dir_wcc = wccdir; + +} + + +void +nfs3_fill_remove3res (remove3res *res, nfsstat3 stat, struct iatt *preparent, + struct iatt *postparent, uint64_t deviceid) +{ + wcc_data dirwcc; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (preparent, deviceid); + nfs3_map_deviceid_to_statdev (postparent, deviceid); + dirwcc = nfs3_stat_to_wcc_data (preparent, postparent); + res->remove3res_u.resok.dir_wcc = dirwcc; +} + + +void +nfs3_prep_remove3args (remove3args *args, struct nfs3_fh *fh, char *name) +{ + memset (args, 0, sizeof (*args)); + args->object.dir.data.data_val = (void *)fh; + args->object.name = name; +} + + +void +nfs3_prep_rmdir3args (rmdir3args *args, struct nfs3_fh *fh, char *name) +{ + memset (args, 0, sizeof (*args)); + args->object.dir.data.data_val = (void *)fh; + args->object.name = name; +} + + +void +nfs3_fill_rmdir3res (rmdir3res *res, nfsstat3 stat, struct iatt *preparent, + struct iatt *postparent, uint64_t deviceid) +{ + wcc_data dirwcc; + memset (res, 0, sizeof (*res)); + res->status = stat; + + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (postparent, deviceid); + nfs3_map_deviceid_to_statdev (preparent, deviceid); + dirwcc = nfs3_stat_to_wcc_data (preparent, postparent); + res->rmdir3res_u.resok.dir_wcc = dirwcc; +} + + +void +nfs3_prep_link3args (link3args *args, struct nfs3_fh *target, + struct nfs3_fh * dirfh, char *name) +{ + memset (args, 0, sizeof (*args)); + args->file.data.data_val = (void *)target; + args->link.dir.data.data_val = (void *)dirfh; + args->link.name = name; +} + + +void +nfs3_fill_link3res (link3res *res, nfsstat3 stat, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + uint64_t deviceid) +{ + post_op_attr poa; + wcc_data dirwcc; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (preparent, deviceid); + nfs3_map_deviceid_to_statdev (postparent, deviceid); + nfs3_map_deviceid_to_statdev (buf,deviceid); + poa = nfs3_stat_to_post_op_attr (buf); + dirwcc = nfs3_stat_to_wcc_data (preparent, postparent); + res->link3res_u.resok.file_attributes = poa; + res->link3res_u.resok.linkdir_wcc = dirwcc; +} + + + +void +nfs3_prep_rename3args (rename3args *args, struct nfs3_fh *olddirfh, + char *oldname, struct nfs3_fh *newdirfh, char *newname) +{ + memset (args, 0, sizeof (*args)); + + args->from.name = oldname; + args->from.dir.data.data_val = (void *)olddirfh; + args->to.name = newname; + args->to.dir.data.data_val = (void *)newdirfh; + +} + + +void +nfs3_fill_rename3res (rename3res *res, nfsstat3 stat, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + uint64_t deviceid) + +{ + wcc_data dirwcc; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (preoldparent, deviceid); + nfs3_map_deviceid_to_statdev (postoldparent, deviceid); + nfs3_map_deviceid_to_statdev (prenewparent, deviceid); + nfs3_map_deviceid_to_statdev (postnewparent, deviceid); + nfs3_map_deviceid_to_statdev (buf, deviceid); + dirwcc = nfs3_stat_to_wcc_data (preoldparent, postoldparent); + res->rename3res_u.resok.fromdir_wcc = dirwcc; + dirwcc = nfs3_stat_to_wcc_data (prenewparent, postnewparent); + res->rename3res_u.resok.todir_wcc = dirwcc; +} + + +void +nfs3_prep_write3args (write3args *args, struct nfs3_fh *fh) +{ + memset (args, 0, sizeof (*args)); + args->file.data.data_val = (void *)fh; +} + + +void +nfs3_fill_write3res (write3res *res, nfsstat3 stat, count3 count, + stable_how stable, uint64_t wverf, struct iatt *prestat, + struct iatt *poststat, uint64_t deviceid) +{ + write3resok resok; + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (prestat, deviceid); + nfs3_map_deviceid_to_statdev (poststat, deviceid); + resok.file_wcc = nfs3_stat_to_wcc_data (prestat, poststat); + resok.count = count; + resok.committed = stable; + memcpy (resok.verf, &wverf, sizeof (wverf)); + + res->write3res_u.resok = resok; +} + + +void +nfs3_prep_commit3args (commit3args *args, struct nfs3_fh *fh) +{ + memset (args, 0, sizeof (*args)); + args->file.data.data_val = (void *)fh; +} + + +void +nfs3_fill_commit3res (commit3res *res, nfsstat3 stat, uint64_t wverf, + struct iatt *prestat, struct iatt *poststat, + uint64_t deviceid) +{ + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (poststat, deviceid); + nfs3_map_deviceid_to_statdev (prestat, deviceid); + res->commit3res_u.resok.file_wcc = nfs3_stat_to_wcc_data (prestat, + poststat); + memcpy (res->commit3res_u.resok.verf, &wverf, sizeof (wverf)); +} + +void +nfs3_fill_read3res (read3res *res, nfsstat3 stat, count3 count, + struct iatt *poststat, int is_eof, uint64_t deviceid) +{ + post_op_attr poa; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (poststat, deviceid); + poa = nfs3_stat_to_post_op_attr (poststat); + res->read3res_u.resok.file_attributes = poa; + res->read3res_u.resok.count = count; + res->read3res_u.resok.eof = is_eof; + res->read3res_u.resok.data.data_len = count; +} + + +void +nfs3_prep_read3args (read3args *args, struct nfs3_fh *fh) +{ + memset (args, 0, sizeof (*args)); + args->file.data.data_val = (void *)fh; +} + + +void +nfs3_fill_pathconf3res (pathconf3res *res, nfsstat3 stat, struct iatt *buf, + uint64_t deviceid) +{ + pathconf3resok resok; + + memset (res, 0, sizeof (*res)); + res->status = stat; + if (stat != NFS3_OK) + return; + + nfs3_map_deviceid_to_statdev (buf, deviceid); + resok.obj_attributes = nfs3_stat_to_post_op_attr (buf); + resok.linkmax = 256; + resok.name_max = NFS_NAME_MAX; + resok.no_trunc = TRUE; + resok.chown_restricted = FALSE; + resok.case_insensitive = FALSE; + resok.case_preserving = TRUE; + + res->pathconf3res_u.resok = resok; +} + + +void +nfs3_prep_pathconf3args (pathconf3args *args, struct nfs3_fh *fh) +{ + memset (args, 0, sizeof (*args)); + args->object.data.data_val = (void *)fh; +} + + +int +nfs3_verify_dircookie (struct nfs3_state *nfs3, fd_t *dirfd, cookie3 cookie, + uint64_t cverf, nfsstat3 *stat) +{ + int ret = -1; + + if ((!nfs3) || (!dirfd)) + return -1; + + /* Can assume that this is first read on the dir, so cookie check + * is successful by default. + */ + if (cookie == 0) + return 0; + + gf_log (GF_NFS3, GF_LOG_TRACE, "Verifying cookie: cverf: %"PRIu64 + ", cookie: %"PRIu64, cverf, cookie); + /* The cookie bad, no way cverf will be zero with a non-zero cookie. */ + if ((cverf == 0) && (cookie != 0)) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Bad cookie requested"); + if (stat) + *stat = NFS3ERR_BAD_COOKIE; + goto err; + } + + /* Yes, its true, our cookie is simply the fd_t address. + * NOTE: We used have the check for cookieverf but VMWare client sends + * a readdirp requests even after we've told it that EOF has been + * reached on the directory. This causes a problem because we close a + * dir fd_t after reaching EOF. The next readdirp sent by VMWare + * contains the address of the closed fd_t as cookieverf. Since we + * closed that fd_t, this readdirp results in a new opendir which will + * give an fd_t that will fail this check below. + */ +/* if ((cverf != (uint64_t)dirfd)) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Cookieverf does not match"); + if (stat) + *stat = NFS3ERR_BAD_COOKIE; + goto err; + } +*/ + gf_log (GF_NFS3, GF_LOG_TRACE, "Cookie verified"); + if (stat) + *stat = NFS3_OK; + ret = 0; +err: + return ret; +} + + +void +nfs3_stat_to_errstr (uint32_t xid, char *op, nfsstat3 stat, int pstat, + char *errstr, size_t len) +{ + if ((!op) || (!errstr)) + return; + + snprintf (errstr, len, "XID: %x, %s: NFS: %d(%s), POSIX: %d(%s)", + xid, op,stat, nfsstat3_strerror (stat), pstat, + strerror (pstat)); +} + +void +nfs3_log_common_call (uint32_t xid, char *op, struct nfs3_fh *fh) +{ + char fhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s", xid, op, + fhstr); +} + + +void +nfs3_log_fh_entry_call (uint32_t xid, char *op, struct nfs3_fh *fh, + char *name) +{ + char fhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, name: %s", xid, + op, fhstr, name); +} + + +void +nfs3_log_rename_call (uint32_t xid, struct nfs3_fh *src, char *sname, + struct nfs3_fh *dst, char *dname) +{ + char sfhstr[1024]; + char dfhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (src, sfhstr, sizeof (sfhstr)); + nfs3_fh_to_str (dst, dfhstr, sizeof (dfhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, RENAME: args: Src: %s, " + "name: %s, Dst: %s, name: %s", xid, sfhstr, sname, dfhstr, + dname); +} + + + +void +nfs3_log_create_call (uint32_t xid, struct nfs3_fh *fh, char *name, + createmode3 mode) +{ + char fhstr[1024]; + char *modestr = NULL; + char exclmode[] = "EXCLUSIVE"; + char unchkd[] = "UNCHECKED"; + char guarded[] = "GUARDED"; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + if (mode == EXCLUSIVE) + modestr = exclmode; + else if (mode == GUARDED) + modestr = guarded; + else + modestr = unchkd; + + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, CREATE: args: %s, name: %s," + " mode: %s", xid, fhstr, name, modestr); +} + + +void +nfs3_log_mknod_call (uint32_t xid, struct nfs3_fh *fh, char *name, int type) +{ + char fhstr[1024]; + char *modestr = NULL; + char chr[] = "CHAR"; + char blk[] = "BLK"; + char sock[] = "SOCK"; + char fifo[] = "FIFO"; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + if (type == NF3CHR) + modestr = chr; + else if (type == NF3BLK) + modestr = blk; + else if (type == NF3SOCK) + modestr = sock; + else + modestr = fifo; + + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, MKNOD: args: %s, name: %s," + " type: %s", xid, fhstr, name, modestr); +} + + + +void +nfs3_log_symlink_call (uint32_t xid, struct nfs3_fh *fh, char *name, char *tgt) +{ + char fhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, SYMLINK: args: %s, name: %s," + " target: %s", xid, fhstr, name, tgt); +} + + +void +nfs3_log_link_call (uint32_t xid, struct nfs3_fh *fh, char *name, + struct nfs3_fh *tgt) +{ + char dfhstr[1024]; + char tfhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, dfhstr, sizeof (dfhstr)); + nfs3_fh_to_str (tgt, tfhstr, sizeof (tfhstr)); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, LINK: args: %s, name: %s," + " target: %s", xid, dfhstr, name, tfhstr); +} + + +void +nfs3_log_rw_call (uint32_t xid, char *op, struct nfs3_fh *fh, offset3 offt, + count3 count, int stablewrite) +{ + char fhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + if (stablewrite == -1) + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, offset:" + " %"PRIu64", count: %"PRIu32, xid, op, fhstr, offt, + count); + else + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, offset:" + " %"PRIu64", count: %"PRIu32", %s", xid, op, fhstr, + offt, count, + (stablewrite == UNSTABLE)?"UNSTABLE":"STABLE"); + +} + + +int +nfs3_getattr_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_PERM: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ACCES: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_setattr_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_lookup_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_PERM: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ACCES: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_access_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_readlink_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + +int +nfs3_read_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_write_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_create_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_mkdir_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_symlink_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_mknod_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + +int +nfs3_remove_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_rmdir_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_rename_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_link_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_readdir_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + + +int +nfs3_fsstat_loglevel (nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (stat) { + + case NFS3ERR_PERM: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOENT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ACCES: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_EXIST: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_XDEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NODEV: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_IO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NXIO: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ISDIR: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_INVAL: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOSPC: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_ROFS: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_FBIG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_MLINK: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NAMETOOLONG: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTEMPTY: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_SERVERFAULT: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_NOTSUPP: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_BADHANDLE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_STALE: + ll = GF_LOG_WARNING; + break; + + case NFS3ERR_DQUOT: + ll = GF_LOG_WARNING; + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + +struct nfs3op_str { + int op; + char str[100]; +}; + +struct nfs3op_str nfs3op_strings[] = { + { NFS3_NULL, "NULL"}, + { NFS3_GETATTR, "GETATTR"}, + { NFS3_SETATTR, "SETATTR"}, + { NFS3_LOOKUP, "LOOKUP"}, + { NFS3_ACCESS, "ACCESS"}, + { NFS3_READLINK, "READLINK"}, + { NFS3_READ, "READ"}, + { NFS3_WRITE, "WRITE"}, + { NFS3_CREATE, "CREATE"}, + { NFS3_MKDIR, "MKDIR"}, + { NFS3_SYMLINK, "SYMLINK"}, + { NFS3_MKNOD, "MKNOD"}, + { NFS3_REMOVE, "REMOVE"}, + { NFS3_RMDIR, "RMDIR"}, + { NFS3_RENAME, "RENAME"}, + { NFS3_LINK, "LINK"}, + { NFS3_READDIR, "READDIR"}, + { NFS3_READDIRP, "READDIRP"}, + { NFS3_FSSTAT, "FSSTAT"}, + { NFS3_FSINFO, "FSINFO"}, + { NFS3_PATHCONF, "PATHCONF"}, + { NFS3_COMMIT, "COMMIT"}, +}; + +int +nfs3_loglevel (int nfs_op, nfsstat3 stat) { + + int ll = GF_LOG_DEBUG; + + switch (nfs_op) { + case NFS3_GETATTR: + ll = nfs3_getattr_loglevel (stat); + break; + + case NFS3_SETATTR: + ll = nfs3_setattr_loglevel (stat); + break; + + case NFS3_LOOKUP: + ll = nfs3_lookup_loglevel (stat); + break; + + case NFS3_ACCESS: + ll = nfs3_access_loglevel (stat); + break; + + case NFS3_READLINK: + ll = nfs3_readlink_loglevel (stat); + break; + + case NFS3_READ: + ll = nfs3_read_loglevel (stat); + break; + + case NFS3_WRITE: + ll = nfs3_write_loglevel (stat); + break; + + case NFS3_CREATE: + ll = nfs3_create_loglevel (stat); + break; + + case NFS3_MKDIR: + ll = nfs3_mkdir_loglevel (stat); + break; + + case NFS3_SYMLINK: + ll = nfs3_symlink_loglevel (stat); + break; + + case NFS3_MKNOD: + ll = nfs3_mknod_loglevel (stat); + break; + + case NFS3_REMOVE: + ll = nfs3_remove_loglevel (stat); + break; + + case NFS3_RMDIR: + ll = nfs3_rmdir_loglevel (stat); + break; + + case NFS3_RENAME: + ll = nfs3_rename_loglevel (stat); + break; + + case NFS3_LINK: + ll = nfs3_link_loglevel (stat); + break; + + case NFS3_READDIR: + ll = nfs3_readdir_loglevel (stat); + break; + + case NFS3_READDIRP: + ll = nfs3_readdir_loglevel (stat); + break; + + case NFS3_FSSTAT: + ll = nfs3_fsstat_loglevel (stat); + break; + + case NFS3_FSINFO: + ll = nfs3_fsstat_loglevel (stat); + break; + + case NFS3_PATHCONF: + ll = nfs3_fsstat_loglevel (stat); + break; + + case NFS3_COMMIT: + ll = nfs3_write_loglevel (stat); + break; + + default: + ll = GF_LOG_DEBUG; + break; + } + + return ll; +} + +void +nfs3_log_common_res (uint32_t xid, int op, nfsstat3 stat, int pstat) +{ + char errstr[1024]; + int ll = nfs3_loglevel (op, stat); + + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, nfs3op_strings[op].str, stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s", errstr); +} + +void +nfs3_log_readlink_res (uint32_t xid, nfsstat3 stat, int pstat, char *linkpath) +{ + char errstr[1024]; + int ll = nfs3_loglevel (NFS3_READLINK, stat); + + if (THIS->ctx->log.loglevel < ll) + return; + + nfs3_stat_to_errstr (xid, "READLINK", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, target: %s", + errstr, linkpath); + +} + +void +nfs3_log_read_res (uint32_t xid, nfsstat3 stat, int pstat, count3 count, + int is_eof, struct iovec *vec, int32_t veccount) +{ + char errstr[1024]; + int ll = GF_LOG_DEBUG; + + ll = nfs3_loglevel (NFS3_READ, stat); + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "READ", stat, pstat, errstr, sizeof (errstr)); + if (vec) + gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", is_eof:" + " %d, vector: count: %d, len: %zd", errstr, count, + is_eof, veccount, vec->iov_len); + else + gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", is_eof:" + " %d", errstr, count, is_eof); +} + + +void +nfs3_log_write_res (uint32_t xid, nfsstat3 stat, int pstat, count3 count, + int stable, uint64_t wverf) +{ + char errstr[1024]; + int ll = nfs3_loglevel (NFS3_WRITE, stat); + + if (THIS->ctx->log.loglevel < ll) + return; + + nfs3_stat_to_errstr (xid, "WRITE", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", %s,wverf: %"PRIu64 + , errstr, count, (stable == UNSTABLE)?"UNSTABLE":"STABLE", + wverf); +} + + +void +nfs3_log_newfh_res (uint32_t xid, int op, nfsstat3 stat, int pstat, + struct nfs3_fh *newfh) +{ + char errstr[1024]; + char fhstr[1024]; + int ll = nfs3_loglevel (op, stat); + + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, nfs3op_strings[op].str, stat, pstat, errstr, sizeof (errstr)); + nfs3_fh_to_str (newfh, fhstr, sizeof (fhstr)); + + gf_log (GF_NFS3, nfs3_loglevel (op, stat), "%s, %s", errstr, fhstr); +} + + +void +nfs3_log_readdir_res (uint32_t xid, nfsstat3 stat, int pstat, uint64_t cverf, + count3 count, int is_eof) +{ + char errstr[1024]; + int ll = nfs3_loglevel (NFS3_READDIR, stat); + + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "READDIR", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", cverf: %"PRIu64 + ", is_eof: %d", errstr, count, cverf, is_eof); +} + + +void +nfs3_log_readdirp_res (uint32_t xid, nfsstat3 stat, int pstat, uint64_t cverf, + count3 dircount, count3 maxcount, int is_eof) +{ + char errstr[1024]; + int ll = nfs3_loglevel (NFS3_READDIRP, stat); + + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "READDIRPLUS", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, dircount: %"PRIu32", maxcount: %" + PRIu32", cverf: %"PRIu64", is_eof: %d", errstr, dircount, + maxcount, cverf, is_eof); +} + + +void +nfs3_log_commit_res (uint32_t xid, nfsstat3 stat, int pstat, uint64_t wverf) +{ + char errstr[1024]; + int ll = nfs3_loglevel (NFS3_COMMIT, stat); + + if (THIS->ctx->log.loglevel < ll) + return; + nfs3_stat_to_errstr (xid, "COMMIT", stat, pstat, errstr, sizeof (errstr)); + gf_log (GF_NFS3, ll, "%s, wverf: %"PRIu64, errstr, wverf); +} + + +void +nfs3_log_readdir_call (uint32_t xid, struct nfs3_fh *fh, count3 dircount, + count3 maxcount) +{ + char fhstr[1024]; + + if (THIS->ctx->log.loglevel < GF_LOG_DEBUG) + return; + + nfs3_fh_to_str (fh, fhstr, sizeof (fhstr)); + + if (maxcount == 0) + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, READDIR: args: %s," + " count: %d", xid, fhstr, (uint32_t)dircount); + else + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, READDIRPLUS: args: %s," + " dircount: %d, maxcount: %d", xid, fhstr, + (uint32_t)dircount, (uint32_t)maxcount); +} + + +int +nfs3_fh_resolve_inode_done (nfs3_call_state_t *cs, inode_t *inode) +{ + int ret = -EFAULT; + + if ((!cs) || (!inode)) + return ret; + + gf_log (GF_NFS3, GF_LOG_TRACE, "FH inode resolved"); + ret = nfs_inode_loc_fill (inode, &cs->resolvedloc, NFS_RESOLVE_EXIST); + if (ret < 0) { + gf_log (GF_NFS3, GF_LOG_ERROR, "inode loc fill failed"); + goto err; + } + + nfs3_call_resume (cs); + +err: + return ret; +} + + +int32_t +nfs3_fh_resolve_entry_lookup_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xattr, + struct iatt *postparent) +{ + nfs3_call_state_t *cs = NULL; + inode_t *linked_inode = NULL; + + cs = frame->local; + cs->resolve_ret = op_ret; + cs->resolve_errno = op_errno; + + if (op_ret == -1) { + gf_log (GF_NFS3, (op_errno == ENOENT ? GF_LOG_TRACE : GF_LOG_ERROR), + "Lookup failed: %s: %s", + cs->resolvedloc.path, strerror (op_errno)); + goto err; + } else + gf_log (GF_NFS3, GF_LOG_TRACE, "Entry looked up: %s", + cs->resolvedloc.path); + + memcpy (&cs->stbuf, buf, sizeof (*buf)); + memcpy (&cs->postparent, postparent, sizeof (*postparent)); + linked_inode = inode_link (inode, cs->resolvedloc.parent, + cs->resolvedloc.name, buf); + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (cs->resolvedloc.inode); + cs->resolvedloc.inode = linked_inode; + } +err: + nfs3_call_resume (cs); + return 0; +} + + +int32_t +nfs3_fh_resolve_inode_lookup_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xattr, + struct iatt *postparent) +{ + nfs3_call_state_t *cs = NULL; + inode_t *linked_inode = NULL; + + cs = frame->local; + cs->resolve_ret = op_ret; + cs->resolve_errno = op_errno; + + if (op_ret == -1) { + gf_log (GF_NFS3, (op_errno == ENOENT ? GF_LOG_TRACE : GF_LOG_ERROR), + "Lookup failed: %s: %s", + cs->resolvedloc.path, strerror (op_errno)); + nfs3_call_resume (cs); + goto err; + } + + memcpy (&cs->stbuf, buf, sizeof(*buf)); + memcpy (&cs->postparent, buf, sizeof(*postparent)); + linked_inode = inode_link (inode, cs->resolvedloc.parent, + cs->resolvedloc.name, buf); + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (cs->resolvedloc.inode); + cs->resolvedloc.inode = linked_inode; + } + + /* If it is an entry lookup and we landed in the callback for hard + * inode resolution, it means the parent inode was not available and + * had to be resolved first. Now that is done, lets head back into + * entry resolution. + */ + if (cs->resolventry) + nfs3_fh_resolve_entry_hard (cs); + else + nfs3_call_resume (cs); +err: + return 0; +} + + + +/* Needs no extra argument since it knows that the fh to be resolved is in + * resolvefh and that it needs to start looking from the root. + */ +int +nfs3_fh_resolve_inode_hard (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + + if (!cs) + return ret; + + gf_log (GF_NFS3, GF_LOG_TRACE, "FH hard resolution for: gfid 0x%s", + uuid_utoa (cs->resolvefh.gfid)); + cs->hardresolved = 1; + nfs_loc_wipe (&cs->resolvedloc); + ret = nfs_gfid_loc_fill (cs->vol->itable, cs->resolvefh.gfid, + &cs->resolvedloc, NFS_RESOLVE_CREATE); + if (ret < 0) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to fill loc using gfid: " + "%s", strerror (-ret)); + goto out; + } + + nfs_user_root_create (&nfu); + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_inode_lookup_cbk, cs); + +out: + return ret; +} + + +int +nfs3_fh_resolve_entry_hard (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + + if (!cs) + return ret; + + nfs_loc_wipe (&cs->resolvedloc); + nfs_user_root_create (&nfu); + gf_log (GF_NFS3, GF_LOG_TRACE, "FH hard resolution: gfid: %s " + ", entry: %s", uuid_utoa (cs->resolvefh.gfid), + cs->resolventry); + + ret = nfs_entry_loc_fill (cs->vol->itable, cs->resolvefh.gfid, + cs->resolventry, &cs->resolvedloc, + NFS_RESOLVE_CREATE); + + if (ret == -2) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Entry needs lookup: %s", + cs->resolvedloc.path); + /* If the NFS op is lookup, let the resume callback + * handle the sending of the lookup fop. Similarly, + * if the NFS op is create, let the create call + * go ahead in the resume callback so that an EEXIST gets + * handled at posix without an extra fop at this point. + */ + if (nfs3_lookup_op (cs) || + (nfs3_create_op (cs) && !nfs3_create_exclusive_op (cs))) { + cs->lookuptype = GF_NFS3_FRESH; + cs->resolve_ret = 0; + nfs3_call_resume (cs); + } else { + cs->hardresolved = 1; + nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_entry_lookup_cbk, cs); + } + ret = 0; + } else if (ret == -1) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Entry needs parent lookup: %s", + cs->resolvedloc.path); + ret = nfs3_fh_resolve_inode_hard (cs); + } else if (ret == 0) { + cs->resolve_ret = 0; + nfs3_call_resume (cs); + } + + return ret; +} + +int +nfs3_fh_resolve_inode (nfs3_call_state_t *cs) +{ + inode_t *inode = NULL; + int ret = -EFAULT; + + if (!cs) + return ret; + + gf_log (GF_NFS3, GF_LOG_TRACE, "FH needs inode resolution"); + uuid_copy (cs->resolvedloc.gfid, cs->resolvefh.gfid); + inode = inode_find (cs->vol->itable, cs->resolvefh.gfid); + if (!inode) + ret = nfs3_fh_resolve_inode_hard (cs); + else + ret = nfs3_fh_resolve_inode_done (cs, inode); + + if (inode) + inode_unref (inode); + + return ret; +} + +int +nfs3_fh_resolve_entry (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + + if (!cs) + return ret; + + return nfs3_fh_resolve_entry_hard (cs); +} + + +int +nfs3_fh_resolve_resume (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + + if (!cs) + return ret; + + if (cs->resolve_ret < 0) + goto err_resume_call; + + if (!cs->resolventry) + ret = nfs3_fh_resolve_inode (cs); + else + ret = nfs3_fh_resolve_entry (cs); + +err_resume_call: + if (ret < 0) { + cs->resolve_ret = -1; + cs->resolve_errno = EFAULT; + nfs3_call_resume (cs); + ret = 0; + } + + return ret; +} + + +int32_t +nfs3_fh_resolve_root_lookup_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xattr, + struct iatt *postparent) +{ + nfs3_call_state_t *cs = NULL; + + cs = frame->local; + cs->resolve_ret = op_ret; + cs->resolve_errno = op_errno; + + if (op_ret == -1) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Root lookup failed: %s", + strerror (op_errno)); + goto err; + } else + gf_log (GF_NFS3, GF_LOG_TRACE, "Root looked up: %s", + cs->resolvedloc.path); + + nfs3_set_root_looked_up (cs->nfs3state, &cs->resolvefh); +err: + nfs3_fh_resolve_resume (cs); + return 0; +} + + +int +nfs3_fh_resolve_root (nfs3_call_state_t *cs) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + + if (!cs) + return ret; + + if (nfs3_is_root_looked_up (cs->nfs3state, &cs->resolvefh)) { + ret = nfs3_fh_resolve_resume (cs); + goto out; + } + + nfs_user_root_create (&nfu); + gf_log (GF_NFS3, GF_LOG_TRACE, "Root needs lookup"); + ret = nfs_root_loc_fill (cs->vol->itable, &cs->resolvedloc); + if (ret < 0) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to lookup root from itable: %s", + strerror (-ret)); + goto out; + } + + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_root_lookup_cbk, cs); + +out: + return ret; +} + + +int +nfs3_fh_resolve_and_resume (nfs3_call_state_t *cs, struct nfs3_fh *fh, + char *entry, nfs3_resume_fn_t resum_fn) +{ + int ret = -EFAULT; + + if ((!cs) || (!fh)) + return ret; + + cs->resume_fn = resum_fn; + cs->resolvefh = *fh; + cs->hashidx = 0; + + /* Check if the resolution is: + * a. fh resolution + * + * or + * + * b. (fh, basename) resolution + */ + if (entry) { /* b */ + cs->resolventry = gf_strdup (entry); + if (!cs->resolventry) + goto err; + } + + ret = nfs3_fh_resolve_root (cs); +err: + return ret; +} |
