nfs-ganesha 1.4
|
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 */