gNFS: Subdir mount does not work on UDP proto

After enabling nfs.mount-udp, mounting a subdir on a volume over
NFS fails. Because mountudpproc3_mnt_3_svc() invokes nfs3_rootfh()
which internally calls mnt3_mntpath_to_export() to resolve the
mount path. mnt3_mntpath_to_export() just works if the mount path
requested is volume itself. It is not able to resolve, if the path
is a subdir inside the volume.

MOUNT over TCP uses mnt3_find_export() to resolve subdir path but
UDP can't use this routine because mnt3_find_export() needs the
req data (of type rpcsvc_request_t) and it's available only for
TCP version of RPC.

FIX:
(1) Use syncop_lookup() framework to resolve the MOUNT PATH by
    breaking it into components and resolve component-by-component.
    i.e. glfs_resolve_at () API from libgfapi shared object.
(2) If MOUNT PATH is subdir, then make sure subdir export is not
    disabled.
(3) Add auth mechanism to respect nfs.rpc-auth-allow/reject and
    subdir auth i.e. nfs.export-dir
(4) Enhanced error handling for MOUNT over UDP

Change-Id: I42ee69415d064b98af4f49773026562824f684d1
BUG: 1118311
Signed-off-by: Santosh Kumar Pradhan <spradhan@redhat.com>
Reviewed-on: http://review.gluster.org/8346
Reviewed-by: soumya k <skoduri@redhat.com>
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
Santosh Kumar Pradhan 2014-07-22 16:56:57 +05:30 committed by Niels de Vos
parent 1642ee54cf
commit ddb31110db
11 changed files with 501 additions and 151 deletions

View File

