diff options
Diffstat (limited to 'xlators/nfs/server/src/nfs3-helpers.c')
| -rw-r--r-- | xlators/nfs/server/src/nfs3-helpers.c | 2825 |
1 files changed, 1102 insertions, 1723 deletions
diff --git a/xlators/nfs/server/src/nfs3-helpers.c b/xlators/nfs/server/src/nfs3-helpers.c index e2c16ef0e..468f8f7af 100644 --- a/xlators/nfs/server/src/nfs3-helpers.c +++ b/xlators/nfs/server/src/nfs3-helpers.c @@ -1,18 +1,18 @@ /* - Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> This file is part of GlusterFS. GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GlusterFS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Affero General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -102,18 +102,21 @@ struct nfs3stat_strerror nfs3stat_strerror_table[] = { uint64_t nfs3_iatt_gfid_to_ino (struct iatt *buf) { - uint64_t ino = 0; + uuid_t gfid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + uint64_t ino = 0; if (!buf) return 0; - if (gf_nfs_enable_ino32()) { - ino = (uint32_t )nfs_hash_gfid (buf->ia_gfid); - goto hashout; - } + if ((buf->ia_ino != 1) && (uuid_compare (buf->ia_gfid, gfid) != 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; + memcpy (&ino, &buf->ia_gfid[8], sizeof (uint64_t)); + } else + ino = 1; hashout: return ino; @@ -343,15 +346,25 @@ nfs3_stat_to_fattr3 (struct iatt *buf) fa.fsid = buf->ia_dev; fa.fileid = nfs3_iatt_gfid_to_ino (buf); + /* FIXME: Handle time resolutions for sub-second granularity */ + if (buf->ia_atime == 9669) { + fa.mtime.seconds = 0; + fa.mtime.nseconds = 0; + fa.atime.seconds = 0; + fa.atime.nseconds = 0; + } else { + fa.mtime.seconds = buf->ia_mtime; + fa.mtime.nseconds = 0; + fa.atime.seconds = buf->ia_atime; + fa.atime.seconds = 0; + fa.atime.nseconds = 0; + } fa.atime.seconds = buf->ia_atime; - fa.atime.nseconds = buf->ia_atime_nsec; + fa.atime.nseconds = 0; 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; + fa.ctime.nseconds = 0; return fa; } @@ -395,10 +408,11 @@ nfs3_stat_to_pre_op_attr (struct iatt *pre) 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; + if (pre->ia_atime == 9669) + poa.pre_op_attr_u.attributes.mtime.seconds = 0; + else + poa.pre_op_attr_u.attributes.mtime.seconds = pre->ia_mtime; 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; @@ -551,48 +565,171 @@ nfs3_prep_access3args (access3args *args, struct nfs3_fh *fh) 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) +nfs3_owner_accessbits (ia_prot_t prot, ia_type_t type, uint32_t request) { - uint32_t accresult = 0; + uint32_t accresult = 0; - if (accbits & POSIX_READ) + if (IA_PROT_RUSR (prot) && (request & ACCESS3_READ)) accresult |= ACCESS3_READ; - if (accbits & POSIX_WRITE) - accresult |= (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE); + if (request & ACCESS3_LOOKUP) + if ((IA_ISDIR (type)) && (IA_PROT_XUSR (prot))) + accresult |= ACCESS3_LOOKUP; + + if ((IA_PROT_WUSR (prot) && (request & ACCESS3_MODIFY))) + accresult |= ACCESS3_MODIFY; + + if ((IA_PROT_WUSR (prot) && (request & ACCESS3_EXTEND))) + accresult |= ACCESS3_EXTEND; + + /* ACCESS3_DELETE is ignored for now since that requires + * knowing the permissions on the parent directory. + */ + + if (request & ACCESS3_EXECUTE) + if (IA_PROT_XUSR (prot) && (!IA_ISDIR (type))) + accresult |= ACCESS3_EXECUTE; + + return accresult; +} + + +uint32_t +nfs3_group_accessbits (ia_prot_t prot, ia_type_t type, uint32_t request) +{ + uint32_t accresult = 0; + + if (IA_PROT_RGRP (prot) && (request & ACCESS3_READ)) + accresult |= ACCESS3_READ; + + if (request & ACCESS3_LOOKUP) + if ((IA_ISDIR (type)) && IA_PROT_RGRP (prot)) + accresult |= ACCESS3_LOOKUP; + + if (IA_PROT_WGRP (prot) && (request & ACCESS3_MODIFY)) + accresult |= ACCESS3_MODIFY; + + if (IA_PROT_WGRP (prot) && (request & ACCESS3_EXTEND)) + accresult |= ACCESS3_EXTEND; + + /* ACCESS3_DELETE is ignored for now since that requires + * knowing the permissions on the parent directory. + */ + + if (request & ACCESS3_EXECUTE) + if (IA_PROT_XGRP (prot) && (!IA_ISDIR (type))) + accresult |= ACCESS3_EXECUTE; + + return accresult; +} + + +uint32_t +nfs3_other_accessbits (ia_prot_t prot, ia_type_t type, uint32_t request) +{ + uint32_t accresult = 0; + + if (IA_PROT_ROTH (prot) && (request & ACCESS3_READ)) + accresult |= ACCESS3_READ; + + if (request & ACCESS3_LOOKUP) + if (IA_ISDIR (type) && IA_PROT_ROTH (prot)) + accresult |= ACCESS3_LOOKUP; + + if (IA_PROT_WOTH (prot) && (request & ACCESS3_MODIFY)) + accresult |= ACCESS3_MODIFY; + + if (IA_PROT_WOTH (prot) && (request & ACCESS3_EXTEND)) + accresult |= ACCESS3_EXTEND; + + /* ACCESS3_DELETE is ignored for now since that requires + * knowing the permissions on the parent directory. + */ - /* lookup on directory allowed only in case of execute permission */ - if (accbits & POSIX_EXEC) - accresult |= (ACCESS3_EXECUTE | ACCESS3_LOOKUP); + if (request & ACCESS3_EXECUTE) + if (IA_PROT_XOTH (prot) && (!IA_ISDIR (type))) + accresult |= ACCESS3_EXECUTE; return accresult; } + uint32_t -nfs3_request_to_accessbits (int32_t accbits) +nfs3_superuser_accessbits (ia_prot_t prot, ia_type_t type, uint32_t request) { - uint32_t acc_request = 0; + uint32_t accresult = 0; + + if (request & ACCESS3_READ) + accresult |= ACCESS3_READ; + + if (request & ACCESS3_LOOKUP) + if (IA_ISDIR (type)) + accresult |= ACCESS3_LOOKUP; + + if (request & ACCESS3_MODIFY) + accresult |= ACCESS3_MODIFY; - if (accbits & ACCESS3_READ) - acc_request |= POSIX_READ; + if (request & ACCESS3_EXTEND) + accresult |= ACCESS3_EXTEND; - if (accbits & (ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE)) - acc_request |= POSIX_WRITE; + /* ACCESS3_DELETE is ignored for now since that requires + * knowing the permissions on the parent directory. + */ + + if (request & ACCESS3_EXECUTE) + if ((IA_PROT_XOTH (prot) || IA_PROT_XUSR (prot) || + IA_PROT_XGRP (prot)) && (!IA_ISDIR (type))) + accresult |= ACCESS3_EXECUTE; + + return accresult; +} - /* For lookup on directory check for execute permission */ - if (accbits & (ACCESS3_EXECUTE | ACCESS3_LOOKUP)) - acc_request |= POSIX_EXEC; - return acc_request; +uint32_t +nfs3_stat_to_accessbits (struct iatt *buf, uint32_t request, uid_t uid, + gid_t gid, gid_t *auxgids, int gids) +{ + uint32_t accresult = 0; + ia_prot_t prot = {0, }; + ia_type_t type = 0; + int testgid = -1; + int x = 0; + + prot = buf->ia_prot; + type = buf->ia_type; + + if (buf->ia_gid == gid) + testgid = gid; + else { + for (; x < gids; ++x) { + if (buf->ia_gid == auxgids[x]) { + testgid = buf->ia_gid; + break; + } + } + } + + if (uid == 0) + accresult = nfs3_superuser_accessbits (prot, type, request); + else if (buf->ia_uid == uid) + accresult = nfs3_owner_accessbits (prot, type, request); + else if ((testgid != -1) && (buf->ia_gid == testgid)) + accresult = nfs3_group_accessbits (prot, type, request); + else + accresult = nfs3_other_accessbits (prot, type, request); + + return accresult; } + + void -nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits) +nfs3_fill_access3res (access3res *res, nfsstat3 status, struct iatt *buf, + uint32_t accbits, uid_t uid, gid_t gid, + uint64_t deviceid, gid_t *gidarr, int gids) { + post_op_attr objattr; uint32_t accres = 0; memset (res, 0, sizeof (*res)); @@ -600,8 +737,11 @@ nfs3_fill_access3res (access3res *res, nfsstat3 status, int32_t accbits) if (status != NFS3_OK) return; - accres = nfs3_accessbits (accbits); + nfs3_map_deviceid_to_statdev (buf, deviceid); + objattr = nfs3_stat_to_post_op_attr (buf); + accres = nfs3_stat_to_accessbits (buf, accbits, uid, gid, gidarr, gids); + res->access3res_u.resok.obj_attributes = objattr; res->access3res_u.resok.access = accres; } @@ -680,7 +820,7 @@ nfs3_fill_entry3 (gf_dirent_t *entry, struct nfs3_fh *dfh) /* 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 + * sense the behavious we provide is similar to the output of the * command: "stat /.." */ entry->d_ino = nfs3_iatt_gfid_to_ino (&entry->d_stat); @@ -749,7 +889,7 @@ nfs3_fill_entryp3 (gf_dirent_t *entry, struct nfs3_fh *dirfh, uint64_t devid) /* 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 + * sense the behavious we provide is similar to the output of the * command: "stat /.." */ entry->d_ino = nfs3_iatt_gfid_to_ino (&entry->d_stat); @@ -1603,1804 +1743,694 @@ err: } -void -nfs3_stat_to_errstr (uint32_t xid, char *op, nfsstat3 stat, int pstat, - char *errstr) -{ - if ((!op) || (!errstr)) - return; - - sprintf (errstr, "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 (gf_log_loglevel < GF_LOG_DEBUG) - return; - - nfs3_fh_to_str (fh, 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) +/* When remove a file, we need to unref the cached fd for an inode but this + * needs to happen only when the file was in fact opened. However, it is + * possible that fd_lookup on a file returns an fd because the file was in + * process of being created(which also returns an fd) but since this fd was not + * opened through this path, in the NFS3 remove path, we'll end up removing the + * reference that belongs to someone else. That means, nfs3 remove path should + * not unref unless it is sure that the file was cached open also. If it was, + * only then perform the fd_unref, else not. + * + * We determine that using a flag in the inode context. + */ +int +nfs3_set_inode_opened (xlator_t *nfsxl, inode_t *inode) { - char fhstr[1024]; - - if (gf_log_loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, fhstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, name: %s", xid, - op, fhstr, name); -} + if ((!nfsxl) || (!inode)) + return -1; + inode_ctx_put (inode, nfsxl, GF_NFS3_FD_CACHED); -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 (gf_log_loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (src, sfhstr); - nfs3_fh_to_str (dst, 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); + return 0; } - -void -nfs3_log_create_call (uint32_t xid, struct nfs3_fh *fh, char *name, - createmode3 mode) +/* Returns 1 if inode was cached open, otherwise 0 */ +int +nfs3_cached_inode_opened (xlator_t *nfsxl, inode_t *inode) { - char fhstr[1024]; - char *modestr = NULL; - char exclmode[] = "EXCLUSIVE"; - char unchkd[] = "UNCHECKED"; - char guarded[] = "GUARDED"; - - if (gf_log_loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, 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); -} - + int ret = -1; + uint64_t cflag = 0; -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 ((!nfsxl) || (!inode)) + return -1; - if (gf_log_loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, fhstr); - if (type == NF3CHR) - modestr = chr; - else if (type == NF3BLK) - modestr = blk; - else if (type == NF3SOCK) - modestr = sock; - else - modestr = fifo; + ret = inode_ctx_get (inode, nfsxl, &cflag); + if (ret == -1) + ret = 0; + else if (cflag == GF_NFS3_FD_CACHED) + ret = 1; - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, MKNOD: args: %s, name: %s," - " type: %s", xid, fhstr, name, modestr); + return ret; } - -void -nfs3_log_symlink_call (uint32_t xid, struct nfs3_fh *fh, char *name, char *tgt) +int32_t +nfs3_dir_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd) { - char fhstr[1024]; - - if (gf_log_loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, fhstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, SYMLINK: args: %s, name: %s," - " target: %s", xid, fhstr, name, tgt); -} - + nfs3_call_state_t *cs = NULL; -void -nfs3_log_link_call (uint32_t xid, struct nfs3_fh *fh, char *name, - struct nfs3_fh *tgt) -{ - char dfhstr[1024]; - char tfhstr[1024]; + cs = frame->local; + if (op_ret == -1) { + cs->resolve_ret = -1; + cs->resolve_errno = op_errno; + nfs3_call_resume (cs); + goto err; + } - if (gf_log_loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, dfhstr); - nfs3_fh_to_str (tgt, tfhstr); - gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, LINK: args: %s, name: %s," - " target: %s", xid, dfhstr, name, tfhstr); + cs->fd = fd; /* Gets unrefd when the call state is wiped. */ + nfs3_set_inode_opened (cs->nfsx, cs->resolvedloc.inode); + gf_log (GF_NFS3, GF_LOG_TRACE, "FD_REF: %d", fd->refcount); + nfs3_call_resume (cs); +err: + return 0; } -void -nfs3_log_rw_call (uint32_t xid, char *op, struct nfs3_fh *fh, offset3 offt, - count3 count, int stablewrite) +int +__nfs3_dir_open_and_resume (nfs3_call_state_t *cs) { - char fhstr[1024]; + nfs_user_t nfu = {0, }; + int ret = -EFAULT; - if (gf_log_loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, 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"); + if (!cs) + return ret; + nfs_user_root_create (&nfu); + ret = nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_dir_open_cbk, cs); + return ret; } 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; +nfs3_dir_open_and_resume (nfs3_call_state_t *cs, nfs3_resume_fn_t resume) +{ + fd_t *fd = NULL; + int ret = -EFAULT; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; + if ((!cs)) + return ret; - default: - ll = GF_LOG_DEBUG; - break; + cs->resume_fn = resume; + gf_log (GF_NFS3, GF_LOG_TRACE, "Opening: %s", cs->resolvedloc.path); + fd = fd_lookup (cs->resolvedloc.inode, 0); + if (fd) { + gf_log (GF_NFS3, GF_LOG_TRACE, "fd found in state: ref: %d", fd->refcount); + cs->fd = fd; /* Gets unrefd when the call state is wiped. */ + cs->resolve_ret = 0; + nfs3_call_resume (cs); + ret = 0; + goto err; } - 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; + ret = __nfs3_dir_open_and_resume (cs); - 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; +err: + return ret; } 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; +nfs3_flush_call_state (nfs3_call_state_t *cs, fd_t *openedfd) +{ + if ((!cs)) + return -1; - default: - ll = GF_LOG_DEBUG; - break; + gf_log (GF_NFS3, GF_LOG_TRACE, "Calling resume"); + if (openedfd) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Opening uncached fd done: %d", + openedfd->refcount); + cs->fd = fd_ref (openedfd); + /* Set resove_ret to 0 so that the error checking in the resume + * callback results in a successful read reply when the fd was + * opened. If the fd opening failed, the resolve_ret is already + * set to -1 in nfs3_file_open_cbk, so that will result in an + * error being returned to the nfs client' read request. + */ + cs->resolve_ret = 0; } + list_del (&cs->openwait_q); + nfs3_call_resume (cs); - return ll; + return 0; } 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; +nfs3_flush_inode_queue (struct inode_op_queue *inode_q, fd_t *openedfd) +{ + nfs3_call_state_t *cstmp = NULL; + nfs3_call_state_t *cs = NULL; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; + if (!inode_q) + return -1; - default: - ll = GF_LOG_DEBUG; - break; - } + list_for_each_entry_safe (cs, cstmp, &inode_q->opq, openwait_q) + nfs3_flush_call_state (cs, openedfd); - return ll; + return 0; } 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; +nfs3_flush_open_wait_call_states (nfs3_call_state_t *cs, fd_t *openedfd) +{ + struct inode_op_queue *inode_q = NULL; + uint64_t ctxaddr = 0; + int ret = 0; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; + if (!cs) + return -1; - default: - ll = GF_LOG_DEBUG; - break; + gf_log (GF_NFS3, GF_LOG_TRACE, "Flushing call state"); + ret = inode_ctx_get (cs->resolvedloc.inode, cs->nfsx, &ctxaddr); + if (ret == -1) { + gf_log (GF_NFS3, GF_LOG_TRACE, "No inode queue present"); + goto out; } - 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; + inode_q = (struct inode_op_queue *)(long)ctxaddr; + if (!inode_q) + goto out; - default: - ll = GF_LOG_DEBUG; - break; + pthread_mutex_lock (&inode_q->qlock); + { + nfs3_flush_inode_queue (inode_q, openedfd); } + pthread_mutex_unlock (&inode_q->qlock); - return ll; +out: + return 0; } 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; +__nfs3_fdcache_update_entry (struct nfs3_state *nfs3, fd_t *fd) +{ + uint64_t ctxaddr = 0; + struct nfs3_fd_entry *fde = NULL; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; + if ((!nfs3) || (!fd)) + return -1; - default: - ll = GF_LOG_DEBUG; - break; + gf_log (GF_NFS3, GF_LOG_TRACE, "Updating fd: 0x%lx", (long int)fd); + fd_ctx_get (fd, nfs3->nfsx, &ctxaddr); + fde = (struct nfs3_fd_entry *)(long)ctxaddr; + if (fde) { + list_del (&fde->list); + list_add_tail (&fde->list, &nfs3->fdlru); } - return ll; + return 0; } 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; +nfs3_fdcache_update (struct nfs3_state *nfs3, fd_t *fd) +{ + if ((!nfs3) || (!fd)) + return -1; - default: - ll = GF_LOG_DEBUG; - break; + LOCK (&nfs3->fdlrulock); + { + __nfs3_fdcache_update_entry (nfs3, fd); } + UNLOCK (&nfs3->fdlrulock); - return ll; + return 0; } 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; +__nfs3_fdcache_remove_entry (struct nfs3_state *nfs3, struct nfs3_fd_entry *fde) +{ + if ((!fde) || (!nfs3)) + return 0; - default: - ll = GF_LOG_DEBUG; - break; - } + gf_log (GF_NFS3, GF_LOG_TRACE, "Removing fd: 0x%lx: %d", + (long int)fde->cachedfd, fde->cachedfd->refcount); + list_del (&fde->list); + fd_ctx_del (fde->cachedfd, nfs3->nfsx, NULL); + fd_unref (fde->cachedfd); + GF_FREE (fde); + --nfs3->fdcount; - return ll; + return 0; } 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; +nfs3_fdcache_remove (struct nfs3_state *nfs3, fd_t *fd) +{ + struct nfs3_fd_entry *fde = NULL; + uint64_t ctxaddr = 0; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; + if ((!nfs3) || (!fd)) + return -1; - default: - ll = GF_LOG_DEBUG; - break; + LOCK (&nfs3->fdlrulock); + { + fd_ctx_get (fd, nfs3->nfsx, &ctxaddr); + fde = (struct nfs3_fd_entry *)(long)ctxaddr; + __nfs3_fdcache_remove_entry (nfs3, fde); } + UNLOCK (&nfs3->fdlrulock); - return ll; + return 0; } 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; +__nfs3_fdcache_replace (struct nfs3_state *nfs3) +{ + struct nfs3_fd_entry *fde = NULL; + struct nfs3_fd_entry *tmp = NULL; - case NFS3ERR_NOTDIR: - ll = GF_LOG_WARNING; - break; + if (!nfs3) + return -1; - case NFS3ERR_ISDIR: - ll = GF_LOG_WARNING; - break; + if (nfs3->fdcount <= GF_NFS3_FDCACHE_SIZE) + return 0; - case NFS3ERR_INVAL: - ll = GF_LOG_WARNING; + list_for_each_entry_safe (fde, tmp, &nfs3->fdlru, list) break; - case NFS3ERR_FBIG: - ll = GF_LOG_WARNING; - break; + __nfs3_fdcache_remove_entry (nfs3, fde); - case NFS3ERR_MLINK: - ll = GF_LOG_WARNING; - break; + return 0; +} - case NFS3ERR_NOTEMPTY: - ll = GF_LOG_WARNING; - break; - case NFS3ERR_SERVERFAULT: - ll = GF_LOG_WARNING; - break; - case NFS3ERR_NOTSUPP: - ll = GF_LOG_WARNING; - break; +int +nfs3_fdcache_add (struct nfs3_state *nfs3, fd_t *fd) +{ + struct nfs3_fd_entry *fde = NULL; + int ret = -1; - case NFS3ERR_BADHANDLE: - ll = GF_LOG_WARNING; - break; + if ((!nfs3) || (!fd)) + return -1; - case NFS3ERR_STALE: - ll = GF_LOG_WARNING; - break; + fde = GF_CALLOC (1, sizeof (*fd), gf_nfs_mt_nfs3_fd_entry); + if (!fde) { + gf_log (GF_NFS3, GF_LOG_ERROR, "fd entry allocation failed"); + goto out; + } - default: - ll = GF_LOG_DEBUG; - break; + /* Already refd by caller. */ + fde->cachedfd = fd; + INIT_LIST_HEAD (&fde->list); + + LOCK (&nfs3->fdlrulock); + { + gf_log (GF_NFS3, GF_LOG_TRACE, "Adding fd: 0x%lx", + (long int) fd); + fd_ctx_set (fd, nfs3->nfsx, (uintptr_t)fde); + fd_bind (fd); + list_add_tail (&fde->list, &nfs3->fdlru); + ++nfs3->fdcount; + __nfs3_fdcache_replace (nfs3); } + UNLOCK (&nfs3->fdlrulock); - return ll; +out: + return ret; } -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; +int32_t +nfs3_file_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd) +{ + nfs3_call_state_t *cs = NULL; + struct nfs3_state *nfs3 = NULL; - default: - ll = GF_LOG_DEBUG; - break; + cs = frame->local; + if (op_ret == -1) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Opening uncached fd failed: " + "%s", strerror(op_errno)); + cs->resolve_ret = -1; + cs->resolve_errno = op_errno; + fd = NULL; + } else { + gf_log (GF_NFS3, GF_LOG_TRACE, "Opening uncached fd done: %d", + fd->refcount); } - return ll; + nfs3 = nfs_rpcsvc_request_program_private (cs->req); + /* Call states are flushed even when the opening of the file failed. + * This allows returning an error for each one of the file io requests + * that are currently queued waiting for the open to succeed. + */ + nfs3_flush_open_wait_call_states (cs, fd); + if (fd) + nfs3_fdcache_add (nfs3, fd); + return 0; } -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; +struct inode_op_queue * +__nfs3_get_inode_queue (nfs3_call_state_t *cs) +{ + struct inode_op_queue *inode_q = NULL; + int ret = -1; + uint64_t ctxaddr = 0; - case NFS3ERR_MLINK: - ll = GF_LOG_WARNING; - break; + ret = __inode_ctx_get (cs->resolvedloc.inode, cs->nfsx, &ctxaddr); + if (ret == 0) { + inode_q = (struct inode_op_queue *)(long)ctxaddr; + gf_log (GF_NFS3, GF_LOG_TRACE, "Inode queue already inited"); + goto err; + } - case NFS3ERR_SERVERFAULT: - ll = GF_LOG_WARNING; - break; + inode_q = GF_CALLOC (1, sizeof (*inode_q), gf_nfs_mt_inode_q); + if (!inode_q) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Memory allocation failed"); + goto err; + } - case NFS3ERR_NOTSUPP: - ll = GF_LOG_WARNING; - break; + gf_log (GF_NFS3, GF_LOG_TRACE, "Initing inode queue"); + INIT_LIST_HEAD (&inode_q->opq); + pthread_mutex_init (&inode_q->qlock, NULL); + __inode_ctx_put (cs->resolvedloc.inode, cs->nfsx, (uintptr_t)inode_q); - case NFS3ERR_BADHANDLE: - ll = GF_LOG_WARNING; - break; +err: + return inode_q; +} - case NFS3ERR_STALE: - ll = GF_LOG_WARNING; - break; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; +struct inode_op_queue * +nfs3_get_inode_queue (nfs3_call_state_t *cs) +{ + struct inode_op_queue *inode_q = NULL; - default: - ll = GF_LOG_DEBUG; - break; + LOCK (&cs->resolvedloc.inode->lock); + { + inode_q = __nfs3_get_inode_queue (cs); } + UNLOCK (&cs->resolvedloc.inode->lock); - return ll; + return inode_q; } -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; +#define GF_NFS3_FD_OPEN_INPROGRESS 1 +#define GF_NFS3_FD_NEEDS_OPEN 0 - case NFS3ERR_NOTSUPP: - ll = GF_LOG_WARNING; - break; - case NFS3ERR_BADHANDLE: - ll = GF_LOG_WARNING; - break; +int +__nfs3_queue_call_state (struct inode_op_queue *inode_q, nfs3_call_state_t *cs) +{ + int ret = -1; - case NFS3ERR_STALE: - ll = GF_LOG_WARNING; - break; + if (!inode_q) + goto err; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; + pthread_mutex_lock (&inode_q->qlock); + { + if (list_empty (&inode_q->opq)) { + gf_log (GF_NFS3, GF_LOG_TRACE, "First call in queue"); + ret = GF_NFS3_FD_NEEDS_OPEN; + } else + ret = GF_NFS3_FD_OPEN_INPROGRESS; - default: - ll = GF_LOG_DEBUG; - break; + gf_log (GF_NFS3, GF_LOG_TRACE, "Queueing call state"); + list_add_tail (&cs->openwait_q, &inode_q->opq); } + pthread_mutex_unlock (&inode_q->qlock); - return ll; +err: + return ret; } +/* Returns GF_NFS3_FD_NEEDS_OPEN if the current call is the first one to be + * queued. If so, the caller will need to send the open fop. If this is a + * non-first call to be queued, it means the fd opening is in progress and + * GF_NFS3_FD_OPEN_INPROGRESS is returned. + * + * Returns -1 on error. + */ 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; +nfs3_queue_call_state (nfs3_call_state_t *cs) +{ + struct inode_op_queue *inode_q = NULL; + int ret = -1; - default: - ll = GF_LOG_DEBUG; - break; + inode_q = nfs3_get_inode_queue (cs); + if (!inode_q) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Failed to get inode op queue"); + goto err; } - return ll; + ret = __nfs3_queue_call_state (inode_q, cs); + +err: + return ret; } 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; +__nfs3_file_open_and_resume (nfs3_call_state_t *cs) +{ + nfs_user_t nfu = {0, }; + int ret = -EFAULT; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; + if (!cs) + return ret; - default: - ll = GF_LOG_DEBUG; - break; + ret = nfs3_queue_call_state (cs); + if (ret == -1) { + gf_log (GF_NFS3, GF_LOG_ERROR, "Error queueing call state"); + ret = -EFAULT; + goto out; + } else if (ret == GF_NFS3_FD_OPEN_INPROGRESS) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Open in progress. Will wait."); + ret = 0; + goto out; } - return ll; + nfs_user_root_create (&nfu); + gf_log (GF_NFS3, GF_LOG_TRACE, "Opening uncached fd"); + ret = nfs_open (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, O_RDWR, + nfs3_file_open_cbk, cs); +out: + return ret; } -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; +fd_t * +nfs3_fdcache_getfd (struct nfs3_state *nfs3, inode_t *inode) +{ + fd_t *fd = NULL; - case NFS3ERR_ISDIR: - ll = GF_LOG_WARNING; - break; + if ((!nfs3) || (!inode)) + return NULL; - case NFS3ERR_INVAL: - ll = GF_LOG_WARNING; - break; + fd = fd_lookup (inode, 0); + if (fd) { + /* Already refd by fd_lookup, so no need to ref again. */ + gf_log (GF_NFS3, GF_LOG_TRACE, "fd found in state: %d", + fd->refcount); + nfs3_fdcache_update (nfs3, fd); + } else + gf_log (GF_NFS3, GF_LOG_TRACE, "fd not found in state"); - case NFS3ERR_NOSPC: - ll = GF_LOG_WARNING; - break; + return fd; +} - case NFS3ERR_ROFS: - ll = GF_LOG_WARNING; - break; - case NFS3ERR_FBIG: - ll = GF_LOG_WARNING; - break; - case NFS3ERR_MLINK: - ll = GF_LOG_WARNING; - break; +int +nfs3_file_open_and_resume (nfs3_call_state_t *cs, nfs3_resume_fn_t resume) +{ + fd_t *fd = NULL; + int ret = -EFAULT; - case NFS3ERR_NAMETOOLONG: - ll = GF_LOG_WARNING; - break; + if (!cs) + return ret; - case NFS3ERR_NOTEMPTY: - ll = GF_LOG_WARNING; - break; + cs->resume_fn = resume; + gf_log (GF_NFS3, GF_LOG_TRACE, "Opening: %s", cs->resolvedloc.path); + fd = nfs3_fdcache_getfd (cs->nfs3state, cs->resolvedloc.inode); + if (fd) { + cs->fd = fd; /* Gets unrefd when the call state is wiped. */ + cs->resolve_ret = 0; + nfs3_call_resume (cs); + ret = 0; + goto err; + } - case NFS3ERR_SERVERFAULT: - ll = GF_LOG_WARNING; - break; + ret = __nfs3_file_open_and_resume (cs); - case NFS3ERR_NOTSUPP: - ll = GF_LOG_WARNING; - break; +err: + return ret; +} - case NFS3ERR_BADHANDLE: - ll = GF_LOG_WARNING; - break; - case NFS3ERR_STALE: - ll = GF_LOG_WARNING; - break; +void +nfs3_stat_to_errstr (uint32_t xid, char *op, nfsstat3 stat, int pstat, + char *errstr) +{ + if ((!op) || (!errstr)) + return; - case NFS3ERR_DQUOT: - ll = GF_LOG_WARNING; - break; + sprintf (errstr, "XID: %x, %s: NFS: %d(%s), POSIX: %d(%s)", xid, op, + stat, nfsstat3_strerror (stat), pstat, strerror (pstat)); +} - default: - ll = GF_LOG_DEBUG; - break; - } +void +nfs3_log_common_call (uint32_t xid, char *op, struct nfs3_fh *fh) +{ + char fhstr[1024]; - return ll; + nfs3_fh_to_str (fh, fhstr); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s", xid, op, + fhstr); } -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) { +void +nfs3_log_fh_entry_call (uint32_t xid, char *op, struct nfs3_fh *fh, + char *name) +{ + char fhstr[1024]; - int ll = GF_LOG_DEBUG; + nfs3_fh_to_str (fh, fhstr); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, %s: args: %s, name: %s", xid, + op, fhstr, name); +} - switch (nfs_op) { - case NFS3_GETATTR: - ll = nfs3_getattr_loglevel (stat); - break; - case NFS3_SETATTR: - ll = nfs3_setattr_loglevel (stat); - break; +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]; - case NFS3_LOOKUP: - ll = nfs3_lookup_loglevel (stat); - break; + nfs3_fh_to_str (src, sfhstr); + nfs3_fh_to_str (dst, 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); +} - 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; +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"; - case NFS3_WRITE: - ll = nfs3_write_loglevel (stat); - break; + nfs3_fh_to_str (fh, fhstr); + if (mode == EXCLUSIVE) + modestr = exclmode; + else if (mode == GUARDED) + modestr = guarded; + else + modestr = unchkd; - case NFS3_CREATE: - ll = nfs3_create_loglevel (stat); - break; + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, CREATE: args: %s, name: %s," + " mode: %s", xid, fhstr, name, modestr); +} - case NFS3_MKDIR: - ll = nfs3_mkdir_loglevel (stat); - break; - case NFS3_SYMLINK: - ll = nfs3_symlink_loglevel (stat); - break; +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"; - case NFS3_MKNOD: - ll = nfs3_mknod_loglevel (stat); - break; + nfs3_fh_to_str (fh, fhstr); + if (type == NF3CHR) + modestr = chr; + else if (type == NF3BLK) + modestr = blk; + else if (type == NF3SOCK) + modestr = sock; + else + modestr = fifo; - case NFS3_REMOVE: - ll = nfs3_remove_loglevel (stat); - break; + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, MKNOD: args: %s, name: %s," + " type: %s", xid, fhstr, name, modestr); +} - 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; +void +nfs3_log_symlink_call (uint32_t xid, struct nfs3_fh *fh, char *name, char *tgt) +{ + char fhstr[1024]; - case NFS3_READDIR: - ll = nfs3_readdir_loglevel (stat); - break; + nfs3_fh_to_str (fh, fhstr); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, SYMLINK: args: %s, name: %s," + " target: %s", xid, fhstr, name, tgt); +} - case NFS3_READDIRP: - ll = nfs3_readdir_loglevel (stat); - break; - case NFS3_FSSTAT: - ll = nfs3_fsstat_loglevel (stat); - break; +void +nfs3_log_link_call (uint32_t xid, struct nfs3_fh *fh, char *name, + struct nfs3_fh *tgt) +{ + char dfhstr[1024]; + char tfhstr[1024]; - case NFS3_FSINFO: - ll = nfs3_fsstat_loglevel (stat); - break; + nfs3_fh_to_str (fh, dfhstr); + nfs3_fh_to_str (tgt, tfhstr); + gf_log (GF_NFS3, GF_LOG_DEBUG, "XID: %x, LINK: args: %s, name: %s," + " target: %s", xid, dfhstr, name, tfhstr); +} - case NFS3_PATHCONF: - ll = nfs3_fsstat_loglevel (stat); - break; - case NFS3_COMMIT: - ll = nfs3_write_loglevel (stat); - break; +void +nfs3_log_rw_call (uint32_t xid, char *op, struct nfs3_fh *fh, offset3 offt, + count3 count, int stablewrite) +{ + char fhstr[1024]; - default: - ll = GF_LOG_DEBUG; - break; - } + nfs3_fh_to_str (fh, 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"); - return ll; } + void -nfs3_log_common_res (uint32_t xid, int op, nfsstat3 stat, int pstat) +nfs3_log_common_res (uint32_t xid, char *op, nfsstat3 stat, int pstat) { char errstr[1024]; - int ll = nfs3_loglevel (op, stat); - if (gf_log_loglevel < ll) - return; - nfs3_stat_to_errstr (xid, nfs3op_strings[op].str, stat, pstat, errstr); - gf_log (GF_NFS3, ll, "%s", errstr); + nfs3_stat_to_errstr (xid, op, stat, pstat, errstr); + gf_log (GF_NFS3, GF_LOG_DEBUG, "%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 (gf_log_loglevel < ll) - return; nfs3_stat_to_errstr (xid, "READLINK", stat, pstat, errstr); - gf_log (GF_NFS3, ll, "%s, target: %s", - errstr, linkpath); + gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, target: %s", errstr, linkpath); } @@ -3409,18 +2439,14 @@ 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 (gf_log_loglevel < ll) - return; nfs3_stat_to_errstr (xid, "READ", stat, pstat, errstr); if (vec) - gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", is_eof:" + gf_log (GF_NFS3, GF_LOG_DEBUG, "%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:" + gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, count: %"PRIu32", is_eof:" " %d", errstr, count, is_eof); } @@ -3430,32 +2456,25 @@ 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 (gf_log_loglevel < ll) - return; nfs3_stat_to_errstr (xid, "WRITE", stat, pstat, errstr); - gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", %s,wverf: %"PRIu64 + gf_log (GF_NFS3, GF_LOG_DEBUG, "%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, +nfs3_log_newfh_res (uint32_t xid, char *op, nfsstat3 stat, int pstat, struct nfs3_fh *newfh) { char errstr[1024]; char fhstr[1024]; - int ll = nfs3_loglevel (op, stat); - if (gf_log_loglevel < ll) - return; - nfs3_stat_to_errstr (xid, nfs3op_strings[op].str, stat, pstat, errstr); + nfs3_stat_to_errstr (xid, op, stat, pstat, errstr); nfs3_fh_to_str (newfh, fhstr); - gf_log (GF_NFS3, nfs3_loglevel (op, stat), "%s, %s", errstr, fhstr); + gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, %s", errstr, fhstr); } @@ -3464,12 +2483,9 @@ 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 (gf_log_loglevel < ll) - return; nfs3_stat_to_errstr (xid, "READDIR", stat, pstat, errstr); - gf_log (GF_NFS3, ll, "%s, count: %"PRIu32", cverf: %"PRIu64 + gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, count: %"PRIu32", cverf: %"PRIu64 ", is_eof: %d", errstr, count, cverf, is_eof); } @@ -3479,12 +2495,9 @@ 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 (gf_log_loglevel < ll) - return; nfs3_stat_to_errstr (xid, "READDIRPLUS", stat, pstat, errstr); - gf_log (GF_NFS3, ll, "%s, dircount: %"PRIu32", maxcount: %" + gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, dircount: %"PRIu32", maxcount: %" PRIu32", cverf: %"PRIu64", is_eof: %d", errstr, dircount, maxcount, cverf, is_eof); } @@ -3494,12 +2507,9 @@ 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 (gf_log_loglevel < ll) - return; nfs3_stat_to_errstr (xid, "COMMIT", stat, pstat, errstr); - gf_log (GF_NFS3, ll, "%s, wverf: %"PRIu64, errstr, wverf); + gf_log (GF_NFS3, GF_LOG_DEBUG, "%s, wverf: %"PRIu64, errstr, wverf); } @@ -3509,9 +2519,6 @@ nfs3_log_readdir_call (uint32_t xid, struct nfs3_fh *fh, count3 dircount, { char fhstr[1024]; - if (gf_log_loglevel < GF_LOG_DEBUG) - return; - nfs3_fh_to_str (fh, fhstr); if (maxcount == 0) @@ -3533,11 +2540,9 @@ nfs3_fh_resolve_inode_done (nfs3_call_state_t *cs, inode_t *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"); + ret = nfs_inode_loc_fill (inode, &cs->resolvedloc); + if (ret < 0) goto err; - } nfs3_call_resume (cs); @@ -3545,6 +2550,55 @@ err: return ret; } +#define GF_NFS3_FHRESOLVE_FOUND 1 +#define GF_NFS3_FHRESOLVE_NOTFOUND 2 +#define GF_NFS3_FHRESOLVE_DIRFOUND 3 + +int +nfs3_fh_resolve_check_entry (struct nfs3_fh *fh, gf_dirent_t *candidate, + int hashidx) +{ + struct iatt *ia = NULL; + int ret = GF_NFS3_FHRESOLVE_NOTFOUND; + nfs3_hash_entry_t entryhash = 0; + + if ((!fh) || (!candidate)) + return ret; + + if ((strcmp (candidate->d_name, ".") == 0) || + (strcmp (candidate->d_name, "..") == 0)) + goto found_entry; + + ia = &candidate->d_stat; + if ((uuid_compare (candidate->d_stat.ia_gfid, fh->gfid)) == 0) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Found entry: gfid: %s, " + "name: %s, hashcount %d", + uuid_utoa (candidate->d_stat.ia_gfid), + candidate->d_name, hashidx); + ret = GF_NFS3_FHRESOLVE_FOUND; + goto found_entry; + } + + /* This condition ensures that we never have to be afraid of having + * a directory hash conflict with a file hash. The consequence of + * this condition is that we can now have unlimited files in a directory + * and upto 65536 sub-directories in a directory. + */ + if (!IA_ISDIR (candidate->d_stat.ia_type)) + goto found_entry; + entryhash = fh->entryhash[hashidx]; + if (entryhash == nfs3_fh_hash_entry (ia->ia_gfid)) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Found hash match: %s: %d, " + "hashidx: %d", candidate->d_name, entryhash, hashidx); + ret = GF_NFS3_FHRESOLVE_DIRFOUND; + goto found_entry; + } + +found_entry: + + return ret; +} + int32_t nfs3_fh_resolve_entry_lookup_cbk (call_frame_t *frame, void *cookie, @@ -3561,16 +2615,13 @@ nfs3_fh_resolve_entry_lookup_cbk (call_frame_t *frame, void *cookie, 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", + gf_log (GF_NFS3, GF_LOG_TRACE, "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) { @@ -3583,8 +2634,44 @@ err: } + +int32_t +nfs3_fh_resolve_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + gf_dirent_t *entries); + +int +nfs3_fh_resolve_found_entry (nfs3_call_state_t *cs, gf_dirent_t *candidate) +{ + int ret = 0; + nfs_user_t nfu = {0, }; + uuid_t gfid = {0, }; + + if ((!cs) || (!candidate)) + return -EFAULT; + + uuid_copy (gfid, cs->resolvedloc.inode->gfid); + nfs_loc_wipe (&cs->resolvedloc); + ret = nfs_entry_loc_fill (cs->vol->itable, gfid, candidate->d_name, + &cs->resolvedloc, NFS_RESOLVE_CREATE); + if (ret == -ENOENT) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Entry not in itable, needs" + " lookup"); + nfs_user_root_create (&nfu); + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_entry_lookup_cbk, + cs); + } else { + gf_log (GF_NFS3, GF_LOG_TRACE, "Entry got from itable"); + nfs3_call_resume (cs); + } + + return ret; +} + + int32_t -nfs3_fh_resolve_inode_lookup_cbk (call_frame_t *frame, void *cookie, +nfs3_fh_resolve_parent_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, @@ -3598,37 +2685,332 @@ nfs3_fh_resolve_inode_lookup_cbk (call_frame_t *frame, void *cookie, 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", + gf_log (GF_NFS3, GF_LOG_TRACE, "Lookup failed: %s: %s", cs->resolvedloc.path, strerror (op_errno)); nfs3_call_resume (cs); 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, 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; + inode_unref (linked_inode); } + nfs3_fh_resolve_entry_hard (cs); - /* 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) +err: + return 0; +} + + +int +nfs3_fh_resolve_found_parent (nfs3_call_state_t *cs, gf_dirent_t *candidate) +{ + int ret = 0; + nfs_user_t nfu = {0, }; + uuid_t gfid = {0, }; + + if ((!cs) || (!candidate)) + return -EFAULT; + + uuid_copy (gfid, cs->resolvedloc.inode->gfid); + nfs_loc_wipe (&cs->resolvedloc); + ret = nfs_entry_loc_fill (cs->vol->itable, gfid, candidate->d_name, + &cs->resolvedloc, NFS_RESOLVE_CREATE); + if (ret == -ENOENT) { + nfs_user_root_create (&nfu); + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_parent_lookup_cbk, + cs); + } else nfs3_fh_resolve_entry_hard (cs); - else - nfs3_call_resume (cs); + + return ret; +} + + +int +nfs3_fh_resolve_found (nfs3_call_state_t *cs, gf_dirent_t *candidate) +{ + int ret = 0; + + if ((!cs) || (!candidate)) + return -EFAULT; + + if (!cs->resolventry) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Candidate entry was found"); + ret = nfs3_fh_resolve_found_entry (cs, candidate); + } else { + gf_log (GF_NFS3, GF_LOG_TRACE, "Entry's parent was found"); + ret = nfs3_fh_resolve_found_parent (cs, candidate); + } + + return ret; +} + + +int32_t +nfs3_fh_resolve_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd) +{ + nfs3_call_state_t *cs = NULL; + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + + cs = frame->local; + cs->resolve_ret = op_ret; + cs->resolve_errno = op_errno; + + if (op_ret == -1) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Dir open failed: %s: %s", + cs->resolvedloc.path, strerror (op_errno)); + nfs3_call_resume (cs); + goto err; + } else + gf_log (GF_NFS3, GF_LOG_TRACE, "Reading directory: %s", + cs->resolvedloc.path); + + nfs_user_root_create (&nfu); + /* Keep this directory fd_t around till we have either: + * a. found the entry, + * b. exhausted all the entries, + * c. decide to step into a child directory. + * + * This decision is made in nfs3_fh_resolve_check_response. + */ + cs->resolve_dir_fd = fd; + gf_log (GF_NFS3, GF_LOG_TRACE, "resolve new fd refed: 0x%lx, ref: %d", + (long)cs->resolve_dir_fd, cs->resolve_dir_fd->refcount); + ret = nfs_readdirp (cs->nfsx, cs->vol, &nfu, fd, GF_NFS3_DTPREF, 0, + nfs3_fh_resolve_readdir_cbk, cs); + err: + return ret; +} + +int32_t +nfs3_fh_resolve_dir_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; + nfs_user_t nfu = {0, }; + 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, GF_LOG_TRACE, "Lookup failed: %s: %s", + cs->resolvedloc.path, strerror (op_errno)); + nfs3_call_resume (cs); + goto err; + } else + gf_log (GF_NFS3, GF_LOG_TRACE, "Dir will be opened: %s", + cs->resolvedloc.path); + + nfs_user_root_create (&nfu); + linked_inode = inode_link (inode, cs->resolvedloc.parent, + cs->resolvedloc.name, buf); + if (linked_inode) { + inode_lookup (linked_inode); + inode_unref (linked_inode); + } + + nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_opendir_cbk, cs); + +err: + return 0; +} + + +/* Validate the depth of the dir such that we do not end up opening and + * reading directories beyond those that are needed for resolving the file + * handle. + * Returns 1 if fh resolution can continue, 0 otherwise. + */ +int +nfs3_fh_resolve_validate_dirdepth (nfs3_call_state_t *cs) +{ + int ret = 1; + + if (!cs) + return 0; + + /* This condition will generally never be hit because the + * hash-matching scheme will prevent us from going into a + * directory that is not part of the hash-array. + */ + if (nfs3_fh_hash_index_is_beyond (&cs->resolvefh, cs->hashidx)) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Hash index is beyond: idx %d," + " fh idx: %d", cs->hashidx, cs->resolvefh.hashcount); + ret = 0; + goto out; + } + + if (cs->hashidx >= GF_NFSFH_MAXHASHES) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Hash index beyond max hashes:" + " hashidx %d, max: %d", cs->hashidx, + GF_NFSFH_MAXHASHES); + ret = 0; + goto out; + } + +out: + return ret; +} + + +int +nfs3_fh_resolve_dir_hard (nfs3_call_state_t *cs, uuid_t dirgfid, char *entry) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + + if (!cs) + return ret; + + cs->hashidx++; + nfs_loc_wipe (&cs->resolvedloc); + if (!nfs3_fh_resolve_validate_dirdepth (cs)) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Dir depth validation failed"); + nfs3_call_resume_estale (cs); + ret = 0; + goto out; + } + + nfs_user_root_create (&nfu); + gf_log (GF_NFS3, GF_LOG_TRACE, "FH hard dir resolution: gfid: %s, " + "entry: %s, next hashcount: %d", uuid_utoa (dirgfid), entry, + cs->hashidx); + ret = nfs_entry_loc_fill (cs->vol->itable, dirgfid, entry, + &cs->resolvedloc, NFS_RESOLVE_CREATE); + + if (ret == 0) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Dir will be opened: %s", + cs->resolvedloc.path); + ret = nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_opendir_cbk, cs); + } else if (ret == -ENOENT) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Dir needs lookup: %s", + cs->resolvedloc.path); + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_dir_lookup_cbk, cs); + } +out: + return ret; +} + + +/* + * Called in a recursive code path, so if another + * directory was opened in an earlier call during fh resolution, we must unref + * through this reference before opening another fd_t. + */ +#define nfs3_fh_resolve_close_cwd(cst) \ + do { \ + if ((cst)->resolve_dir_fd) { \ + gf_log (GF_NFS3, GF_LOG_TRACE, "resolve fd " \ + "unrefing: 0x%lx, ref: %d", \ + (long)(cst)->resolve_dir_fd, \ + (cst)->resolve_dir_fd->refcount); \ + fd_unref ((cst)->resolve_dir_fd); \ + } \ + } while (0) \ + + +int +nfs3_fh_resolve_check_response (nfs3_call_state_t *cs, gf_dirent_t *candidate, + int response, off_t last_offt) +{ + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + + if (!cs) + return ret; + + switch (response) { + + case GF_NFS3_FHRESOLVE_DIRFOUND: + nfs3_fh_resolve_close_cwd (cs); + nfs3_fh_resolve_dir_hard (cs, cs->resolvedloc.inode->gfid, + candidate->d_name); + break; + + case GF_NFS3_FHRESOLVE_FOUND: + nfs3_fh_resolve_close_cwd (cs); + nfs3_fh_resolve_found (cs, candidate); + break; + + case GF_NFS3_FHRESOLVE_NOTFOUND: + nfs_user_root_create (&nfu); + nfs_readdirp (cs->nfsx, cs->vol, &nfu, cs->resolve_dir_fd, + GF_NFS3_DTPREF, last_offt, + nfs3_fh_resolve_readdir_cbk, cs); + break; + } + return 0; } +int +nfs3_fh_resolve_search_dir (nfs3_call_state_t *cs, gf_dirent_t *entries) +{ + gf_dirent_t *candidate = NULL; + int ret = GF_NFS3_FHRESOLVE_NOTFOUND; + off_t lastoff = 0; + + if ((!cs) || (!entries)) + return -EFAULT; + + if (list_empty (&entries->list)) + goto not_found; + + list_for_each_entry (candidate, &entries->list, list) { + lastoff = candidate->d_off; + gf_log (GF_NFS3, GF_LOG_TRACE, "Candidate: %s, gfid: %s", + candidate->d_name, + uuid_utoa (candidate->d_stat.ia_gfid)); + ret = nfs3_fh_resolve_check_entry (&cs->resolvefh, candidate, + cs->hashidx); + if (ret != GF_NFS3_FHRESOLVE_NOTFOUND) + break; + } + +not_found: + nfs3_fh_resolve_check_response (cs, candidate, ret, lastoff); + return ret; +} + + +int32_t +nfs3_fh_resolve_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + gf_dirent_t *entries) +{ + nfs3_call_state_t *cs = NULL; + + cs = frame->local; + if (op_ret <= 0) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Directory read done: %s: %s", + cs->resolvedloc.path, strerror (op_ret)); + cs->resolve_ret = -1; + cs->resolve_errno = ESTALE; + nfs3_call_resume (cs); + goto err; + } + + nfs3_fh_resolve_search_dir (cs, entries); +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. @@ -3642,21 +3024,33 @@ nfs3_fh_resolve_inode_hard (nfs3_call_state_t *cs) 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; + cs->hashidx++; 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)); + if (!nfs3_fh_resolve_validate_dirdepth (cs)) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Dir depth validation failed"); + nfs3_call_resume_estale (cs); + ret = 0; goto out; } nfs_user_root_create (&nfu); - ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, - nfs3_fh_resolve_inode_lookup_cbk, cs); + gf_log (GF_NFS3, GF_LOG_TRACE, "FH hard resolution for: gfid 0x%s" + ", hashcount: %d, current hashidx %d", + uuid_utoa (cs->resolvefh.gfid), + cs->resolvefh.hashcount, cs->hashidx); + ret = nfs_root_loc_fill (cs->vol->itable, &cs->resolvedloc); + + if (ret == 0) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Dir will be opened: %s", + cs->resolvedloc.path); + ret = nfs_opendir (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_opendir_cbk, cs); + } else if (ret == -ENOENT) { + gf_log (GF_NFS3, GF_LOG_TRACE, "Dir needs lookup: %s", + cs->resolvedloc.path); + ret = nfs_lookup (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + nfs3_fh_resolve_dir_lookup_cbk, cs); + } out: return ret; @@ -3675,8 +3069,8 @@ nfs3_fh_resolve_entry_hard (nfs3_call_state_t *cs) 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); + ", entry: %s, hashidx: %d", uuid_utoa (cs->resolvefh.gfid), + cs->resolventry, cs->hashidx); ret = nfs_entry_loc_fill (cs->vol->itable, cs->resolvefh.gfid, cs->resolventry, &cs->resolvedloc, @@ -3685,22 +3079,13 @@ nfs3_fh_resolve_entry_hard (nfs3_call_state_t *cs) 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))) { + if (nfs3_lookup_op (cs)) { cs->lookuptype = GF_NFS3_FRESH; cs->resolve_ret = 0; nfs3_call_resume (cs); - } else { - cs->hardresolved = 1; + } else 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", @@ -3724,7 +3109,6 @@ nfs3_fh_resolve_inode (nfs3_call_state_t *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); @@ -3791,7 +3175,7 @@ nfs3_fh_resolve_root_lookup_cbk (call_frame_t *frame, void *cookie, cs->resolve_errno = op_errno; if (op_ret == -1) { - gf_log (GF_NFS3, GF_LOG_ERROR, "Root lookup failed: %s", + gf_log (GF_NFS3, GF_LOG_TRACE, "Root lookup failed: %s", strerror (op_errno)); goto err; } else @@ -3822,11 +3206,6 @@ nfs3_fh_resolve_root (nfs3_call_state_t *cs) 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); |
