nfs-ganesha 1.4

fsal_internal.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  * -------------
00024  */
00025 
00036 #define FSAL_INTERNAL_C
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #include  "fsal.h"
00042 #include "fsal_internal.h"
00043 #include "abstract_mem.h"
00044 #include "SemN.h"
00045 #include "fsal_convert.h"
00046 #include <libgen.h>             /* used for 'dirname' */
00047 #include <pthread.h>
00048 #include <string.h>
00049 #include <sys/types.h>
00050 #include <xfs/xfs.h>
00051 #include <xfs/handle.h>
00052 #include <mntent.h>
00053 
00054 /* Add missing prototype */
00055 int fd_to_handle(int fd, void **hanp, size_t * hlen);
00056 
00057 /* credential lifetime (1h) */
00058 fsal_uint_t CredentialLifetime = 3600;
00059 
00060 /* static filesystem info.
00061  * The access is thread-safe because
00062  * it is read-only, except during initialization.
00063  */
00064 fsal_staticfsinfo_t global_fs_info;
00065 
00066 /* filesystem info for HPSS */
00067 static fsal_staticfsinfo_t default_posix_info = {
00068   0xFFFFFFFFFFFFFFFFLL,         /* max file size (64bits) */
00069   _POSIX_LINK_MAX,              /* max links */
00070   FSAL_MAX_NAME_LEN,            /* max filename */
00071   FSAL_MAX_PATH_LEN,            /* max pathlen */
00072   TRUE,                         /* no_trunc */
00073   TRUE,                         /* chown restricted */
00074   FALSE,                        /* case insensitivity */
00075   TRUE,                         /* case preserving */
00076   FSAL_EXPTYPE_PERSISTENT,      /* FH expire type */
00077   TRUE,                         /* hard link support */
00078   TRUE,                         /* symlink support */
00079   FALSE,                        /* lock management */
00080   FALSE,                        /* lock owners */
00081   FALSE,                        /* async blocking locks */
00082   TRUE,                         /* named attributes */
00083   TRUE,                         /* handles are unique and persistent */
00084   {10, 0},                      /* Duration of lease at FS in seconds */
00085   FSAL_ACLSUPPORT_ALLOW,        /* ACL support */
00086   TRUE,                         /* can change times */
00087   TRUE,                         /* homogenous */
00088   POSIX_SUPPORTED_ATTRIBUTES,   /* supported attributes */
00089   0,                            /* maxread size */
00090   0,                            /* maxwrite size */
00091   0,                            /* default umask */
00092   0,                            /* cross junctions */
00093   0400,                         /* default access rights for xattrs: root=RW, owner=R */
00094   0,                            /* default access check support in FSAL */
00095   0,                            /* default share reservation support in FSAL */
00096   0                             /* default share reservation support with open owners in FSAL */
00097 };
00098 
00099 /* variables for limiting the calls to the filesystem */
00100 static int limit_calls = FALSE;
00101 semaphore_t sem_fs_calls;
00102 
00103 /* threads keys for stats */
00104 static pthread_key_t key_stats;
00105 static pthread_once_t once_key = PTHREAD_ONCE_INIT;
00106 
00107 /* init keys */
00108 static void init_keys(void)
00109 {
00110   if(pthread_key_create(&key_stats, NULL) == -1)
00111     LogError(COMPONENT_FSAL, ERR_SYS, ERR_PTHREAD_KEY_CREATE, errno);
00112 
00113   return;
00114 }                               /* init_keys */
00115 
00127 void fsal_increment_nbcall(int function_index, fsal_status_t status)
00128 {
00129 
00130   fsal_statistics_t *bythread_stat = NULL;
00131 
00132   /* verify index */
00133 
00134   if(function_index >= FSAL_NB_FUNC)
00135     return;
00136 
00137   /* first, we init the keys if this is the first time */
00138 
00139   if(pthread_once(&once_key, init_keys) != 0)
00140     {
00141       LogError(COMPONENT_FSAL, ERR_SYS, ERR_PTHREAD_ONCE, errno);
00142       return;
00143     }
00144 
00145   /* we get the specific value */
00146 
00147   bythread_stat = (fsal_statistics_t *) pthread_getspecific(key_stats);
00148 
00149   /* we allocate stats if this is the first time */
00150 
00151   if(bythread_stat == NULL)
00152     {
00153       int i;
00154 
00155       bythread_stat = gsh_malloc(sizeof(fsal_statistics_t));
00156 
00157       if(bythread_stat == NULL)
00158         {
00159           LogError(COMPONENT_FSAL, ERR_SYS, ERR_MALLOC, ENOMEM);
00160         }
00161 
00162       /* inits the struct */
00163 
00164       for(i = 0; i < FSAL_NB_FUNC; i++)
00165         {
00166           bythread_stat->func_stats.nb_call[i] = 0;
00167           bythread_stat->func_stats.nb_success[i] = 0;
00168           bythread_stat->func_stats.nb_err_retryable[i] = 0;
00169           bythread_stat->func_stats.nb_err_unrecover[i] = 0;
00170         }
00171 
00172       /* set the specific value */
00173       pthread_setspecific(key_stats, (void *)bythread_stat);
00174 
00175     }
00176 
00177   /* we increment the values */
00178 
00179   if(bythread_stat)
00180     {
00181       bythread_stat->func_stats.nb_call[function_index]++;
00182 
00183       if(!FSAL_IS_ERROR(status))
00184         bythread_stat->func_stats.nb_success[function_index]++;
00185       else if(status.major == ERR_FSAL_DELAY)   /* Error is retryable */
00186         bythread_stat->func_stats.nb_err_retryable[function_index]++;
00187       else
00188         bythread_stat->func_stats.nb_err_unrecover[function_index]++;
00189     }
00190 
00191   return;
00192 }
00193 
00204 void fsal_internal_getstats(fsal_statistics_t * output_stats)
00205 {
00206 
00207   fsal_statistics_t *bythread_stat = NULL;
00208 
00209   /* first, we init the keys if this is the first time */
00210   if(pthread_once(&once_key, init_keys) != 0)
00211     {
00212       LogError(COMPONENT_FSAL, ERR_SYS, ERR_PTHREAD_ONCE, errno);
00213       return;
00214     }
00215 
00216   /* we get the specific value */
00217   bythread_stat = (fsal_statistics_t *) pthread_getspecific(key_stats);
00218 
00219   /* we allocate stats if this is the first time */
00220   if(bythread_stat == NULL)
00221     {
00222       int i;
00223 
00224       if((bythread_stat =
00225           gsh_malloc(sizeof(fsal_statistics_t))) == NULL)
00226         LogError(COMPONENT_FSAL, ERR_SYS, ERR_MALLOC, ENOMEM);
00227 
00228       /* inits the struct */
00229       for(i = 0; i < FSAL_NB_FUNC; i++)
00230         {
00231           bythread_stat->func_stats.nb_call[i] = 0;
00232           bythread_stat->func_stats.nb_success[i] = 0;
00233           bythread_stat->func_stats.nb_err_retryable[i] = 0;
00234           bythread_stat->func_stats.nb_err_unrecover[i] = 0;
00235         }
00236 
00237       /* set the specific value */
00238       pthread_setspecific(key_stats, (void *)bythread_stat);
00239 
00240     }
00241 
00242   if(output_stats)
00243     (*output_stats) = (*bythread_stat);
00244 
00245   return;
00246 
00247 }
00248 
00252 void TakeTokenFSCall()
00253 {
00254   /* no limits */
00255   if(limit_calls == FALSE)
00256     return;
00257 
00258   /* there is a limit */
00259   semaphore_P(&sem_fs_calls);
00260 
00261 }
00262 
00263 void ReleaseTokenFSCall()
00264 {
00265   /* no limits */
00266   if(limit_calls == FALSE)
00267     return;
00268 
00269   /* there is a limit */
00270   semaphore_V(&sem_fs_calls);
00271 
00272 }
00273 
00274 /*
00275  *  This function initializes shared variables of the fsal.
00276  */
00277 fsal_status_t fsal_internal_init_global(fsal_init_info_t * fsal_info,
00278                                         fs_common_initinfo_t * fs_common_info,
00279                                         xfsfs_specific_initinfo_t * fs_specific_info)
00280 {
00281 
00282   /* sanity check */
00283   if(!fsal_info || !fs_common_info || !fs_specific_info)
00284     ReturnCode(ERR_FSAL_FAULT, 0);
00285 
00286   /* inits FS call semaphore */
00287   if(fsal_info->max_fs_calls > 0)
00288     {
00289       int rc;
00290 
00291       limit_calls = TRUE;
00292 
00293       rc = semaphore_init(&sem_fs_calls, fsal_info->max_fs_calls);
00294 
00295       if(rc != 0)
00296         ReturnCode(ERR_FSAL_SERVERFAULT, rc);
00297 
00298       LogDebug(COMPONENT_FSAL,
00299                         "FSAL INIT: Max simultaneous calls to filesystem is limited to %u.",
00300                         fsal_info->max_fs_calls);
00301 
00302     }
00303   else
00304     {
00305       LogDebug(COMPONENT_FSAL,
00306                         "FSAL INIT: Max simultaneous calls to filesystem is unlimited.");
00307     }
00308 
00309   /* setting default values. */
00310   global_fs_info = default_posix_info;
00311 
00312   display_fsinfo(&default_posix_info);
00313 
00314   /* Analyzing fs_common_info struct */
00315 
00316   if((fs_common_info->behaviors.maxfilesize != FSAL_INIT_FS_DEFAULT) ||
00317      (fs_common_info->behaviors.maxlink != FSAL_INIT_FS_DEFAULT) ||
00318      (fs_common_info->behaviors.maxnamelen != FSAL_INIT_FS_DEFAULT) ||
00319      (fs_common_info->behaviors.maxpathlen != FSAL_INIT_FS_DEFAULT) ||
00320      (fs_common_info->behaviors.no_trunc != FSAL_INIT_FS_DEFAULT) ||
00321      (fs_common_info->behaviors.case_insensitive != FSAL_INIT_FS_DEFAULT) ||
00322      (fs_common_info->behaviors.case_preserving != FSAL_INIT_FS_DEFAULT) ||
00323      (fs_common_info->behaviors.named_attr != FSAL_INIT_FS_DEFAULT) ||
00324      (fs_common_info->behaviors.lease_time != FSAL_INIT_FS_DEFAULT) ||
00325      (fs_common_info->behaviors.supported_attrs != FSAL_INIT_FS_DEFAULT) ||
00326      (fs_common_info->behaviors.homogenous != FSAL_INIT_FS_DEFAULT))
00327     ReturnCode(ERR_FSAL_NOTSUPP, 0);
00328 
00329   SET_BOOLEAN_PARAM(global_fs_info, fs_common_info, symlink_support);
00330   SET_BOOLEAN_PARAM(global_fs_info, fs_common_info, link_support);
00331   SET_BOOLEAN_PARAM(global_fs_info, fs_common_info, lock_support);
00332   SET_BOOLEAN_PARAM(global_fs_info, fs_common_info, lock_support_owner);
00333   SET_BOOLEAN_PARAM(global_fs_info, fs_common_info, lock_support_async_block);
00334   SET_BOOLEAN_PARAM(global_fs_info, fs_common_info, cansettime);
00335 
00336   SET_INTEGER_PARAM(global_fs_info, fs_common_info, maxread);
00337   SET_INTEGER_PARAM(global_fs_info, fs_common_info, maxwrite);
00338 
00339   SET_BITMAP_PARAM(global_fs_info, fs_common_info, umask);
00340 
00341   SET_BOOLEAN_PARAM(global_fs_info, fs_common_info, auth_exportpath_xdev);
00342 
00343   SET_BITMAP_PARAM(global_fs_info, fs_common_info, xattr_access_rights);
00344 
00345   LogFullDebug(COMPONENT_FSAL,
00346                     "Supported attributes constant = 0x%llX.",
00347                     POSIX_SUPPORTED_ATTRIBUTES);
00348 
00349   LogFullDebug(COMPONENT_FSAL,
00350                     "Supported attributes default = 0x%llX.",
00351                     default_posix_info.supported_attrs);
00352 
00353   LogDebug(COMPONENT_FSAL,
00354                     "FSAL INIT: Supported attributes mask = 0x%llX.",
00355                     global_fs_info.supported_attrs);
00356 
00357   ReturnCode(ERR_FSAL_NO_ERROR, 0);
00358 }
00359 
00360 fsal_status_t fsal_internal_handle2fd(fsal_op_context_t * p_context,
00361                                       fsal_handle_t * phandle, int *pfd, int oflags)
00362 {
00363   int rc = 0;
00364   int errsv = 0;
00365   xfsfsal_handle_t *xh = (xfsfsal_handle_t *)phandle;
00366 
00367   if(!phandle || !pfd || !p_context)
00368     ReturnCode(ERR_FSAL_FAULT, 0);
00369 
00370   rc = open_by_handle(xh->data.handle_val, xh->data.handle_len, oflags);
00371   errsv = errno;
00372   if(rc == -1)
00373     {
00374       if(errsv == EISDIR)
00375         {
00376           rc = open_by_handle(xh->data.handle_val, xh->data.handle_len,
00377                               O_DIRECTORY);
00378           if(rc < 0)
00379              ReturnCode(posix2fsal_error(errsv), errsv);
00380         }
00381       else
00382         ReturnCode(posix2fsal_error(errsv), errsv);
00383     }
00384 
00385   *pfd = rc;
00386 
00387   ReturnCode(ERR_FSAL_NO_ERROR, 0);
00388 }                               /* fsal_internal_handle2fd */
00389 
00390 fsal_status_t fsal_internal_fd2handle(fsal_op_context_t * p_context,
00391                                       int fd, fsal_handle_t * handle)
00392 {
00393   xfsfsal_handle_t *phandle = (xfsfsal_handle_t *)handle;
00394   int rc = 0;
00395   struct stat ino;
00396 
00397   char *handle_val;
00398   size_t handle_len;
00399 
00400   if(!phandle)
00401     ReturnCode(ERR_FSAL_FAULT, 0);
00402 
00403   memset(phandle, 0, sizeof(xfsfsal_handle_t));
00404 
00405   /* retrieve inode */
00406   rc = fstat(fd, &ino);
00407   if(rc)
00408     ReturnCode(posix2fsal_error(errno), errno);
00409 
00410   phandle->data.inode = ino.st_ino;
00411   switch (ino.st_mode & S_IFMT)
00412     {
00413     case S_IFREG:
00414       phandle->data.type = DT_REG;
00415       break;
00416     case S_IFDIR:
00417       phandle->data.type = DT_DIR;
00418       break;
00419     default:
00420       LogCrit(COMPONENT_FSAL, "Unexpected type 0%o for inode %zd",
00421               ino.st_mode & S_IFMT, ino.st_ino);
00422       ReturnCode(ERR_FSAL_INVAL, EINVAL);
00423     }
00424 
00425   if((rc = fd_to_handle(fd, (void **)(&handle_val), &handle_len)) < 0)
00426     ReturnCode(posix2fsal_error(errno), errno);
00427 
00428   if(handle_len > sizeof(phandle->data.handle_val))
00429     {
00430       free_handle(handle_val, handle_len);
00431       ReturnCode(ERR_FSAL_TOOSMALL, 0);
00432     }
00433 
00434   memcpy(phandle->data.handle_val, handle_val, handle_len);
00435   phandle->data.handle_len = handle_len;
00436 
00437   free_handle(handle_val, handle_len);
00438 
00439   ReturnCode(ERR_FSAL_NO_ERROR, 0);
00440 }                               /* fsal_internal_fd2handle */
00441 
00442 fsal_status_t fsal_internal_Path2Handle(xfsfsal_op_context_t * p_context,       /* IN */
00443                                         fsal_path_t * p_fsalpath,       /* IN */
00444                                         xfsfsal_handle_t * p_handle /* OUT */ )
00445 {
00446   int objectfd;
00447   fsal_status_t st;
00448 
00449   if(!p_context || !p_handle || !p_fsalpath)
00450     ReturnCode(ERR_FSAL_FAULT, 0);
00451 
00452   memset(p_handle, 0, sizeof(xfsfsal_handle_t));
00453 
00454   LogFullDebug(COMPONENT_FSAL, "Lookup handle for %s", p_fsalpath->path);
00455 
00456   if((objectfd = open(p_fsalpath->path, O_RDONLY, 0600)) < 0)
00457     ReturnCode(posix2fsal_error(errno), errno);
00458 
00459   st = fsal_internal_fd2handle(p_context, objectfd, p_handle);
00460   close(objectfd);
00461   return st;
00462 }                               /* fsal_internal_Path2Handle */
00463 
00464 fsal_status_t fsal_internal_setattrs_symlink(fsal_handle_t * p_filehandle,   /* IN */
00465                                              fsal_op_context_t * p_context,  /* IN */
00466                                              fsal_attrib_list_t * p_attrib_set, /* IN */
00467                                              fsal_attrib_list_t * p_object_attributes)
00468 {
00469   if(!p_filehandle || !p_context || !p_attrib_set)
00470     Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);
00471 
00472   *p_object_attributes = *p_attrib_set;
00473 
00474   ReturnCode(ERR_FSAL_NO_ERROR, 0);
00475 }                               /* fsal_internal_setattrs_symlink */
00476 
00477 /* The code that follows is intended to produce a xfs handle for a symlink. Roughly it is kind of "get handle by inode"
00478  * It may not be portable
00479  * I keep it for wanting of a better solution */
00480 
00481 #define XFS_FSHANDLE_SZ             8
00482 typedef struct xfs_fshandle
00483 {
00484   char fsh_space[XFS_FSHANDLE_SZ];
00485 } xfs_fshandle_t;
00486 
00487 /* private file handle - for use by open_by_fshandle */
00488 #define XFS_FILEHANDLE_SZ           24
00489 #define XFS_FILEHANDLE_SZ_FOLLOWING 14
00490 #define XFS_FILEHANDLE_SZ_PAD       2
00491 typedef struct xfs_filehandle
00492 {
00493   xfs_fshandle_t fh_fshandle;   /* handle of fs containing this inode */
00494   int16_t fh_sz_following;      /* bytes in handle after this member */
00495   char fh_pad[XFS_FILEHANDLE_SZ_PAD];   /* padding, must be zeroed */
00496   __uint32_t fh_gen;            /* generation count */
00497   xfs_ino_t fh_ino;             /* 64 bit ino */
00498 } xfs_filehandle_t;
00499 
00500 static void build_xfsfilehandle(xfs_filehandle_t * phandle,
00501                                 xfs_fshandle_t * pfshandle, xfs_bstat_t * pxfs_bstat)
00502 {
00503   /* Fill in the FS specific part */
00504   memcpy(&phandle->fh_fshandle, pfshandle, sizeof(xfs_fshandle_t));
00505 
00506   /* Do the required padding */
00507   phandle->fh_sz_following = XFS_FILEHANDLE_SZ_FOLLOWING;
00508   memset(phandle->fh_pad, 0, XFS_FILEHANDLE_SZ_PAD);
00509 
00510   /* Add object's specific information from xfs_bstat_t */
00511   phandle->fh_gen = pxfs_bstat->bs_gen;
00512   phandle->fh_ino = pxfs_bstat->bs_ino;
00513 }                               /* build_xfsfilehandle */
00514 
00515 int fsal_internal_get_bulkstat_by_inode(int fd, xfs_ino_t * p_ino, xfs_bstat_t * pxfs_bstat)
00516 {
00517   xfs_fsop_bulkreq_t bulkreq;
00518 
00519   bulkreq.lastip = (__u64 *)p_ino;
00520   bulkreq.icount = 1;
00521   bulkreq.ubuffer = pxfs_bstat;
00522   bulkreq.ocount = NULL;
00523   return ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq);
00524 }                               /* get_bulkstat_by_inode */
00525 
00526 fsal_status_t fsal_internal_inum2handle(fsal_op_context_t * context,
00527                                         ino_t inum, fsal_handle_t * handle)
00528 {
00529   xfsfsal_op_context_t * p_context = (xfsfsal_op_context_t *)context;
00530   xfsfsal_handle_t * phandle = (xfsfsal_handle_t *)handle;
00531   int fd = 0;
00532 
00533   xfs_ino_t xfs_ino;
00534   xfs_bstat_t bstat;
00535 
00536   xfs_filehandle_t xfsfilehandle;
00537   xfs_fshandle_t xfsfshandle;
00538 
00539   if((fd = open(p_context->export_context->mount_point, O_DIRECTORY)) == -1)
00540     ReturnCode(posix2fsal_error(errno), errno);
00541 
00542   xfs_ino = inum;
00543   if(fsal_internal_get_bulkstat_by_inode(fd, &xfs_ino, &bstat) < 0)
00544     {
00545       close(fd);
00546       ReturnCode(posix2fsal_error(errno), errno);
00547     }
00548 
00549   close(fd);
00550 
00551   memcpy(xfsfshandle.fsh_space, p_context->export_context->mnt_fshandle_val,
00552          XFS_FSHANDLE_SZ);
00553   build_xfsfilehandle(&xfsfilehandle, &xfsfshandle, &bstat);
00554 
00555   memcpy(phandle->data.handle_val, &xfsfilehandle, sizeof(xfs_filehandle_t));
00556   phandle->data.handle_len = sizeof(xfs_filehandle_t);
00557   phandle->data.inode = inum;
00558   switch (bstat.bs_mode & S_IFMT)
00559     {
00560     case S_IFSOCK:
00561       phandle->data.type = DT_SOCK;
00562       break;
00563     case S_IFLNK:
00564       phandle->data.type = DT_LNK;
00565       break;
00566     case S_IFREG:
00567     case S_IFDIR:
00568       LogCrit(COMPONENT_FSAL, "Why are you trying to fake handle on %ld?",
00569               xfs_ino);
00570       break;
00571     case S_IFBLK:
00572       phandle->data.type = DT_BLK;
00573       break;
00574     case S_IFCHR:
00575       phandle->data.type = DT_CHR;
00576       break;
00577     case S_IFIFO:
00578       phandle->data.type = DT_FIFO;
00579       break;
00580     default:
00581       LogCrit(COMPONENT_FSAL, "Unknown value %o for inode %ld",
00582               bstat.bs_mode & S_IFMT, xfs_ino);
00583       break;
00584     }
00585 
00586   ReturnCode(ERR_FSAL_NO_ERROR, 0);
00587 }                               /* fsal_internal_inum2handle */
00588 
00589 int fsal_internal_path2fsname(char *rpath, char *fs_spec)
00590 {
00591   FILE *fp;
00592   struct mntent mnt;
00593   struct mntent *pmnt;
00594   char work[MAXPATHLEN];
00595   char mntdir[MAXPATHLEN];
00596 
00597   size_t pathlen, outlen;
00598   int rc = -1;
00599 
00600   pathlen = 0;
00601   outlen = 0;
00602 
00603   if(!rpath || !fs_spec)
00604     return -1;
00605 
00606   fp = setmntent(MOUNTED, "r");
00607 
00608   if(fp == NULL)
00609     return -1;
00610 
00611   while((pmnt = getmntent_r(fp, &mnt, work, MAXPATHLEN)) != NULL)
00612     {
00613       /* get the longer path that matches export path */
00614       if(mnt.mnt_dir != NULL)
00615         {
00616 
00617           /* Consider only xfs mount points */
00618           if(strncmp(mnt.mnt_type, "xfs", 256))
00619             continue;
00620 
00621           pathlen = strlen(mnt.mnt_dir);
00622 
00623           if((pathlen > outlen) && !strcmp(mnt.mnt_dir, "/"))
00624             {
00625               outlen = pathlen;
00626               strncpy(mntdir, mnt.mnt_dir, MAXPATHLEN);
00627               strncpy(fs_spec, mnt.mnt_fsname, MAXPATHLEN);
00628             }
00629           /* in other cases, the filesystem must be <mountpoint>/<smthg> or <mountpoint>\0 */
00630           else if((pathlen > outlen) &&
00631                   !strncmp(rpath, mnt.mnt_dir, pathlen) &&
00632                   ((rpath[pathlen] == '/') || (rpath[pathlen] == '\0')))
00633             {
00634               /* LogFullDebug(COMPONENT_FSAL, "%s is under mountpoint %s, type=%s, fs=%s", 
00635                  rpath, mnt.mnt_dir, mnt.mnt_type, mnt.mnt_fsname); */
00636 
00637               outlen = pathlen;
00638               strncpy(mntdir, mnt.mnt_dir, MAXPATHLEN);
00639               strncpy(fs_spec, mnt.mnt_fsname, MAXPATHLEN);
00640               rc = 0;
00641             }
00642         }
00643 
00644     }
00645 
00646   endmntent(fp);
00647   return rc;
00648 }                               /* fsal_internal_path2fsname */