@ -226,4 +226,55 @@ int glfs_getxattr_process (void *value, size_t size, dict_t *xattr,
/* Sends RPC call to glusterd to fetch required volume info */
int glfs_get_volume_info (struct glfs *fs);
/*
SYNOPSIS
glfs_new_from_ctx: Creates a virtual mount object by taking a
glusterfs_ctx_t object.
DESCRIPTION
glfs_new_from_ctx() is not same as glfs_new(). It takes the
glusterfs_ctx_t object instead of creating one by glusterfs_ctx_new().
Again the usage is restricted to NFS MOUNT over UDP i.e. in
glfs_resolve_at() which would take fs object as input but never use
(purpose is not to change the ABI of glfs_resolve_at()).
PARAMETERS
@ctx: glusterfs_ctx_t object
RETURN VALUES
fs : Pointer to the newly created glfs_t object.
NULL : Otherwise.
*/
struct glfs *glfs_new_from_ctx (glusterfs_ctx_t *ctx);
/*
SYNOPSIS
glfs_free_from_ctx: Free up the memory occupied by glfs_t object
created by glfs_new_from_ctx().
DESCRIPTION
The glfs_t object allocated by glfs_new_from_ctx() must be released
by the caller using this routine. The usage is restricted to NFS
MOUNT over UDP i.e.
__mnt3udp_get_export_subdir_inode ()
=> glfs_resolve_at().
PARAMETERS
@fs: The glfs_t object to be deallocated.
RETURN VALUES
void
*/
void glfs_free_from_ctx (struct glfs *fs);
#endif /* !_GLFS_INTERNAL_H */

View File

@ -554,6 +554,43 @@ glfs_new (const char *volname)
}
struct glfs *
glfs_new_from_ctx (glusterfs_ctx_t *ctx)
{
struct glfs *fs = NULL;
if (!ctx)
return NULL;
fs = GF_CALLOC (1, sizeof (*fs), glfs_mt_glfs_t);
if (!fs)
return NULL;
fs->ctx = ctx;
(void) pthread_cond_init (&fs->cond, NULL);
(void) pthread_mutex_init (&fs->mutex, NULL);
INIT_LIST_HEAD (&fs->openfds);
return fs;
}
void
glfs_free_from_ctx (struct glfs *fs)
{
if (!fs)
return;
(void) pthread_cond_destroy (&fs->cond);
(void) pthread_mutex_destroy (&fs->mutex);
GF_FREE (fs);
}
int
glfs_set_volfile (struct glfs *fs, const char *volfile)
{

View File

@ -2366,21 +2366,18 @@ rpcsvc_combine_allow_reject_volume_check (int allow, int reject)
}
int
rpcsvc_auth_check (rpcsvc_t *svc, char *volname,
rpc_transport_t *trans)
rpcsvc_auth_check (rpcsvc_t *svc, char *volname, char *ipaddr)
{
int ret = RPCSVC_AUTH_REJECT;
int accept = RPCSVC_AUTH_REJECT;
int reject = RPCSVC_AUTH_REJECT;
char *hostname = NULL;
char *ip = NULL;
char client_ip[RPCSVC_PEER_STRLEN] = {0};
char *allow_str = NULL;
char *reject_str = NULL;
char *srchstr = NULL;
dict_t *options = NULL;
if (!svc || !volname || !trans)
if (!svc || !volname || !ipaddr)
return ret;
/* Fetch the options from svc struct and validate */
@ -2388,13 +2385,6 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname,
if (!options)
return ret;
ret = rpcsvc_transport_peername (trans, client_ip, RPCSVC_PEER_STRLEN);
if (ret != 0) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get remote addr: "
"%s", gai_strerror (ret));
return RPCSVC_AUTH_REJECT;
}
/* Accept if its the default case: Allow all, Reject none
* The default volfile always contains a 'allow *' rule
* for each volume. If allow rule is missing (which implies
@ -2435,13 +2425,9 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname,
return RPCSVC_AUTH_ACCEPT;
}
/* Non-default rule, authenticate */
if (!get_host_name (client_ip, &ip))
ip = client_ip;
/* addr-namelookup check */
if (svc->addr_namelookup == _gf_true) {
ret = gf_get_hostname_from_ip (ip, &hostname);
ret = gf_get_hostname_from_ip (ipaddr, &hostname);
if (ret) {
if (hostname)
GF_FREE (hostname);
@ -2454,10 +2440,10 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname,
}
accept = rpcsvc_transport_peer_check_allow (options, volname,
ip, hostname);
ipaddr, hostname);
reject = rpcsvc_transport_peer_check_reject (options, volname,
ip, hostname);
ipaddr, hostname);
if (hostname)
GF_FREE (hostname);
@ -2465,32 +2451,16 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname,
}
int
rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname,
rpc_transport_t *trans)
rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname, uint16_t port)
{
union gf_sock_union sock_union;
int ret = RPCSVC_AUTH_REJECT;
socklen_t sinsize = sizeof (&sock_union.sin);
char *srchstr = NULL;
char *valstr = NULL;
uint16_t port = 0;
gf_boolean_t insecure = _gf_false;
memset (&sock_union, 0, sizeof (sock_union));
if ((!svc) || (!volname) || (!trans))
if ((!svc) || (!volname))
return ret;
ret = rpcsvc_transport_peeraddr (trans, NULL, 0, &sock_union.storage,
sinsize);
if (ret != 0) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get peer addr: %s",
gai_strerror (ret));
ret = RPCSVC_AUTH_REJECT;
goto err;
}
port = ntohs (sock_union.sin.sin_port);
gf_log (GF_RPCSVC, GF_LOG_TRACE, "Client port: %d", (int)port);
/* If the port is already a privileged one, dont bother with checking
* options.

View File

@ -500,11 +500,10 @@ rpcsvc_transport_peeraddr (rpc_transport_t *trans, char *addrstr, int addrlen,
struct sockaddr_storage *returnsa, socklen_t sasize);
extern int
rpcsvc_auth_check (rpcsvc_t *svc, char *volname, rpc_transport_t *trans);
rpcsvc_auth_check (rpcsvc_t *svc, char *volname, char *ipaddr);
extern int
rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname,
rpc_transport_t *trans);
rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname, uint16_t port);
#define rpcsvc_request_seterr(req, err) (req)->rpc_err = err
#define rpcsvc_request_set_autherr(req, err) (req)->auth_err = err

View File

@ -19,6 +19,27 @@ TEST $CLI volume start $V0
EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available;
TEST mount_nfs $H0:/$V0 $N0 nolock,mountproto=udp,proto=tcp;
TEST mkdir -p $N0/foo/bar
TEST ls $N0/foo
TEST ls $N0/foo/bar
EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0
EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available;
TEST mount_nfs $H0:/$V0/foo $N0 nolock,mountproto=udp,proto=tcp;
EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0
EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available;
TEST mount_nfs $H0:/$V0/foo/bar $N0 nolock,mountproto=udp,proto=tcp;
EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0
TEST $CLI volume set $V0 nfs.addr-namelookup on
TEST $CLI volume set $V0 nfs.rpc-auth-allow $H0
EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available;
TEST mount_nfs $H0:/$V0/foo/bar $N0 nolock,mountproto=udp,proto=tcp;
EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0
TEST $CLI volume set $V0 nfs.rpc-auth-reject $H0
EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available;
TEST ! mount_nfs $H0:/$V0/foo/bar $N0 nolock,mountproto=udp,proto=tcp;
cleanup;

View File

@ -5,7 +5,8 @@ server_la_LDFLAGS = -module -avoid-version
server_la_SOURCES = nfs.c nfs-common.c nfs-fops.c nfs-inodes.c \
nfs-generics.c mount3.c nfs3-fh.c nfs3.c nfs3-helpers.c nlm4.c \
nlmcbk_svc.c mount3udp_svc.c acl3.c
server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
$(top_builddir)/api/src/libgfapi.la
noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h \
mount3.h nfs3-fh.h nfs3.h nfs3-helpers.h nfs-mem-types.h nlm4.h \
@ -14,6 +15,7 @@ noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h \
AM_CPPFLAGS = $(GF_CPPFLAGS) \
-DLIBDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/auth\" \
-I$(top_srcdir)/libglusterfs/src \
-I$(top_srcdir)/api/src \
-I$(nfsrpclibdir) -I$(CONTRIBDIR)/rbtree \
-I$(top_srcdir)/rpc/xdr/src/ -DDATADIR=\"$(localstatedir)\"

View File

@ -31,6 +31,8 @@
#include "nfs.h"
#include "common-utils.h"
#include "store.h"
#include "glfs-internal.h"
#include "glfs.h"
#include <errno.h>
#include <sys/socket.h>
@ -211,7 +213,10 @@ mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh, int *authflavor,
uint32_t fhlen = 0;
res.fhs_status = stat;
fhlen = nfs3_fh_compute_size (fh);
if (fh)
fhlen = nfs3_fh_compute_size ();
res.mountres3_u.mountinfo.fhandle.fhandle3_len = fhlen;
res.mountres3_u.mountinfo.fhandle.fhandle3_val = (char *)fh;
res.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = authflavor;
@ -1021,7 +1026,7 @@ mnt3_match_subnet_v4 (struct addrinfo *ai, uint32_t saddr, uint32_t mask)
* the directory or not. Client's IP address will be compared with
* allowed IP list or range present in mnt3_export structure.
*
* @param req - RPC request. This structure contains client's IP address.
* @param client_addr - This structure contains client's IP address.
* @param export - mnt3_export structure. Contains allowed IP list/range.
*
* @return 0 - on Success and -EACCES on failure.
@ -1029,12 +1034,11 @@ mnt3_match_subnet_v4 (struct addrinfo *ai, uint32_t saddr, uint32_t mask)
* TODO: Support IPv6 subnetwork
*/
int
mnt3_verify_auth (rpcsvc_request_t *req, struct mnt3_export *export)
mnt3_verify_auth (struct sockaddr_in *client_addr, struct mnt3_export *export)
{
int retvalue = -EACCES;
int ret = 0;
struct host_auth_spec *host = NULL;
struct sockaddr_in *client_addr = NULL;
struct sockaddr_in *allowed_addr = NULL;
struct addrinfo *allowed_addrinfo = NULL;
@ -1045,8 +1049,7 @@ mnt3_verify_auth (rpcsvc_request_t *req, struct mnt3_export *export)
};
/* Sanity check */
if ((NULL == req) ||
(NULL == req->trans) ||
if ((NULL == client_addr) ||
(NULL == export) ||
(NULL == export->hostspec)) {
gf_log (GF_MNT, GF_LOG_ERROR, "Invalid argument");
@ -1055,9 +1058,6 @@ mnt3_verify_auth (rpcsvc_request_t *req, struct mnt3_export *export)
host = export->hostspec;
/* Client's IP address. */
client_addr = (struct sockaddr_in *)(&(req->trans->peerinfo.sockaddr));
/*
* Currently IPv4 subnetwork is supported i.e. AF_INET.
* TODO: IPv6 subnetwork i.e. AF_INET6.
@ -1121,16 +1121,19 @@ int
mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms,
struct mnt3_export *exp, char *subdir)
{
mnt3_resolve_t *mres = NULL;
int ret = -EFAULT;
struct nfs3_fh pfh = GF_NFS3FH_STATIC_INITIALIZER;
mnt3_resolve_t *mres = NULL;
int ret = -EFAULT;
struct nfs3_fh pfh = GF_NFS3FH_STATIC_INITIALIZER;
struct sockaddr_in *sin = NULL;
if ((!req) || (!ms) || (!exp) || (!subdir))
return ret;
sin = (struct sockaddr_in *)(&(req->trans->peerinfo.sockaddr));
/* Need to check AUTH */
if (NULL != exp->hostspec) {
ret = mnt3_verify_auth (req, exp);
ret = mnt3_verify_auth (sin, exp);
if (0 != ret) {
gf_log (GF_MNT,GF_LOG_ERROR,
"AUTH verification failed");
@ -1149,15 +1152,17 @@ mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms,
mres->req = req;
strncpy (mres->remainingdir, subdir, MNTPATHLEN);
if (gf_nfs_dvm_off (nfs_state (ms->nfsx)))
pfh = nfs3_fh_build_indexed_root_fh (mres->mstate->nfsx->children, mres->exp->vol);
pfh = nfs3_fh_build_indexed_root_fh (
mres->mstate->nfsx->children,
mres->exp->vol);
else
pfh = nfs3_fh_build_uuid_root_fh (exp->volumeid);
mres->parentfh = pfh;
ret = __mnt3_resolve_subdir (mres);
if (ret < 0) {
gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s"
, mres->exp->expname);
gf_log (GF_MNT, GF_LOG_ERROR,
"Failed to resolve export dir: %s", mres->exp->expname);
GF_FREE (mres);
}
@ -1182,8 +1187,8 @@ mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms,
ret = mnt3_resolve_subdir (req, ms, exp, volume_subdir);
if (ret < 0) {
gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s"
, exp->expname);
gf_log (GF_MNT, GF_LOG_ERROR,
"Failed to resolve export dir: %s", exp->expname);
goto err;
}
@ -1241,45 +1246,100 @@ foundexp:
}
int
mnt3_check_client_net (struct mount3_state *ms, rpcsvc_request_t *req,
xlator_t *targetxl)
static int
mnt3_check_client_net_check (rpcsvc_t *svc, char *expvol,
char *ipaddr, uint16_t port)
{
int ret = RPCSVC_AUTH_REJECT;
rpcsvc_t *svc = NULL;
rpc_transport_t *trans = NULL;
struct sockaddr_storage sastorage = {0,};
char peer[RPCSVC_PEER_STRLEN] = {0,};
int ret = -1;
if ((!svc) || (!expvol) || (!ipaddr))
goto err;
if ((!ms) || (!req) || (!targetxl))
return -1;
svc = rpcsvc_request_service (req);
trans = rpcsvc_request_transport (req);
ret = rpcsvc_transport_peeraddr (trans, peer, RPCSVC_PEER_STRLEN,
&sastorage, sizeof (sastorage));
if (ret != 0) {
gf_log (GF_MNT, GF_LOG_WARNING, "Failed to get peer addr: %s",
gai_strerror (ret));
}
ret = rpcsvc_auth_check (svc, targetxl->name, trans);
ret = rpcsvc_auth_check (svc, expvol, ipaddr);
if (ret == RPCSVC_AUTH_REJECT) {
gf_log (GF_MNT, GF_LOG_INFO, "Peer %s not allowed", peer);
gf_log (GF_MNT, GF_LOG_INFO, "Peer %s not allowed", ipaddr);
goto err;
}
ret = rpcsvc_transport_privport_check (svc, targetxl->name,
rpcsvc_request_transport (req));
ret = rpcsvc_transport_privport_check (svc, expvol, port);
if (ret == RPCSVC_AUTH_REJECT) {
gf_log (GF_MNT, GF_LOG_INFO, "Peer %s rejected. Unprivileged "
"port not allowed", peer);
"port %d not allowed", ipaddr, port);
goto err;
}
ret = 0;
ret = RPCSVC_AUTH_ACCEPT;
err:
return ret;
}
static int
mnt3_check_client_net_tcp (rpcsvc_request_t *req, char *volname)
{
rpcsvc_t *svc = NULL;
rpc_transport_t *trans = NULL;
union gf_sock_union sock_union;
socklen_t socksize = sizeof (struct sockaddr_in);
char peer[RPCSVC_PEER_STRLEN] = {0,};
char *ipaddr = NULL;
uint16_t port = 0;
int ret = RPCSVC_AUTH_REJECT;
if ((!req) || (!volname))
goto err;
svc = rpcsvc_request_service (req);
trans = rpcsvc_request_transport (req);
if ((!svc) || (!trans))
goto err;
ret = rpcsvc_transport_peeraddr (trans, peer, RPCSVC_PEER_STRLEN,
&sock_union.storage, socksize);
if (ret != 0) {
gf_log (GF_MNT, GF_LOG_WARNING,
"Failed to get peer addr: %s",
gai_strerror (ret));
ret = RPCSVC_AUTH_REJECT;
goto err;
}
/* peer[] gets IP:PORT formar, slash the port out */
if (!get_host_name ((char *)peer, &ipaddr))
ipaddr = peer;
port = ntohs (sock_union.sin.sin_port);
ret = mnt3_check_client_net_check (svc, volname, ipaddr, port);
err:
return ret;
}
static int
mnt3_check_client_net_udp (struct svc_req *req, char *volname, xlator_t *nfsx)
{
rpcsvc_t *svc = NULL;
struct sockaddr_in *sin = NULL;
char ipaddr[INET_ADDRSTRLEN + 1] = {0, };
uint16_t port = 0;
int ret = RPCSVC_AUTH_REJECT;
struct nfs_state *nfs = NULL;
if ((!req) || (!volname) || (!nfsx))
goto err;
sin = svc_getcaller (req->rq_xprt);
if (!sin)
goto err;
(void) inet_ntop (AF_INET, &sin->sin_addr, ipaddr, INET_ADDRSTRLEN);
port = ntohs (sin->sin_port);
nfs = (struct nfs_state *)nfsx->private;
if (nfs != NULL)
svc = nfs->rpcsvc;
ret = mnt3_check_client_net_check (svc, volname, ipaddr, port);
err:
return ret;
}
@ -1289,7 +1349,7 @@ int
mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms,
char *subdir)
{
char volname[1024];
char volname[1024] = {0, };
struct mnt3_export *exp = NULL;
char *volname_ptr = NULL;
int ret = -ENOENT;
@ -1317,7 +1377,8 @@ mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms,
goto err;
}
if (mnt3_check_client_net (ms, req, exp->vol) == RPCSVC_AUTH_REJECT) {
ret = mnt3_check_client_net_tcp (req, exp->vol->name);
if (ret == RPCSVC_AUTH_REJECT) {
gf_log (GF_MNT, GF_LOG_DEBUG, "Client mount not allowed");
ret = -EACCES;
goto err;
@ -1415,7 +1476,7 @@ mnt3svc_mnt (rpcsvc_request_t *req)
* call to mnt3_find_export().
*
* This is subdir mount, we are already DONE!
* nfs_subvolume_started() and mnt3_check_client_net()
* nfs_subvolume_started() and mnt3_check_client_net_tcp()
* validation are done in mnt3_parse_dir_exports()
* which is invoked through mnt3_find_export().
*
@ -1433,7 +1494,7 @@ mnt3svc_mnt (rpcsvc_request_t *req)
goto mnterr;
}
ret = mnt3_check_client_net (ms, req, exp->vol);
ret = mnt3_check_client_net_tcp (req, exp->vol->name);
if (ret == RPCSVC_AUTH_REJECT) {
mntstat = MNT3ERR_ACCES;
gf_log (GF_MNT, GF_LOG_DEBUG, "Client mount not allowed");
@ -1926,61 +1987,242 @@ err:
return ret;
}
/* just declaring, definition is way down below */
rpcsvc_program_t mnt3prog;
/* nfs3_rootfh used by mount3udp thread needs to access mount3prog.private
* directly as we don't have nfs xlator pointer to dereference it. But thats OK
/*
* __mnt3udp_get_mstate() Fetches mount3_state from xlator
* Linkage: Static
* Usage: Used only for UDP MOUNT codepath
*/
struct nfs3_fh *
nfs3_rootfh (char* path)
static struct mount3_state *
__mnt3udp_get_mstate (xlator_t *nfsx)
{
struct nfs_state *nfs = NULL;
struct mount3_state *ms = NULL;
struct nfs3_fh *fh = NULL;
struct mnt3_export *exp = NULL;
if (nfsx == NULL)
return NULL;
nfs = (struct nfs_state *)nfsx->private;
if (nfs == NULL)
return NULL;
ms = (struct mount3_state *)nfs->mstate;
return ms;
}
static inode_t *
__mnt3udp_get_export_subdir_inode (struct svc_req *req, char *subdir,
char *expname, /* OUT */
struct mnt3_export *exp)
{
inode_t *inode = NULL;
char *tmp = NULL;
loc_t loc = {0, };
struct iatt buf = {0, };
int ret = -1;
glfs_t *fs = NULL;
if ((!req) || (!subdir) || (!expname) || (!exp))
return NULL;
/* AUTH check for subdir i.e. nfs.export-dir */
if (exp->hostspec) {
struct sockaddr_in *sin = svc_getcaller (req->rq_xprt);
ret = mnt3_verify_auth (sin, exp);
if (ret) {
gf_log (GF_MNT,GF_LOG_ERROR,
"AUTH(nfs.export-dir) verification failed");
errno = EACCES;
return NULL;
}
}
/*
* IMP: glfs_t fs object is not used by glfs_resolve_at (). The main
* purpose is to not change the ABI of glfs_resolve_at () and not to
* pass a NULL object.
*
* TODO: Instead of linking against libgfapi.so, just for one API
* i.e. glfs_resolve_at(), It would be cleaner if PATH name to
* inode resolution code can be moved to libglusterfs.so or so.
*/
fs = glfs_new_from_ctx (exp->vol->ctx);
if (!fs)
return NULL;
ret = glfs_resolve_at (fs, exp->vol, NULL, subdir,
&loc, &buf, 0 /* Follow link */,
0 /* Hard lookup */);
glfs_free_from_ctx (fs);
if (ret != 0) {
loc_wipe (&loc);
return NULL;
}
inode = inode_ref (loc.inode);
snprintf (expname, PATH_MAX, "/%s%s", exp->vol->name, loc.path);
loc_wipe (&loc);
return inode;
}
static inode_t *
__mnt3udp_get_export_volume_inode (struct svc_req *req, char *volpath,
char *expname, /* OUT */
struct mnt3_export *exp)
{
char *rpath = NULL;
inode_t *inode = NULL;
if ((!req) || (!volpath) || (!expname) || (!exp))
return NULL;
rpath = strchr (volpath, '/');
if (rpath == NULL)
rpath = "/";
inode = inode_from_path (exp->vol->itable, rpath);
snprintf (expname, PATH_MAX, "/%s", exp->vol->name);
return inode;
}
/*
* nfs3_rootfh() is used for NFS MOUNT over UDP i.e. mountudpproc3_mnt_3_svc().
* Especially in mount3udp_thread() THREAD. Gluster NFS starts this thread
* when nfs.mount-udp is ENABLED (set to TRUE/ON).
*/
struct nfs3_fh *
nfs3_rootfh (struct svc_req *req, xlator_t *nfsx,
char *path, char *expname /* OUT */)
{
struct nfs3_fh *fh = NULL;
inode_t *inode = NULL;
struct mnt3_export *exp = NULL;
struct mount3_state *ms = NULL;
struct nfs_state *nfs = NULL;
int mnt3type = MNT3_EXPTYPE_DIR;
int ret = RPCSVC_AUTH_REJECT;
if ((!req) || (!nfsx) || (!path) || (!expname)) {
errno = EFAULT;
return NULL;
}
/*
* 1. First check if the MOUNT is for whole volume.
* i.e. __mnt3udp_get_export_volume_inode ()
* 2. If NOT, then TRY for SUBDIR MOUNT.
* i.e. __mnt3udp_get_export_subdir_inode ()
* 3. If a subdir is exported using nfs.export-dir,
* then the mount type would be MNT3_EXPTYPE_DIR,
* so make sure to find the proper path to be
* resolved using __volume_subdir()
* 3. Make sure subdir export is allowed.
*/
ms = __mnt3udp_get_mstate(nfsx);
if (!ms) {
errno = EFAULT;
return NULL;
}
ms = mnt3prog.private;
exp = mnt3_mntpath_to_export (ms, path);
if (exp == NULL)
if (exp != NULL)
mnt3type = exp->exptype;
if (mnt3type == MNT3_EXPTYPE_DIR) {
char volname [MNTPATHLEN] = {0, };
char *volptr = volname;
/* Subdir export (nfs3.export-dirs) check */
if (!gf_mnt3_export_dirs(ms)) {
errno = EACCES;
return NULL;
}
path = __volume_subdir (path, &volptr);
if (exp == NULL)
exp = mnt3_mntpath_to_export (ms, volname);
}
if (exp == NULL) {
errno = ENOENT;
return NULL;
}
nfs = (struct nfs_state *)nfsx->private;
if (!nfs_subvolume_started (nfs, exp->vol)) {
errno = ENOENT;
return NULL;
}
/* AUTH check: respect nfs.rpc-auth-allow/reject */
ret = mnt3_check_client_net_udp (req, exp->vol->name, nfsx);
if (ret == RPCSVC_AUTH_REJECT) {
errno = EACCES;
return NULL;
}
switch (mnt3type) {
case MNT3_EXPTYPE_VOLUME:
inode = __mnt3udp_get_export_volume_inode (req, path,
expname, exp);
break;
case MNT3_EXPTYPE_DIR:
inode = __mnt3udp_get_export_subdir_inode (req, path,
expname, exp);
break;
default:
/* Never reachable */
gf_log (GF_MNT, GF_LOG_ERROR, "Unknown MOUNT3 type");
errno = EFAULT;
goto err;
}
tmp = (char *)path;
tmp = strchr (tmp, '/');
if (tmp == NULL)
tmp = "/";
inode = inode_from_path (exp->vol->itable, tmp);
if (inode == NULL)
if (inode == NULL) {
/* Don't over-write errno */
if (!errno)
errno = ENOENT;
goto err;
}
/* Build the inode from FH */
fh = GF_CALLOC (1, sizeof(*fh), gf_nfs_mt_nfs3_fh);
if (fh == NULL)
if (fh == NULL) {
errno = ENOMEM;
goto err;
nfs3_build_fh (inode, exp->volumeid, fh);
}
(void) nfs3_build_fh (inode, exp->volumeid, fh);
err:
if (inode)
inode_unref (inode);
return fh;
}
int
mount3udp_add_mountlist (char *host, dirpath *expname)
mount3udp_add_mountlist (xlator_t *nfsx, char *host, char *export)
{
struct mountentry *me = NULL;
struct mount3_state *ms = NULL;
char *export = NULL;
ms = mnt3prog.private;
if ((!host) || (!export) || (!nfsx))
return -1;
ms = __mnt3udp_get_mstate (nfsx);
if (!ms)
return -1;
me = GF_CALLOC (1, sizeof (*me), gf_nfs_mt_mountentry);
if (!me)
return -1;
export = (char *)expname;
while (*export == '/')
export++;
strncpy (me->exname, export, MNTPATHLEN);
strncpy (me->hostname, host, MNTPATHLEN);
@ -1995,15 +2237,17 @@ mount3udp_add_mountlist (char *host, dirpath *expname)
}
int
mount3udp_delete_mountlist (char *hostname, dirpath *expname)
mount3udp_delete_mountlist (xlator_t *nfsx, char *hostname, char *export)
{
struct mount3_state *ms = NULL;
char *export = NULL;
ms = mnt3prog.private;
export = (char *)expname;
while (*export == '/')
export++;
if ((!hostname) || (!export) || (!nfsx))
return -1;
ms = __mnt3udp_get_mstate (nfsx);
if (!ms)
return -1;
mnt3svc_umount (ms, export, hostname);
return 0;
}

View File

@ -23,49 +23,73 @@
#include <netinet/in.h>
extern struct nfs3_fh* nfs3_rootfh (char *dp);
extern mountres3 mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh,
int *authflavor, u_int aflen);
extern struct nfs3_fh*
nfs3_rootfh (struct svc_req *req, xlator_t *nfsx, char *dp, char *expname);
extern mountres3
mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh,
int *authflavor, u_int aflen);
extern int
mount3udp_add_mountlist (char *host, dirpath *expname);
mount3udp_add_mountlist (xlator_t *nfsx, char *host, char *expname);
extern int
mount3udp_delete_mountlist (char *host, dirpath *expname);
mount3udp_delete_mountlist (xlator_t *nfsx, char *host, char *expname);
extern mountstat3
mnt3svc_errno_to_mnterr (int32_t errnum);
/* only this thread will use this, no locking needed */
char mnthost[INET_ADDRSTRLEN+1];
#define MNT3UDP_AUTH_LEN 1 /* Only AUTH_UNIX for now */
mountres3 *
mountudpproc3_mnt_3_svc(dirpath **dpp, struct svc_req *req)
{
struct mountres3 *res = NULL;
int *autharr = NULL;
struct nfs3_fh *fh = NULL;
char *tmp = NULL;
char *mpath = NULL;
xlator_t *nfsx = THIS;
char expname[PATH_MAX] = {0, };
mountstat3 stat = MNT3ERR_SERVERFAULT;
tmp = (char *)*dpp;
while (*tmp == '/')
tmp++;
fh = nfs3_rootfh (tmp);
if (fh == NULL) {
gf_log (GF_MNT, GF_LOG_DEBUG, "unable to get fh for %s", tmp);
goto err;
}
errno = 0; /* RESET errno */
mpath = (char *)*dpp;
while (*mpath == '/')
mpath++;
res = GF_CALLOC (1, sizeof(*res), gf_nfs_mt_mountres3);
if (res == NULL) {
gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory");
gf_log (GF_MNT, GF_LOG_ERROR, "Unable to allocate memory");
goto err;
}
autharr = GF_CALLOC (1, sizeof(*autharr), gf_nfs_mt_int);
autharr = GF_CALLOC (MNT3UDP_AUTH_LEN, sizeof(int), gf_nfs_mt_int);
if (autharr == NULL) {
gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory");
gf_log (GF_MNT, GF_LOG_ERROR, "Unable to allocate memory");
goto err;
}
autharr[0] = AUTH_UNIX;
*res = mnt3svc_set_mountres3 (MNT3_OK, fh, autharr, 1);
mount3udp_add_mountlist (mnthost, *dpp);
fh = nfs3_rootfh (req, nfsx, mpath, (char *)expname);
/* FAILURE: No FH */
if (fh == NULL) {
gf_log (GF_MNT, GF_LOG_ERROR, "Unable to get fh for %s", mpath);
if (errno)
stat = mnt3svc_errno_to_mnterr (errno);
*res = mnt3svc_set_mountres3 (stat, NULL /* fh */,
autharr, MNT3UDP_AUTH_LEN);
return res;
}
/* SUCCESS */
stat = MNT3_OK;
*res = mnt3svc_set_mountres3 (stat, fh, autharr, MNT3UDP_AUTH_LEN);
(void) mount3udp_add_mountlist (nfsx, mnthost, (char *) expname);
return res;
err:
@ -79,14 +103,16 @@ mountstat3 *
mountudpproc3_umnt_3_svc(dirpath **dp, struct svc_req *req)
{
mountstat3 *stat = NULL;
char *mpath = (char *) *dp;
xlator_t *nfsx = THIS;
stat = GF_CALLOC (1, sizeof(mountstat3), gf_nfs_mt_mountstat3);
if (stat == NULL) {
gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory");
gf_log (GF_MNT, GF_LOG_ERROR, "Unable to allocate memory");
return NULL;
}
*stat = MNT3_OK;
mount3udp_delete_mountlist (mnthost, *dp);
(void) mount3udp_delete_mountlist (nfsx, mnthost, mpath);
return stat;
}
@ -147,7 +173,7 @@ mountudp_program_3(struct svc_req *rqstp, register SVCXPRT *transp)
}
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument,
(caddr_t) &argument)) {
gf_log (GF_MNT, GF_LOG_ERROR, "unable to free arguments");
gf_log (GF_MNT, GF_LOG_ERROR, "Unable to free arguments");
}
if (result == NULL)
return;
@ -176,8 +202,8 @@ mount3udp_thread (void *argv)
GF_ASSERT (nfsx);
if (glusterfs_this_set(nfsx)) {
gf_log (GF_MNT, GF_LOG_ERROR, "failed to set xlator, "
"nfs.mount-udp will not work");
gf_log (GF_MNT, GF_LOG_ERROR,
"Failed to set xlator, nfs.mount-udp will not work");
return NULL;
}

