diff options
-rw-r--r-- | xlators/nfs/server/src/mount3.c | 694 | ||||
-rw-r--r-- | xlators/nfs/server/src/mount3.h | 36 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-mem-types.h | 2 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs.c | 22 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs3-fh.c | 3 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs3-fh.h | 2 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs3.c | 2 |
7 files changed, 712 insertions, 49 deletions
diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c index 9b287cf907e..b943d1290c3 100644 --- a/xlators/nfs/server/src/mount3.c +++ b/xlators/nfs/server/src/mount3.c @@ -175,19 +175,19 @@ mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh, int *authflavor, int mnt3svc_update_mountlist (struct mount3_state *ms, rpcsvc_request_t *req, - xlator_t *exportxl) + char *expname) { struct mountentry *me = NULL; int ret = -1; - if ((!ms) || (!req) || (!exportxl)) + if ((!ms) || (!req) || (!expname)) return -1; me = (struct mountentry *)GF_CALLOC (1, sizeof (*me), gf_nfs_mt_mountentry); if (!me) return -1; - strcpy (me->exname, exportxl->name); + strcpy (me->exname, expname); INIT_LIST_HEAD (&me->mlist); /* Must get the IP or hostname of the client so we * can map it into the mount entry. @@ -243,8 +243,8 @@ mnt3svc_lookup_mount_cbk (call_frame_t *frame, void *cookie, if (status != MNT3_OK) goto xmit_res; - fh = nfs3_fh_build_root_fh (ms->nfsx->children, this, *buf); - mnt3svc_update_mountlist (ms, req, this); + fh = nfs3_fh_build_root_fh (ms->nfsx->children, this); + mnt3svc_update_mountlist (ms, req, this->name); xmit_res: gf_log (GF_MNT, GF_LOG_DEBUG, "Mount reply status: %d", status); if (op_ret == 0) { @@ -261,26 +261,423 @@ xmit_res: int -mnt3svc_mount (rpcsvc_request_t *req, xlator_t *nfsx, xlator_t * xl) +mnt3_match_dirpath_export (char *expname, char *dirpath) { - loc_t oploc = {0, }; - int ret = -1; + int ret = 0; + int dlen = 0; + + if ((!expname) || (!dirpath)) + return 0; + + /* Some clients send a dirpath for mount that includes the slash at the + * end. String compare for searching the export will fail because our + * exports list does not include that slash. Remove the slash to + * compare. + */ + dlen = strlen (dirpath); + if (dirpath [dlen - 1] == '/') + dirpath [dlen - 1] = '\0'; + + if (dirpath[0] != '/') + expname++; + + if (strcmp (expname, dirpath) == 0) + ret = 1; + + return ret; +} + + +int +mnt3svc_mount_inode (rpcsvc_request_t *req, struct mount3_state *ms, + xlator_t * xl, inode_t *exportinode) +{ + int ret = -EFAULT; nfs_user_t nfu = {0, }; + loc_t exportloc = {0, }; - if ((!req) || (!xl)) + if ((!req) || (!xl) || (!ms) || (!exportinode)) return ret; - ret = nfs_ino_loc_fill (xl->itable, 1, 0, &oploc); + ret = nfs_inode_loc_fill (exportinode, &exportloc); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Loc fill failed for export inode" + ": ino %"PRIu64", gen: %"PRIu64", volume: %s", + exportinode->ino, exportinode->generation, xl->name); + goto err; + } + /* To service the mount request, all we need to do * is to send a lookup fop that returns the stat * for the root of the child volume. This is * used to build the root fh sent to the client. */ nfs_request_user_init (&nfu, req); - ret = nfs_lookup (nfsx, xl, &nfu, &oploc, mnt3svc_lookup_mount_cbk, - (void *)req); - nfs_loc_wipe (&oploc); + ret = nfs_lookup (ms->nfsx, xl, &nfu, &exportloc, + mnt3svc_lookup_mount_cbk, (void *)req); + + nfs_loc_wipe (&exportloc); +err: + return ret; +} + + +/* For a volume mount request, we just have to create loc on the root inode, + * and send a lookup. In the lookup callback the mount reply is send along with + * the file handle. + */ +int +mnt3svc_volume_mount (rpcsvc_request_t *req, struct mount3_state *ms, + struct mnt3_export *exp) +{ + inode_t *exportinode = NULL; + int ret = -EFAULT; + + if ((!req) || (!exp) || (!ms)) + return ret; + + exportinode = inode_get (exp->vol->itable, 1, 0); + if (!exportinode) { + gf_log (GF_MNT, GF_LOG_ERROR, "Faild to get root inode"); + ret = -ENOENT; + goto err; + } + + ret = mnt3svc_mount_inode (req, ms, exp->vol, exportinode); + inode_unref (exportinode); + +err: + return ret; +} + + +/* The catch with directory exports is that the first component of the export + * name will be the name of the volume. + * Any lookup that needs to be performed to build the directory's file handle + * needs to start from the directory path from the root of the volume. For that + * we need to strip out the volume name first. + */ +char * +__volume_subdir (char *dirpath) +{ + char *subdir = NULL; + + if (!dirpath) + return NULL; + + if (dirpath[0] == '/') + dirpath++; + + subdir = index (dirpath, (int)'/'); + + return subdir; +} + + +void +mnt3_resolve_state_wipe (mnt3_resolve_t *mres) +{ + if (!mres) + return; + + nfs_loc_wipe (&mres->resolveloc); + GF_FREE (mres); + +} + + +/* Sets up the component argument to contain the next component in the path and + * sets up path as an absolute path starting from the next component. + */ +char * +__setup_next_component (char *path, char *component) +{ + char *comp = NULL; + char *nextcomp = NULL; + + if ((!path) || (!component)) + return NULL; + + strcpy (component, path); + comp = index (component, (int)'/'); + if (!comp) + goto err; + + comp++; + nextcomp = index (comp, (int)'/'); + if (nextcomp) { + strcpy (path, nextcomp); + *nextcomp = '\0'; + } else + path[0] = '\0'; + +err: + return comp; +} + +int32_t +mnt3_resolve_subdir_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); + +/* There are multiple components in the directory export path and each one + * needs to be looked up one after the other. + */ +int +__mnt3_resolve_export_subdir_comp (mnt3_resolve_t *mres) +{ + char dupsubdir[MNTPATHLEN]; + char *nextcomp = NULL; + int ret = -EFAULT; + uint64_t parino = 0; + uint64_t pargen = 0; + nfs_user_t nfu = {0, }; + + if (!mres) + return ret; + + nextcomp = __setup_next_component (mres->remainingdir, dupsubdir); + if (!nextcomp) + goto err; + + parino = mres->resolveloc.inode->ino; + pargen = mres->resolveloc.inode->generation; + /* Wipe the contents of the previous component */ + nfs_loc_wipe (&mres->resolveloc); + ret = nfs_entry_loc_fill (mres->exp->vol->itable, parino, pargen, + nextcomp, &mres->resolveloc, + NFS_RESOLVE_CREATE); + if ((ret < 0) && (ret != -2)) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve and create " + "inode: parent %"PRIu64", gen: %"PRIu64", entry %s", + parino, pargen, nextcomp); + ret = -EFAULT; + goto err; + } + + nfs_request_user_init (&nfu, mres->req); + ret = nfs_lookup (mres->mstate->nfsx, mres->exp->vol, &nfu, + &mres->resolveloc, mnt3_resolve_subdir_cbk, mres); + +err: + return ret; +} + + +int32_t +mnt3_resolve_subdir_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) +{ + mnt3_resolve_t *mres = NULL; + mountstat3 mntstat = MNT3ERR_SERVERFAULT; + struct nfs3_fh fh = {{0}, }; + int autharr[10]; + int autharrlen = 0; + rpcsvc_t *svc = NULL; + mountres3 res = {0, }; + + mres = frame->local; + + if (op_ret == -1) { + mntstat = mnt3svc_errno_to_mnterr (op_errno); + goto err; + } + + inode_link (mres->resolveloc.inode, mres->resolveloc.parent, + mres->resolveloc.name, buf); + + nfs3_fh_build_child_fh (&mres->parentfh, buf, &fh); + if (strlen (mres->remainingdir) <= 0) { + op_ret = -1; + mntstat = MNT3_OK; + mnt3svc_update_mountlist (mres->mstate, mres->req, + mres->exp->expname); + goto err; + } + + mres->parentfh = fh; + op_ret = __mnt3_resolve_export_subdir_comp (mres); + if (op_ret < 0) + mntstat = mnt3svc_errno_to_mnterr (-op_ret); +err: + if (op_ret == -1) { + gf_log (GF_MNT, GF_LOG_DEBUG, "Mount reply status: %d", + mntstat); + svc = rpcsvc_request_service (mres->req); + autharrlen = rpcsvc_auth_array (svc, this->name, autharr, 10); + + res = mnt3svc_set_mountres3 (mntstat, &fh, autharr, autharrlen); + mnt3svc_submit_reply (mres->req, (void *)&res, + (mnt3_serializer)xdr_serialize_mountres3); + mnt3_resolve_state_wipe (mres); + } + + return 0; +} + + + +/* We will always have to perform a hard lookup on all the components of a + * directory export for a mount request because in the mount reply we need the + * file handle of the directory. Our file handle creation code is designed with + * the assumption that to build a child file/dir fh, we'll always have the + * parent dir's fh available so that we may copy the hash array of the previous + * dir levels. + * + * Since we do not store the file handles anywhere, for every mount request we + * must resolve the file handles of every component so that the parent dir file + * of the exported directory can be built. + */ +int +__mnt3_resolve_export_subdir (mnt3_resolve_t *mres) +{ + char dupsubdir[MNTPATHLEN]; + char *firstcomp = NULL; + int ret = -EFAULT; + nfs_user_t nfu = {0, }; + + if (!mres) + return ret; + + firstcomp = __setup_next_component (mres->remainingdir, dupsubdir); + if (!firstcomp) + goto err; + + ret = nfs_entry_loc_fill (mres->exp->vol->itable, 1, 0, firstcomp, + &mres->resolveloc, NFS_RESOLVE_CREATE); + if ((ret < 0) && (ret != -2)) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve and create " + "inode for volume root: %s", mres->exp->vol->name); + ret = -EFAULT; + goto err; + } + + nfs_request_user_init (&nfu, mres->req); + ret = nfs_lookup (mres->mstate->nfsx, mres->exp->vol, &nfu, + &mres->resolveloc, mnt3_resolve_subdir_cbk, mres); + +err: + return ret; +} + + +int +mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms, + struct mnt3_export *exp) +{ + mnt3_resolve_t *mres = NULL; + char *volume_subdir = NULL; + int ret = -EFAULT; + + if ((!req) || (!ms) || (!exp)) + return ret; + + volume_subdir = __volume_subdir (exp->expname); + if (!volume_subdir) + goto err; + + mres = GF_CALLOC (1, sizeof (mnt3_resolve_t), gf_nfs_mt_mnt3_resolve); + if (!mres) { + gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); + goto err; + } + + mres->exp = exp; + mres->mstate = ms; + mres->req = req; + strcpy (mres->remainingdir, volume_subdir); + mres->parentfh = nfs3_fh_build_root_fh (mres->mstate->nfsx->children, + mres->exp->vol); + + ret = __mnt3_resolve_export_subdir (mres); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" + , mres->exp->expname); + GF_FREE (mres); + } + +err: + return ret; +} + + +int +mnt3svc_mount (rpcsvc_request_t *req, struct mount3_state *ms, + struct mnt3_export *exp) +{ + int ret = -EFAULT; + + if ((!req) || (!ms) || (!exp)) + return ret; + + if (exp->exptype == MNT3_EXPTYPE_VOLUME) + ret = mnt3svc_volume_mount (req, ms, exp); + else if (exp->exptype == MNT3_EXPTYPE_DIR) + ret = mnt3_resolve_export_subdir (req, ms, exp); + + return ret; +} + + +/* mnt3_mntpath_to_xlator sets this to 1 if the mount is for a full +* volume or 2 for a subdir in the volume. +*/ +struct mnt3_export * +mnt3_mntpath_to_export (struct mount3_state *ms, char *dirpath) +{ + struct mnt3_export *exp = NULL; + struct mnt3_export *found = NULL; + + if ((!ms) || (!dirpath)) + return NULL; + + list_for_each_entry (exp, &ms->exportlist, explist) { + + /* Search for the an exact match with the volume */ + if (mnt3_match_dirpath_export (exp->expname, dirpath)) { + found = exp; + gf_log (GF_MNT, GF_LOG_DEBUG, "Found export volume: " + "%s", exp->vol->name); + goto foundexp; + } + } + gf_log (GF_MNT, GF_LOG_DEBUG, "Export not found"); +foundexp: + return found; +} + + +int +mnt3_check_client_net (struct mount3_state *ms, rpcsvc_request_t *req, + xlator_t *targetxl) +{ + rpcsvc_t *svc = NULL; + int ret = -1; + + if ((!ms) || (!req) || (!targetxl)) + return -1; + + svc = rpcsvc_request_service (req); + ret = rpcsvc_conn_peer_check (svc->options, targetxl->name, + rpcsvc_request_conn (req)); + if (ret == RPCSVC_AUTH_REJECT) { + gf_log (GF_MNT, GF_LOG_TRACE, "Peer not allowed"); + goto err; + } + + ret = rpcsvc_conn_privport_check (svc, targetxl->name, + rpcsvc_request_conn (req)); + if (ret == RPCSVC_AUTH_REJECT) { + gf_log (GF_MNT, GF_LOG_TRACE, "Unprivileged port not allowed"); + goto err; + } + + ret = 0; +err: return ret; } @@ -291,10 +688,9 @@ mnt3svc_mnt (rpcsvc_request_t *req) struct iovec pvec = {0, }; char path[MNTPATHLEN]; int ret = -1; - xlator_t *targetxl = NULL; struct mount3_state *ms = NULL; - rpcsvc_t *svc = NULL; mountstat3 mntstat = MNT3ERR_SERVERFAULT; + struct mnt3_export *exp = NULL; if (!req) return -1; @@ -318,35 +714,26 @@ mnt3svc_mnt (rpcsvc_request_t *req) ret = 0; gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s", path); - targetxl = nfs_mntpath_to_xlator (ms->nfsx->children, path); - if (!targetxl) { + exp = mnt3_mntpath_to_export (ms, path); + if (!exp) { ret = -1; mntstat = MNT3ERR_NOENT; goto mnterr; } - svc = rpcsvc_request_service (req); - ret = rpcsvc_conn_peer_check (svc->options, targetxl->name, - rpcsvc_request_conn (req)); - if (ret == RPCSVC_AUTH_REJECT) { - mntstat = MNT3ERR_ACCES; - ret = -1; - gf_log (GF_MNT, GF_LOG_TRACE, "Peer not allowed"); - goto mnterr; - } - - ret = rpcsvc_conn_privport_check (svc, targetxl->name, - rpcsvc_request_conn (req)); - if (ret == RPCSVC_AUTH_REJECT) { + ret = mnt3_check_client_net (ms, req, exp->vol); + if (ret == -1) { mntstat = MNT3ERR_ACCES; ret = -1; - gf_log (GF_MNT, GF_LOG_TRACE, "Unprivileged port not allowed"); + gf_log (GF_MNT, GF_LOG_DEBUG, "Client mount not allowed"); goto rpcerr; } - mnt3svc_mount (req, ms->nfsx, targetxl); + ret = mnt3svc_mount (req, ms, exp); + if (ret < 0) + mntstat = mnt3svc_errno_to_mnterr (-ret); mnterr: - if (ret == -1) { + if (ret < 0) { mnt3svc_mnt_error_reply (req, mntstat); ret = 0; } @@ -705,7 +1092,7 @@ rpcerr: exports -mnt3_xlchildren_to_exports (rpcsvc_t *svc, xlator_list_t *cl) +mnt3_xlchildren_to_exports (rpcsvc_t *svc, struct mount3_state *ms) { struct exportnode *elist = NULL; struct exportnode *prev = NULL; @@ -713,12 +1100,13 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, xlator_list_t *cl) size_t namelen = 0; int ret = -1; char *addrstr = NULL; + struct mnt3_export *ent = NULL; - if ((!cl) || (!svc)) + if ((!ms) || (!svc)) return NULL; - while (cl) { - namelen = strlen (cl->xlator->name); + list_for_each_entry(ent, &ms->exportlist, explist) { + namelen = strlen (ent->expname) + 1; elist = GF_CALLOC (1, sizeof (*elist), gf_nfs_mt_exportnode); if (!elist) { gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation" @@ -734,10 +1122,9 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, xlator_list_t *cl) goto free_list; } - strcpy (elist->ex_dir, "/"); - strcat (elist->ex_dir, cl->xlator->name); + strcpy (elist->ex_dir, ent->expname); - addrstr = rpcsvc_volume_allowed (svc->options,cl->xlator->name); + addrstr = rpcsvc_volume_allowed (svc->options, ent->vol->name); if (addrstr) addrstr = gf_strdup (addrstr); else @@ -760,8 +1147,6 @@ mnt3_xlchildren_to_exports (rpcsvc_t *svc, xlator_list_t *cl) if (!first) first = elist; - - cl = cl->next; } ret = 0; @@ -794,8 +1179,7 @@ mnt3svc_export (rpcsvc_request_t *req) } /* Using the children translator names, build the export list */ - elist = mnt3_xlchildren_to_exports (rpcsvc_request_service (req), - ms->nfsx->children); + elist = mnt3_xlchildren_to_exports (rpcsvc_request_service (req), ms); if (!elist) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed to build exports list"); rpcsvc_request_seterr (req, SYSTEM_ERR); @@ -813,10 +1197,224 @@ err: } +struct mnt3_export * +mnt3_init_export_ent (struct mount3_state *ms, xlator_t *xl, char *exportpath) +{ + struct mnt3_export *exp = NULL; + int alloclen = 0; + int ret = -1; + + if ((!ms) || (!xl)) + return NULL; + + exp = GF_CALLOC (1, sizeof (*exp), gf_nfs_mt_mnt3_export); + if (!exp) { + gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); + return NULL; + } + + INIT_LIST_HEAD (&exp->explist); + if (exportpath) + alloclen = strlen (xl->name) + 2 + strlen (exportpath); + else + alloclen = strlen (xl->name) + 2; + + exp->expname = GF_CALLOC (alloclen, sizeof (char), gf_nfs_mt_char); + if (!exp->expname) { + gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); + GF_FREE (exp); + exp = NULL; + goto err; + } + + if (exportpath) { + gf_log (GF_MNT, GF_LOG_TRACE, "Initing dir export: %s:%s", + xl->name, exportpath); + exp->exptype = MNT3_EXPTYPE_DIR; + ret = snprintf (exp->expname, alloclen, "/%s%s", xl->name, + exportpath); + } else { + gf_log (GF_MNT, GF_LOG_TRACE, "Initing volume export: %s", + xl->name); + exp->exptype = MNT3_EXPTYPE_VOLUME; + ret = snprintf (exp->expname, alloclen, "/%s", xl->name); + } + + exp->vol = xl; +err: + return exp; +} + + +int +__mnt3_init_volume_direxports (struct mount3_state *ms, xlator_t *xlator, + char *optstr) +{ + struct mnt3_export *newexp = NULL; + int ret = -1; + char *savptr = NULL; + char *dupopt = NULL; + char *token = NULL; + + if ((!ms) || (!xlator) || (!optstr)) + return -1; + + dupopt = gf_strdup (optstr); + if (!dupopt) { + gf_log (GF_MNT, GF_LOG_ERROR, "gf_strdup failed"); + goto err; + } + + token = strtok_r (dupopt, ",", &savptr); + while (token) { + newexp = mnt3_init_export_ent (ms, xlator, token); + if (!newexp) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to init dir " + "export: %s", token); + ret = -1; + goto err; + } + + list_add_tail (&newexp->explist, &ms->exportlist); + token = strtok_r (NULL, ",", &savptr); + } + + ret = 0; +err: + if (dupopt) + GF_FREE (dupopt); + + return ret; +} + + +int +__mnt3_init_volume (struct mount3_state *ms, dict_t *opts, xlator_t *xlator) +{ + struct mnt3_export *newexp = NULL; + int ret = -1; + char searchstr[1024]; + char *optstr = NULL; + + if ((!ms) || (!xlator) || (!opts)) + return -1; + + ret = snprintf (searchstr, 1024, "nfs3.%s.export-dir", xlator->name); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "snprintf failed"); + ret = -1; + goto err; + } + + if (dict_get (opts, searchstr)) { + ret = dict_get_str (opts, searchstr, &optstr); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to read option: " + "%s", searchstr); + ret = -1; + goto err; + } + + ret = __mnt3_init_volume_direxports (ms, xlator, optstr); + if (ret == -1) { + gf_log (GF_MNT, GF_LOG_ERROR, "Dir export setup failed" + " for volume: %s", xlator->name); + goto err; + } + + } + + if (ms->export_volumes) { + newexp = mnt3_init_export_ent (ms, xlator, NULL); + if (!newexp) { + ret = -1; + goto err; + } + + list_add_tail (&newexp->explist, &ms->exportlist); + } + ret = 0; + + +err: + return ret; +} + + +int +__mnt3_init_volume_export (struct mount3_state *ms, dict_t *opts) +{ + int ret = -1; + char *optstr = NULL; + /* On by default. */ + gf_boolean_t boolt = _gf_true; + + if ((!ms) || (!opts)) + return -1; + + if (!dict_get (opts, "nfs3.export-volumes")) { + ret = 0; + goto err; + } + + ret = dict_get_str (opts, "nfs3.export-volumes", &optstr); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to read option: " + "nfs3.export-volumes"); + ret = -1; + goto err; + } + + gf_string2boolean (optstr, &boolt); + ret = 0; + +err: + if (boolt == _gf_false) { + gf_log (GF_MNT, GF_LOG_TRACE, "Volume exports disabled"); + ms->export_volumes = 0; + } else { + gf_log (GF_MNT, GF_LOG_TRACE, "Volume exports enabled"); + ms->export_volumes = 1; + } + + return ret; +} + + +int +mnt3_init_options (struct mount3_state *ms, dict_t *options) +{ + xlator_list_t *volentry = NULL; + int ret = -1; + + if ((!ms) || (!options)) + return -1; + + __mnt3_init_volume_export (ms, options); + volentry = ms->nfsx->children; + while (volentry) { + gf_log (GF_MNT, GF_LOG_TRACE, "Initing options for: %s", + volentry->xlator->name); + ret = __mnt3_init_volume (ms, options, volentry->xlator); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Volume init failed"); + goto err; + } + + volentry = volentry->next; + } + + ret = 0; +err: + return ret; +} + + struct mount3_state * mnt3_init_state (xlator_t *nfsx) { struct mount3_state *ms = NULL; + int ret = -1; if (!nfsx) return NULL; @@ -829,7 +1427,13 @@ mnt3_init_state (xlator_t *nfsx) ms->iobpool = nfsx->ctx->iobuf_pool; ms->nfsx = nfsx; - ms->exports = nfsx->children; + INIT_LIST_HEAD (&ms->exportlist); + ret = mnt3_init_options (ms, nfsx->options); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Options init failed"); + return NULL; + } + INIT_LIST_HEAD (&ms->mountlist); LOCK_INIT (&ms->mountlock); diff --git a/xlators/nfs/server/src/mount3.h b/xlators/nfs/server/src/mount3.h index 7cfd2b0cb84..f555bc7f18a 100644 --- a/xlators/nfs/server/src/mount3.h +++ b/xlators/nfs/server/src/mount3.h @@ -33,6 +33,7 @@ #include "list.h" #include "xdr-nfs3.h" #include "locking.h" +#include "nfs3-fh.h" /* Registered with portmap */ #define GF_MOUNTV3_PORT 38465 @@ -60,12 +61,28 @@ struct mountentry { char hostname[MNTPATHLEN]; }; +#define MNT3_EXPTYPE_VOLUME 1 +#define MNT3_EXPTYPE_DIR 2 + +struct mnt3_export { + struct list_head explist; + + /* The string that may contain either the volume name if the full volume + * is exported or the subdirectory in the volume. + */ + char *expname; + xlator_t *vol; + int exptype; +}; + struct mount3_state { xlator_t *nfsx; /* The buffers for all network IO are got from this pool. */ struct iobuf_pool *iobpool; - xlator_list_t *exports; + + /* List of exports, can be volumes or directories in those volumes. */ + struct list_head exportlist; /* List of current mount points over all the exports from this * server. @@ -74,5 +91,22 @@ struct mount3_state { /* Used to protect the mountlist. */ gf_lock_t mountlock; + + /* Set to 0 if exporting full volumes is disabled. On by default. */ + int export_volumes; }; + + +struct mount3_resolve_state { + struct mnt3_export *exp; + struct mount3_state *mstate; + rpcsvc_request_t *req; + + char remainingdir[MNTPATHLEN]; + loc_t resolveloc; + struct nfs3_fh parentfh; +}; + +typedef struct mount3_resolve_state mnt3_resolve_t; + #endif diff --git a/xlators/nfs/server/src/nfs-mem-types.h b/xlators/nfs/server/src/nfs-mem-types.h index 118ee2d23b0..8913ba38b3f 100644 --- a/xlators/nfs/server/src/nfs-mem-types.h +++ b/xlators/nfs/server/src/nfs-mem-types.h @@ -40,6 +40,8 @@ enum gf_nfs_mem_types_ { gf_nfs_mt_nfs_initer_list, gf_nfs_mt_xlator_t, gf_nfs_mt_list_head, + gf_nfs_mt_mnt3_resolve, + gf_nfs_mt_mnt3_export, gf_nfs_mt_end }; #endif diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c index cb5f19ef992..d7d2a5fd6e2 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -578,6 +578,11 @@ fini (xlator_t *this) struct xlator_cbks cbks = { }; struct xlator_fops fops = { }; +/* TODO: If needed, per-volume options below can be extended to be export ++ * specific also because after export-dir is introduced, a volume is not ++ * neccessarily an export whereas different subdirectories within that volume ++ * can be and may need these options to be specified separately. ++ */ struct volume_options options[] = { { .key = {"nfs3.read-size"}, .type = GF_OPTION_TYPE_SIZET, @@ -624,6 +629,23 @@ struct volume_options options[] = { " trusted-write behaviour. Off by default." }, + { .key = {"nfs3.*.export-dir"}, + .type = GF_OPTION_TYPE_STR, + .description = "By default, all subvolumes of nfs are exported as " + "individual exports. There are cases where a " + "subdirectory or subdirectories in the volume need to " + "be exported separately. This option can also be used " + "in conjunction with nfs3.export-volumes option to " + "restrict exports only to the subdirectories specified" + " through this option. Must be an absolute path." + }, + { .key = {"nfs3.export-volumes"}, + .type = GF_OPTION_TYPE_BOOL, + .description = "Enable or disable exporting whole volumes, instead " + "if used in conjunction with nfs3.export-dir, can " + "allow setting up only subdirectories as exports. On " + "by default." + }, { .key = {"rpc-auth.auth-unix"}, .type = GF_OPTION_TYPE_BOOL, .description = "Disable or enable the AUTH_UNIX authentication type." diff --git a/xlators/nfs/server/src/nfs3-fh.c b/xlators/nfs/server/src/nfs3-fh.c index c7eb78fb378..59a78641105 100644 --- a/xlators/nfs/server/src/nfs3-fh.c +++ b/xlators/nfs/server/src/nfs3-fh.c @@ -75,9 +75,10 @@ nfs3_fh_init (struct nfs3_fh *fh, struct iatt *buf) struct nfs3_fh -nfs3_fh_build_root_fh (xlator_list_t *cl, xlator_t *xl, struct iatt buf) +nfs3_fh_build_root_fh (xlator_list_t *cl, xlator_t *xl) { struct nfs3_fh fh = {{0}, }; + struct iatt buf = {0, }; if ((!cl) || (!xl)) return fh; diff --git a/xlators/nfs/server/src/nfs3-fh.h b/xlators/nfs/server/src/nfs3-fh.h index f526edf43b0..73e4b7817c9 100644 --- a/xlators/nfs/server/src/nfs3-fh.h +++ b/xlators/nfs/server/src/nfs3-fh.h @@ -84,7 +84,7 @@ extern xlator_t * nfs3_fh_to_xlator (xlator_list_t *cl, struct nfs3_fh *fh); extern struct nfs3_fh -nfs3_fh_build_root_fh (xlator_list_t *cl, xlator_t *xl, struct iatt buf); +nfs3_fh_build_root_fh (xlator_list_t *cl, xlator_t *xl); extern int nfs3_fh_is_root_fh (struct nfs3_fh *fh); diff --git a/xlators/nfs/server/src/nfs3.c b/xlators/nfs/server/src/nfs3.c index fda6d6413bf..131596e8fd2 100644 --- a/xlators/nfs/server/src/nfs3.c +++ b/xlators/nfs/server/src/nfs3.c @@ -903,7 +903,7 @@ nfs3svc_lookup_parentdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, nfs3_fh_build_parent_fh (&cs->fh, buf, &newfh); else newfh = nfs3_fh_build_root_fh (cs->nfs3state->exportslist, - cs->vol, *buf); + cs->vol); xmit_res: nfs3_log_newfh_res (rpcsvc_request_xid (cs->req), "LOOKUP", status, |