From 03c791e2d699574dae077d05a171a768bfb28ec3 Mon Sep 17 00:00:00 2001 From: Shehjar Tikoo Date: Thu, 23 Dec 2010 04:28:26 +0000 Subject: nfs: Support subdirectory exports Enable exporting directories as separate exports. Even though the directories wont show up in showmount output, they'll still be mount'able. The new option: nfs.export-dirs is enabled by default so that users dont have to wait till this option is incorporated into the gluster command line. Signed-off-by: Shehjar Tikoo Signed-off-by: Anand V. Avati BUG: 1743 (XenServer is not compatible with GlusterNFS) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=1743 --- xlators/nfs/server/src/mount3.c | 189 ++++++++++++++++++++++++++++++++++++---- xlators/nfs/server/src/mount3.h | 2 + xlators/nfs/server/src/nfs.c | 9 ++ 3 files changed, 183 insertions(+), 17 deletions(-) (limited to 'xlators/nfs/server') diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c index 25754a30f12..5f3a0a1a692 100644 --- a/xlators/nfs/server/src/mount3.c +++ b/xlators/nfs/server/src/mount3.c @@ -399,9 +399,10 @@ err: * we need to strip out the volume name first. */ char * -__volume_subdir (char *dirpath) +__volume_subdir (char *dirpath, char **volname) { char *subdir = NULL; + int volname_len = 0; if (!dirpath) return NULL; @@ -410,7 +411,19 @@ __volume_subdir (char *dirpath) dirpath++; subdir = index (dirpath, (int)'/'); + if (!subdir) + goto out; + if (!*volname) + goto out; + + /* subdir points to the first / after the volume name while dirpath + * points to the first char of the volume name. + */ + volname_len = subdir - dirpath; + strncpy (*volname, dirpath, volname_len); + *(*volname + volname_len) = '\0'; +out: return subdir; } @@ -473,6 +486,7 @@ __mnt3_resolve_export_subdir_comp (mnt3_resolve_t *mres) int ret = -EFAULT; nfs_user_t nfu = {0, }; char gfidstr[512]; + uuid_t gfid = {0, }; if (!mres) return ret; @@ -482,9 +496,9 @@ __mnt3_resolve_export_subdir_comp (mnt3_resolve_t *mres) goto err; /* Wipe the contents of the previous component */ + uuid_copy (gfid, mres->resolveloc.inode->gfid); nfs_loc_wipe (&mres->resolveloc); - ret = nfs_entry_loc_fill (mres->exp->vol->itable, - mres->resolveloc.inode->gfid, nextcomp, + ret = nfs_entry_loc_fill (mres->exp->vol->itable, gfid, nextcomp, &mres->resolveloc, NFS_RESOLVE_CREATE); if ((ret < 0) && (ret != -2)) { uuid_unparse (mres->resolveloc.inode->gfid, gfidstr); @@ -572,7 +586,7 @@ err: * of the exported directory can be built. */ int -__mnt3_resolve_export_subdir (mnt3_resolve_t *mres) +__mnt3_resolve_subdir (mnt3_resolve_t *mres) { char dupsubdir[MNTPATHLEN]; char *firstcomp = NULL; @@ -607,21 +621,16 @@ err: int -mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms, - struct mnt3_export *exp) +mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms, + struct mnt3_export *exp, char *subdir) { mnt3_resolve_t *mres = NULL; - char *volume_subdir = NULL; int ret = -EFAULT; struct nfs3_fh pfh = GF_NFS3FH_STATIC_INITIALIZER; - if ((!req) || (!ms) || (!exp)) + if ((!req) || (!ms) || (!exp) || (!subdir)) 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"); @@ -631,14 +640,14 @@ mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms, mres->exp = exp; mres->mstate = ms; mres->req = req; - strcpy (mres->remainingdir, volume_subdir); + strcpy (mres->remainingdir, subdir); if (gf_nfs_dvm_off (nfs_state (ms->nfsx))) 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_export_subdir (mres); + ret = __mnt3_resolve_subdir (mres); if (ret < 0) { gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" , mres->exp->expname); @@ -650,6 +659,32 @@ err: } +int +mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms, + struct mnt3_export *exp) +{ + char *volume_subdir = NULL; + int ret = -EFAULT; + + if ((!req) || (!ms) || (!exp)) + return ret; + + volume_subdir = __volume_subdir (exp->expname, NULL); + if (!volume_subdir) + goto err; + + ret = mnt3_resolve_subdir (req, ms, exp, exp->expname); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" + , exp->expname); + goto err; + } + +err: + return ret; +} + + int mnt3svc_mount (rpcsvc_request_t *req, struct mount3_state *ms, struct mnt3_export *exp) @@ -728,6 +763,82 @@ err: } +int +mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms, + char *subdir) +{ + char volname[1024]; + struct mnt3_export *exp = NULL; + char *volname_ptr = NULL; + int ret = -1; + + if ((!ms) || (!subdir)) + return -1; + + volname_ptr = volname; + subdir = __volume_subdir (subdir, &volname_ptr); + if (!subdir) + goto err; + + exp = mnt3_mntpath_to_export (ms, volname); + if (!exp) + goto err; + + ret = mnt3_resolve_subdir (req, ms, exp, subdir); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" + , subdir); + goto err; + } + +err: + return ret; +} + + +int +mnt3_find_export (rpcsvc_request_t *req, char *path, struct mnt3_export **e) +{ + int ret = -EFAULT; + struct mount3_state *ms = NULL; + struct mnt3_export *exp = NULL; + struct nfs_state *nfs = NULL; + + if ((!req) || (!path) || (!e)) + return -1; + + ms = (struct mount3_state *)nfs_rpcsvc_request_program_private (req); + if (!ms) { + gf_log (GF_MNT, GF_LOG_ERROR, "Mount state not present"); + nfs_rpcsvc_request_seterr (req, SYSTEM_ERR); + goto err; + } + + nfs = (struct nfs_state *)ms->nfsx->private; + gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s", path); + exp = mnt3_mntpath_to_export (ms, path); + if (exp) { + ret = 0; + *e = exp; + goto err; + } + + if (!gf_mnt3_export_dirs(ms)) { + ret = -1; + goto err; + } + + ret = mnt3_parse_dir_exports (req, ms, path); + if (ret == 0) { + ret = -2; + goto err; + } + +err: + return ret; +} + + int mnt3svc_mnt (rpcsvc_request_t *req) { @@ -760,15 +871,18 @@ mnt3svc_mnt (rpcsvc_request_t *req) } ret = 0; + nfs = (struct nfs_state *)ms->nfsx->private; gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s", path); - exp = mnt3_mntpath_to_export (ms, path); - if (!exp) { + ret = mnt3_find_export (req, path, &exp); + if (ret == -2) { + ret = 0; + goto rpcerr; + } else if (ret < 0) { ret = -1; mntstat = MNT3ERR_NOENT; goto mnterr; } - nfs = (struct nfs_state *)ms->nfsx->private; if (!nfs_subvolume_started (nfs, exp->vol)) { gf_log (GF_MNT, GF_LOG_DEBUG, "Volume %s not started", exp->vol->name); @@ -1496,6 +1610,46 @@ err: } +int +__mnt3_init_dir_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-dirs")) { + ret = 0; + goto err; + } + + ret = dict_get_str (opts, "nfs3.export-dirs", &optstr); + if (ret < 0) { + gf_log (GF_MNT, GF_LOG_ERROR, "Failed to read option: " + "nfs3.export-dirs"); + ret = -1; + goto err; + } + + gf_string2boolean (optstr, &boolt); + ret = 0; + +err: + if (boolt == _gf_false) { + gf_log (GF_MNT, GF_LOG_TRACE, "Dir exports disabled"); + ms->export_dirs = 0; + } else { + gf_log (GF_MNT, GF_LOG_TRACE, "Dir exports enabled"); + ms->export_dirs = 1; + } + + return ret; +} + + int mnt3_init_options (struct mount3_state *ms, dict_t *options) { @@ -1506,6 +1660,7 @@ mnt3_init_options (struct mount3_state *ms, dict_t *options) return -1; __mnt3_init_volume_export (ms, options); + __mnt3_init_dir_export (ms, options); volentry = ms->nfsx->children; while (volentry) { gf_log (GF_MNT, GF_LOG_TRACE, "Initing options for: %s", diff --git a/xlators/nfs/server/src/mount3.h b/xlators/nfs/server/src/mount3.h index d4d6d446fc6..ad4f21c98db 100644 --- a/xlators/nfs/server/src/mount3.h +++ b/xlators/nfs/server/src/mount3.h @@ -99,8 +99,10 @@ struct mount3_state { /* Set to 0 if exporting full volumes is disabled. On by default. */ int export_volumes; + int export_dirs; }; +#define gf_mnt3_export_dirs(mst) ((mst)->export_dirs) struct mount3_resolve_state { struct mnt3_export *exp; diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c index 3291858efc0..979fd2fb04d 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -764,6 +764,15 @@ struct volume_options options[] = { "restrict exports only to the subdirectories specified" " through this option. Must be an absolute path." }, + { .key = {"nfs3.export-dirs"}, + .type = GF_OPTION_TYPE_BOOL, + .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. Enabling this option allows " + "any directory on a volumes to be exported separately." + " Directory exports are enabled by default." + }, { .key = {"nfs3.export-volumes"}, .type = GF_OPTION_TYPE_BOOL, .description = "Enable or disable exporting whole volumes, instead " -- cgit