View File

@ -182,7 +182,7 @@ nfs3_fh_build_child_fh (struct nfs3_fh *parent, struct iatt *newstat,
uint32_t
nfs3_fh_compute_size (struct nfs3_fh *fh)
nfs3_fh_compute_size ()
{
return GF_NFSFH_STATIC_SIZE;
}

View File

@ -66,7 +66,7 @@ struct nfs3_fh {
#define GF_NFS3FH_STATIC_INITIALIZER {{0},}
extern uint32_t
nfs3_fh_compute_size (struct nfs3_fh *fh);
nfs3_fh_compute_size ();
extern uint16_t
nfs3_fh_hash_entry (uuid_t gfid);

View File

@ -424,7 +424,7 @@ nfs3_fill_lookup3res_success (lookup3res *res, nfsstat3 stat,
res->status = stat;
if (fh) {
res->lookup3res_u.resok.object.data.data_val = (void *)fh;
fhlen = nfs3_fh_compute_size (fh);
fhlen = nfs3_fh_compute_size ();
res->lookup3res_u.resok.object.data.data_len = fhlen;
}
@ -721,7 +721,7 @@ nfs3_fill_post_op_fh3 (struct nfs3_fh *fh, post_op_fh3 *pfh)
return;
pfh->handle_follows = 1;
fhlen = nfs3_fh_compute_size (fh);
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;
}