diff options
Diffstat (limited to 'xlators/nfs/server/src/nfs3-helpers.c')
| -rw-r--r-- | xlators/nfs/server/src/nfs3-helpers.c | 3917 |
1 files changed, 3917 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 00000000000..897fb42b071 --- /dev/null +++ b/xlators/nfs/server/src/nfs3-helpers.c @@ -0,0 +1,3917 @@ +/* + 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. +*/ + +#include <inttypes.h> + +#include <glusterfs/xlator.h> +#include "nfs3.h" +#include "nfs3-fh.h" +#include "msg-nfs3.h" +#include <glusterfs/rbthash.h> +#include "nfs-fops.h" +#include "nfs-inodes.h" +#include "nfs-generics.h" +#include "nfs3-helpers.h" +#include "nfs-mem-types.h" +#include <glusterfs/iatt.h> +#include <glusterfs/common-utils.h> +#include "nfs-messages.h" +#include "mount3.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"}, + {NFS3ERR_END_OF_LIST, "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 ENOTSUP: + 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. + */ +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; + } +} + +void +nfs3_stat_to_fattr3(struct iatt *buf, fattr3 *fa) +{ + if (buf == NULL || fa == NULL) { + errno = EINVAL; + return; + } + + 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; +} + +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 (gf_is_zero_filled_stat(buf)) + goto out; + + nfs3_stat_to_fattr3(buf, &(attr.post_op_attr_u.attributes)); + 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 (gf_is_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(); + 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); + nfs3_stat_to_fattr3(buf, &(res->getattr3res_u.resok.obj_attributes)); +} + +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 != NFS3ERR_END_OF_LIST; 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; + int name_len = 0; + if ((!entry) || (!dfh)) + return NULL; + + ent = GF_CALLOC(1, sizeof(*ent), gf_nfs_mt_entry3); + if (!ent) + return NULL; + + gf_msg_trace(GF_NFS3, 0, "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; + name_len = strlen(entry->d_name); + ent->name = GF_MALLOC(name_len + 1, gf_nfs_mt_char); + if (!ent->name) { + GF_FREE(ent); + ent = NULL; + goto err; + } + strcpy(ent->name, entry->d_name); + ent->name[name_len] = '\0'; + +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(); + 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_MALLOC(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}, + }; + int name_len = 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_msg_trace(GF_NFS3, 0, "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; + name_len = strlen(entry->d_name); + ent->name = GF_MALLOC(name_len + 1, gf_nfs_mt_char); + if (!ent->name) { + GF_FREE(ent); + ent = NULL; + goto err; + } + strcpy(ent->name, entry->d_name); + ent->name[name_len] = '\0'; + + nfs3_fh_build_child_fh(dirfh, &entry->d_stat, &newfh); + nfs3_map_deviceid_to_statdev(&entry->d_stat, devid); + /* * + * In tier volume, the readdirp send only to cold subvol + * which will populate in the 'T' file entries in the result. + * For such files an explicit stat call is required, by setting + * following argument client will perform the same. + * + * The inode value for 'T' files and directory is NULL, so just + * skip the check if it is directory. + */ + if (!(IA_ISDIR(entry->d_stat.ia_type)) && (entry->inode == NULL)) + ent->name_attributes.attributes_follow = FALSE; + else + 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 = gf_time(); + } + + 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 = gf_time(); + } + + 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_msg_trace(GF_NFS3, 0, + "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_msg_trace(GF_NFS3, 0, "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_msg_trace(GF_NFS3, 0, "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_msg_debug(GF_NFS3, 0, "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_msg_debug(GF_NFS3, 0, "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_msg_debug(GF_NFS3, 0, + "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_msg_debug(GF_NFS3, 0, + "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_msg_debug(GF_NFS3, 0, + "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_msg_debug(GF_NFS3, 0, + "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_msg_debug(GF_NFS3, 0, + "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_msg_debug(GF_NFS3, 0, + "XID: %x, %s: args: %s, offset:" + " %" PRIu64 ", count: %" PRIu32, + xid, op, fhstr, offt, count); + else + gf_msg_debug(GF_NFS3, 0, + "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, + const char *path) +{ + 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)); + if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, "%s => (%s)", path, errstr); + else + gf_msg(GF_NFS3, ll, errno, NFS_MSG_STAT_ERROR, "%s => (%s)", path, + errstr); +} + +void +nfs3_log_readlink_res(uint32_t xid, nfsstat3 stat, int pstat, char *linkpath, + const char *path) +{ + 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)); + if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, "%s => (%s), target: %s", path, errstr, + linkpath); + else + gf_msg(GF_NFS3, ll, errno, NFS_MSG_STAT_ERROR, "%s => (%s) target: %s", + path, 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, + const char *path) +{ + 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) + if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, + "%s => (%s), count: %" PRIu32 + ", is_eof:" + " %d, vector: count: %d, len: %zd", + path, errstr, count, is_eof, veccount, vec->iov_len); + else + gf_msg(GF_NFS3, ll, errno, NFS_MSG_STAT_ERROR, + "%s => (%s), count: %" PRIu32 + ", is_eof:" + " %d, vector: count: %d, len: %zd", + path, errstr, count, is_eof, veccount, vec->iov_len); + else if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, + "%s => (%s), count: %" PRIu32 + ", is_eof:" + " %d", + path, errstr, count, is_eof); + else + gf_msg(GF_NFS3, ll, errno, NFS_MSG_STAT_ERROR, + "%s => (%s), count: %" PRIu32 + ", is_eof:" + " %d", + path, errstr, count, is_eof); +} + +void +nfs3_log_write_res(uint32_t xid, nfsstat3 stat, int pstat, count3 count, + int stable, uint64_t wverf, const char *path) +{ + 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)); + if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, + "%s => (%s), count: %" PRIu32 + ", %s,wverf: " + "%" PRIu64, + path, errstr, count, + (stable == UNSTABLE) ? "UNSTABLE" : "STABLE", wverf); + else + gf_msg(GF_NFS3, ll, errno, NFS_MSG_STAT_ERROR, + "%s => (%s), count: %" PRIu32 ", %s,wverf: %" PRIu64, path, + 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, const char *path) +{ + 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)); + + if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, "%s => (%s), %s", path, errstr, fhstr); + else + gf_msg(GF_NFS3, nfs3_loglevel(op, stat), errno, NFS_MSG_STAT_ERROR, + "%s => (%s), %s", path, errstr, fhstr); +} + +void +nfs3_log_readdir_res(uint32_t xid, nfsstat3 stat, int pstat, uint64_t cverf, + count3 count, int is_eof, const char *path) +{ + 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)); + if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, + "%s => (%s), count: %" PRIu32 ", cverf: %" PRIu64 + ", is_eof: %d", + path, errstr, count, cverf, is_eof); + else + gf_msg(GF_NFS3, ll, errno, NFS_MSG_STAT_ERROR, + "%s => (%s), count: %" PRIu32 ", cverf: %" PRIu64 ", is_eof: %d", + path, 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, + const char *path) +{ + 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)); + if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, + "%s => (%s), dircount: %" PRIu32 ", maxcount: %" PRIu32 + ", cverf: %" PRIu64 ", is_eof: %d", + path, errstr, dircount, maxcount, cverf, is_eof); + else + gf_msg(GF_NFS3, ll, errno, NFS_MSG_STAT_ERROR, + "%s => (%s), dircount: %" PRIu32 ", maxcount: %" PRIu32 + ", cverf: %" PRIu64 ", is_eof: %d", + path, errstr, dircount, maxcount, cverf, is_eof); +} + +void +nfs3_log_commit_res(uint32_t xid, nfsstat3 stat, int pstat, uint64_t wverf, + const char *path) +{ + 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)); + if (ll == GF_LOG_DEBUG) + gf_msg_debug(GF_NFS3, 0, "%s => (%s), wverf: %" PRIu64, path, errstr, + wverf); + else + gf_msg(GF_NFS3, ll, errno, NFS_MSG_STAT_ERROR, + "%s => (%s), wverf: %" PRIu64, path, 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_msg_debug(GF_NFS3, 0, + "XID: %x, READDIR: args: %s," + " count: %d", + xid, fhstr, (uint32_t)dircount); + else + gf_msg_debug(GF_NFS3, 0, + "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_msg_trace(GF_NFS3, 0, "FH inode resolved"); + ret = nfs_inode_loc_fill(inode, &cs->resolvedloc, NFS_RESOLVE_EXIST); + if (ret < 0) { + gf_msg(GF_NFS3, GF_LOG_ERROR, -ret, NFS_MSG_INODE_LOC_FILL_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) { + if (op_errno == ENOENT) { + gf_msg_trace(GF_NFS3, 0, "Lookup failed: %s: %s", + cs->resolvedloc.path, strerror(op_errno)); + } else { + gf_msg(GF_NFS3, GF_LOG_ERROR, op_errno, NFS_MSG_LOOKUP_FAIL, + "Lookup failed: %s: %s", cs->resolvedloc.path, + strerror(op_errno)); + } + goto err; + } else + gf_msg_trace(GF_NFS3, 0, "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) { + nfs_fix_generation(this, linked_inode); + inode_lookup(linked_inode); + inode_unref(cs->resolvedloc.inode); + cs->resolvedloc.inode = linked_inode; + } else { + /* nfs3_fh_resolve_entry_hard() use to resolve entire path if needed. + * So the ctx for inode obtained from here need to set properly, + * otherwise it may result in a crash. + */ + nfs_fix_generation(this, 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) { + if (op_errno == ENOENT) { + gf_msg_trace(GF_NFS3, 0, "Lookup failed: %s: %s", + cs->resolvedloc.path, strerror(op_errno)); + } else { + gf_msg(GF_NFS3, GF_LOG_ERROR, op_errno, NFS_MSG_LOOKUP_FAIL, + "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) { + nfs_fix_generation(this, 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_msg_trace(GF_NFS3, 0, "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_msg(GF_NFS3, GF_LOG_ERROR, -ret, NFS_MSG_INODE_LOC_FILL_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, + }; + gf_boolean_t freshlookup = _gf_false; + + if (!cs) + return ret; + + nfs_loc_wipe(&cs->resolvedloc); + nfs_user_root_create(&nfu); + gf_msg_trace(GF_NFS3, 0, + "FH hard resolution: gfid: %s " + ", entry: %s", + uuid_utoa(cs->resolvefh.gfid), cs->resolventry); + + ret = nfs_entry_loc_fill(cs->nfsx, cs->vol->itable, cs->resolvefh.gfid, + cs->resolventry, &cs->resolvedloc, + NFS_RESOLVE_CREATE, &freshlookup); + + if (ret == -2) { + gf_msg_trace(GF_NFS3, 0, "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 (freshlookup && + (nfs3_lookup_op(cs) || + (nfs3_create_op(cs) && !nfs3_create_exclusive_op(cs)))) { + cs->lookuptype = GF_NFS3_FRESH; + cs->resolve_ret = 0; + cs->hardresolved = 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_msg_trace(GF_NFS3, 0, "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; + xlator_t *this = NULL; + + if (!cs) + return ret; + + this = cs->nfsx; + gf_msg_trace(GF_NFS3, 0, "FH needs inode resolution"); + gf_uuid_copy(cs->resolvedloc.gfid, cs->resolvefh.gfid); + + inode = inode_find(cs->vol->itable, cs->resolvefh.gfid); + if (!inode || inode_ctx_get(inode, this, NULL)) + 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_msg(GF_NFS3, GF_LOG_ERROR, op_errno, NFS_MSG_LOOKUP_ROOT_FAIL, + "Root lookup failed: %s", strerror(op_errno)); + goto err; + } else + gf_msg_trace(GF_NFS3, 0, "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_msg_trace(GF_NFS3, 0, "Root needs lookup"); + ret = nfs_root_loc_fill(cs->vol->itable, &cs->resolvedloc); + if (ret < 0) { + gf_msg(GF_NFS3, GF_LOG_ERROR, -ret, NFS_MSG_LOOKUP_ROOT_FAIL, + "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; +} + +/** + * __nfs3_fh_auth_get_peer -- Get a peer name from the rpc request object + * + * @peer: Char * to write to + * @req : The request to get host/peer from + */ +int +__nfs3_fh_auth_get_peer(const rpcsvc_request_t *req, char *peer) +{ + struct sockaddr_storage sastorage = { + 0, + }; + rpc_transport_t *trans = NULL; + int ret = 0; + + /* Why do we pass in the peer here and then + * store it rather than malloc() and return a char * ? We want to avoid + * heap allocations in the IO path as much as possible for speed + * so we try to keep all allocations on the stack. + */ + trans = rpcsvc_request_transport(req); + ret = rpcsvc_transport_peeraddr(trans, peer, RPCSVC_PEER_STRLEN, &sastorage, + sizeof(sastorage)); + if (ret != 0) { + gf_msg(GF_NFS3, GF_LOG_WARNING, 0, NFS_MSG_GET_PEER_ADDR_FAIL, + "Failed to get peer addr: %s", gai_strerror(ret)); + } + return ret; +} + +/* + * nfs3_fh_auth_nfsop () -- Checks if an nfsop is authorized. + * + * @cs: The NFS call state containing all the relevant information + * + * @return: 0 if authorized + * -EACCES for completely unauthorized fop + * -EROFS for unauthorized write operations (rm, mkdir, write) + */ +int +nfs3_fh_auth_nfsop(nfs3_call_state_t *cs, gf_boolean_t is_write_op) +{ + struct nfs_state *nfs = NULL; + struct mount3_state *ms = NULL; + + nfs = (struct nfs_state *)cs->nfsx->private; + ms = (struct mount3_state *)nfs->mstate; + return mnt3_authenticate_request(ms, cs->req, &cs->resolvefh, NULL, NULL, + NULL, NULL, is_write_op); +} + +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; +} |
