From: Andrew Deason Date: Thu, 11 Mar 2010 18:19:47 +0000 (-0600) Subject: Parallel I/O extensions to namei backend X-Git-Tag: upstream/1.6.0.pre2^2~79 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=6d0b9da6f0734e638087cfe6092df1a7b80c5bc9;p=packages%2Fo%2Fopenafs.git Parallel I/O extensions to namei backend This adds the ability for certain namei operations (currently only ListViceInodes) to occur across multiple different threads in parallel. Currently this is only enabled when built with the not-yet-existant AFS_SALSRV_ENV. Originally written by Tom Keiser. (cherry picked from commit 0a4a03ae68bea51a74a4ef496d50a800bd3e0cbd) Reviewed-on: http://gerrit.openafs.org/1864 Tested-by: BuildBot Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear Change-Id: I2fa3aa60a13c81e0a0bc7ffb5b323ec7580f560f Reviewed-on: http://gerrit.openafs.org/3826 Tested-by: BuildBot Reviewed-by: Derrick Brashear --- diff --git a/src/vol/namei_ops.c b/src/vol/namei_ops.c index e408c15c2..0c09b5b88 100644 --- a/src/vol/namei_ops.c +++ b/src/vol/namei_ops.c @@ -69,6 +69,13 @@ #define LOCK_UN 8 /* unlock */ #endif +#ifdef AFS_SALSRV_ENV +#include +#include +#include +#include +#endif + #ifndef HAVE_FLOCK #include @@ -945,6 +952,15 @@ namei_copy_on_write(IHandle_t *h) #define LINKTABLE_WIDTH 2 #define LINKTABLE_SHIFT 1 /* log 2 = 1 */ +/** + * compute namei link table file and bit offset from inode number. + * + * @param[in] ino inode number + * @param[out] offset link table file offset + * @param[out] index bit offset within 2-byte record + * + * @internal + */ static void namei_GetLCOffsetAndIndexFromIno(Inode ino, afs_foff_t * offset, int *index) { @@ -955,9 +971,33 @@ namei_GetLCOffsetAndIndexFromIno(Inode ino, afs_foff_t * offset, int *index) *index = (tindex << 1) + tindex; } -/* namei_GetLinkCount - * If lockit is set, lock the file and leave it locked upon a successful - * return. +#ifdef AFS_PTHREAD_ENV +/* XXX do static initializers work for WINNT/pthread? */ +pthread_mutex_t _namei_glc_lock = PTHREAD_MUTEX_INITIALIZER; +#define NAMEI_GLC_LOCK MUTEX_ENTER(&_namei_glc_lock) +#define NAMEI_GLC_UNLOCK MUTEX_EXIT(&_namei_glc_lock) +#else /* !AFS_PTHREAD_ENV */ +#define NAMEI_GLC_LOCK +#define NAMEI_GLC_UNLOCK +#endif /* !AFS_PTHREAD_ENV */ + +/** + * get the link count of an inode. + * + * @param[in] h namei link count table file handle + * @param[in] ino inode number for which we are requesting a link count + * @param[in] lockit if asserted, return with lock held on link table file + * @param[in] fixup if asserted, write 1 to link count when read() returns + * zero (at EOF) + * @param[in] nowrite return success on zero byte read or ZLC + * + * @post if lockit asserted and lookup was successful, will return with write + * lock on link table file descriptor + * + * @return link count + * @retval -1 namei link table i/o error + * + * @internal */ static int namei_GetLinkCount2(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrite) @@ -981,20 +1021,41 @@ namei_GetLinkCount2(FdHandle_t * h, Inode ino, int lockit, int fixup, int nowrit if ((rc == 0 || !((row >> index) & NAMEI_TAGMASK)) && fixup && nowrite) return 1; if (rc == 0 && fixup) { + /* + * extend link table and write a link count of 1 for ino + * + * in order to make MT-safe, truncation (extension really) + * must happen under a mutex + */ struct stat st; - if (fstat(h->fd_fd, &st) || st.st_size >= offset+sizeof(row)) - goto bad_getLinkByte; + NAMEI_GLC_LOCK; + if (fstat(h->fd_fd, &st) || st.st_size >= offset+sizeof(row)) { + NAMEI_GLC_UNLOCK; + goto bad_getLinkByte; + } FDH_TRUNC(h, offset+sizeof(row)); row = 1 << index; rc = FDH_PWRITE(h, (char *)&row, sizeof(row), offset); + NAMEI_GLC_UNLOCK; } if (rc != sizeof(row)) { goto bad_getLinkByte; } if (fixup && !((row >> index) & NAMEI_TAGMASK)) { - row |= 1<=0 number of matching files found */ int namei_ListAFSFiles(char *dev, int (*writeFun) (FILE *, struct ViceInodeInfo *, char *, - char *), FILE * fp, + char *), + FILE * fp, int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *), afs_uint32 singleVolumeNumber, void *rock) { @@ -1306,28 +1394,533 @@ namei_ListAFSFiles(char *dev, return ninodes; } -/* namei_ListAFSSubDirs +#ifdef DELETE_ZLC +static void AddToZLCDeleteList(char dir, char *name); +static void DeleteZLCFiles(char *path); +#endif + +/** + * examine a namei volume special file. + * + * @param[in] path1 volume special directory path + * @param[in] dname directory entry name + * @param[in] myIH inode handle to volume directory + * @param[out] linkHandle namei link count fd handle. if + * the inode in question is the link + * table, then the FdHandle is populated + * @param[in] writeFun metadata write function pointer + * @param[in] fp file pointer where inode metadata + * is written by (*writeFun)() + * @param[in] judgeFun inode filter function pointer. if + * not NULL, only inodes for which this + * function returns non-zero are recorded + * into fp by writeFun + * @param[in] singleVolumeNumer volume id filter. if non-zero, only + * inodes associated with this volume id + * are recorded by writeFun + * @param[in] rock opaque pointer passed to writeFun and + * judgeFun + * + * @return operation status + * @retval 1 count this inode + * @retval 0 don't count this inode + * @retval -1 failure + * + * @internal + */ +static int +_namei_examine_special(char * path1, + char * dname, + IHandle_t * myIH, + FdHandle_t * linkHandle, + int (*writeFun) (FILE *, struct ViceInodeInfo *, char *, + char *), + FILE * fp, + int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *), + int singleVolumeNumber, + void *rock) +{ + int ret = 0; + struct ViceInodeInfo info; + + if (DecodeInode(path1, dname, &info, myIH->ih_vid) < 0) { + ret = 0; + goto error; + } + + if (info.u.param[2] != VI_LINKTABLE) { + info.linkCount = 1; + } else { + char path2[512]; + /* Open this handle */ + (void)afs_snprintf(path2, sizeof(path2), + "%s/%s", path1, dname); + linkHandle->fd_fd = afs_open(path2, Testing ? O_RDONLY : O_RDWR, 0666); + info.linkCount = + namei_GetLinkCount2(linkHandle, (Inode) 0, 1, 1, Testing); + } + + if (!judgeFun || + (*judgeFun) (&info, singleVolumeNumber, rock)) { + ret = 1; + if ((*writeFun) (fp, &info, path1, dname) < 0) { + ret = -1; + } + } + + error: + return ret; +} + +/** + * examine a namei file. + * + * @param[in] path1 volume special directory path + * @param[in] dname directory entry name + * @param[in] myIH inode handle to volume directory + * @param[in] linkHandle namei link count fd handle. + * @param[in] writeFun metadata write function pointer + * @param[in] fp file pointer where inode metadata + * is written by (*writeFun)() + * @param[in] judgeFun inode filter function pointer. if + * not NULL, only inodes for which this + * function returns non-zero are recorded + * into fp by writeFun + * @param[in] singleVolumeNumer volume id filter. if non-zero, only + * inodes associated with this volume id + * are recorded by writeFun + * @param[in] rock opaque pointer passed to writeFun and + * judgeFun + * + * @return operation status + * @retval 1 count this inode + * @retval 0 don't count this inode + * @retval -1 failure + * @retval -2 request ZLC delete + * + * @internal + */ +static int +_namei_examine_reg(char * path3, + char * dname, + IHandle_t * myIH, + FdHandle_t * linkHandle, + int (*writeFun) (FILE *, struct ViceInodeInfo *, char *, + char *), + FILE * fp, + int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *), + int singleVolumeNumber, + void *rock) +{ + int ret = 0; + struct ViceInodeInfo info; +#ifdef DELETE_ZLC + int i; /* XXX this isn't set anywhere, nor was it set in + * namei_ListAFSSubdirs. wtf? */ +#endif + + if (DecodeInode(path3, dname, &info, myIH->ih_vid) < 0) { + goto error; + } + + info.linkCount = + namei_GetLinkCount2(linkHandle, + info.inodeNumber, 1, 1, Testing); + if (info.linkCount == 0) { +#ifdef DELETE_ZLC + Log("Found 0 link count file %s/%s, deleting it.\n", path3, dname); +#ifdef AFS_SALSRV_ENV + /* defer -- the AddToZLCDeleteList() interface is not MT-safe */ + ret = -2; +#else /* !AFS_SALSRV_ENV */ + AddToZLCDeleteList((char)i, dname); +#endif /* !AFS_SALSRV_ENV */ +#else /* !DELETE_ZLC */ + Log("Found 0 link count file %s/%s.\n", path3, + dname); +#endif + goto error; + } + + if (!judgeFun || + (*judgeFun) (&info, singleVolumeNumber, rock)) { + ret = 1; + if ((*writeFun) (fp, &info, path3, dname) < 0) { + ret = -1; + } + } + + error: + return ret; +} + +/** + * listsubdirs work queue node. + */ +struct listsubdirs_work_node { +#ifdef AFS_SALSRV_ENV + int *error; /**< *error set if an error was + * encountered in any listsubdirs + * thread. */ +#endif + + IHandle_t * IH; /**< volume directory handle */ + FdHandle_t *linkHandle; /**< namei link count fd handle. when + * examinining the link table special + * inode, this will be pointed at the + * link table + */ + FILE * fp; /**< file pointer for writeFun */ + + /** function which will write inode metadata to fp */ + int (*writeFun) (FILE *, struct ViceInodeInfo *, char *, char *); + + /** inode filter function */ + int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *); + int singleVolumeNumber; /**< volume id filter */ + void * rock; /**< pointer passed to writeFun and judgeFun */ + int code; /**< return code from examine function */ + int special; /**< asserted when this is a volume + * special file */ +}; + +/** + * simple wrapper around _namei_examine_special and _namei_examine_reg. + * + * @param[in] work the struct listsubdirs_work_node for the associated + * "list subdirs" job + * @param[in] dir the directory to examine + * @param[in] filename the filename in 'dir' to examine + * + * @return operation status + * @retval 1 count this inode + * @retval 0 don't count this inode + * @retval -1 failure + */ +static_inline int +_namei_examine_file(const struct listsubdirs_work_node *work, char *dir, + char *filename) +{ + if (work->special) { + return _namei_examine_special(dir, filename, work->IH, + work->linkHandle, work->writeFun, work->fp, + work->judgeFun, work->singleVolumeNumber, + work->rock); + } else { + return _namei_examine_reg(dir, filename, work->IH, + work->linkHandle, work->writeFun, work->fp, + work->judgeFun, work->singleVolumeNumber, + work->rock); + } +} + + +#ifdef AFS_SALSRV_ENV +/** @addtogroup afs_vol_salsrv_pario */ +/*@{*/ + +/** + * arguments for the _namei_examine_file_cbk callback function. + */ +struct listsubdirs_args { + const struct listsubdirs_work_node *work; /**< arguments that are the same + * for all invocations of + * _namei_examine_file_cbk, in + * threads */ + int *result; /**< where we can store the return code of _namei_examine_file */ + + char dir[512]; /**< directory to examine */ + char filename[256]; /**< filename in 'dir' to examine */ +}; + +/** + * a node in the list of results of listsubdir jobs. + */ +struct listsubdirs_result { + struct rx_queue q; + int inodes; /**< return value from _namei_examine_file */ +}; + +/** + * clean up a list of 'struct listsubdirs_result's and interpret the results. + * + * @param[in] resultlist a list of 'struct listsubdirs_result's + * + * @return number of inodes found + * @retval -1 error + */ +static int +_namei_listsubdirs_cleanup_results(struct rx_queue *resultlist) +{ + struct listsubdirs_result *res, *nres; + int ret = 0; + + for(queue_Scan(resultlist, res, nres, listsubdirs_result)) { + if (ret < 0) { + /* noop, retain erroneous error code */ + } else if (res->inodes < 0) { + ret = -1; + } else { + ret += res->inodes; + } + + queue_Remove(res); + free(res); + res = NULL; + } + + return ret; +} + +/** + * wait for the spawned listsubdirs jobs to finish, and return how many inodes + * they found. + * + * @param[in] queue queue to wait to finish + * @param[in] resultlist list of 'struct listsubdirs_result's that the queued + * jobs are storing their results in + * + * @return number of inodes found + * @retval -1 error + */ +static int +_namei_listsubdirs_wait(struct afs_work_queue *queue, struct rx_queue *resultlist) +{ + int code; + + code = afs_wq_wait_all(queue); + if (code) { + return -1; + } + + return _namei_listsubdirs_cleanup_results(resultlist); +} + +/** + * work queue entry point for examining namei files. + * + * @param[in] queue pointer to struct Vwork_queue + * @param[in] node pointer to struct Vwork_queue_node + * @param[in] queue_rock opaque pointer to struct salsrv_pool_state + * @param[in] node_rock opaque pointer to struct listsubdirs_work_node + * @param[in] caller_rock opaque pointer to struct salsrv_worker_thread_state + * + * @return operation status + * + * @see Vwork_queue_callback_func_t + * + * @internal + */ +static int +_namei_examine_file_cbk(struct afs_work_queue *queue, + struct afs_work_queue_node *node, + void *queue_rock, + void *node_rock, + void *caller_rock) +{ + int code; + struct listsubdirs_args *args = node_rock; + const struct listsubdirs_work_node * work = args->work; + char *dir = args->dir; + char *filename = args->filename; + + code = _namei_examine_file(work, dir, filename); + + *(args->result) = code; + + if (code < 0) { + *(work->error) = 1; + /* we've errored, so no point in letting more jobs continue */ + afs_wq_shutdown(queue); + } + + return 0; +} + +static pthread_once_t wq_once = PTHREAD_ONCE_INIT; +static pthread_key_t wq_key; + +/** + * create the wq_key key for storing a work queue. + */ +static void +_namei_wq_keycreate(void) +{ + osi_Assert(pthread_key_create(&wq_key, NULL) == 0); +} + +/** + * set the work queue for this thread to use for backgrounding namei ops. + * + * The work queue will be used in ListAFSSubdirs (called indirectly by + * ListViceInodes) to examine files in parallel. + * + * @param[in] wq the work queue to use + */ +void +namei_SetWorkQueue(struct afs_work_queue *wq) +{ + osi_Assert(pthread_once(&wq_once, _namei_wq_keycreate) == 0); + + osi_Assert(pthread_setspecific(wq_key, wq) == 0); +} + +/** + * enqueue an examine file work unit. + * + * @param[in] work the _namei_examine_file arguments that are common to + * all callers within the same ListAFSFiles operation + * @param[in] dir the specific directory to look at (string will be + * copied; can be stack/temporary memory) + * @param[in] filename the filename to look at (string will be copied; can be + * stack/temporary memory) + * @param[in] wq work queue to enqueue this work unit to + * @param[in] resultlist the list to append the 'struct listsubdirs_result' to + * for the enqueued work unit + * + * @return operation status + * @retval 0 success + * @retval -1 fatal error + * + * @note errors MUST be indicated by a -1 error code and nothing else, to be + * compatible with _namei_examine_reg and _namei_examine_special + * + * @internal + */ +static int +_namei_examine_file_spawn(const struct listsubdirs_work_node *work, + const char *dir, const char *filename, + struct afs_work_queue *wq, + struct rx_queue *resultlist) +{ + int code, ret = 0; + struct listsubdirs_args *args = NULL; + struct listsubdirs_result *result = NULL; + struct afs_work_queue_node *node = NULL; + struct afs_work_queue_add_opts opts; + + args = malloc(sizeof(*args)); + if (args == NULL) { + ret = -1; + goto error; + } + + result = malloc(sizeof(*result)); + if (result == NULL) { + ret = -1; + goto error; + } + + code = afs_wq_node_alloc(&node); + if (code) { + ret = -1; + goto error; + } + code = afs_wq_node_set_detached(node); + if (code) { + ret = -1; + goto error; + } + + args->work = work; + args->result = &result->inodes; + strlcpy(args->dir, dir, sizeof(args->dir)); + strlcpy(args->filename, filename, sizeof(args->filename)); + + code = afs_wq_node_set_callback(node, + &_namei_examine_file_cbk, + args, &free); + if (code) { + ret = -1; + goto error; + } + args = NULL; + + afs_wq_add_opts_init(&opts); + opts.donate = 1; + + code = afs_wq_add(wq, node, &opts); + if (code) { + ret = -1; + goto error; + } + node = NULL; + + queue_Append(resultlist, result); + result = NULL; + + error: + if (node) { + afs_wq_node_put(node); + node = NULL; + } + if (args) { + free(args); + args = NULL; + } + if (result) { + free(result); + result = NULL; + } + + return ret; +} + +/*@}*/ +#else /* !AFS_SALSRV_ENV */ +# define _namei_examine_file_spawn(work, dir, file, wq, resultlist) \ + _namei_examine_file(work, dir, file) +#endif /* !AFS_SALSRV_ENV */ + +/** + * traverse and check inodes. * + * @param[in] dirIH volume group directory handle + * @param[in] writeFun function pointer which will write inode + * metadata to FILE stream fp + * @param[in] fp file stream where inode metadata gets + * written + * @param[in] judgeFun inode filter function. if not NULL, only + * inodes for which the filter returns non-zero + * will be written out by writeFun + * @param[in] singleVolumeNumber volume id filter. only inodes matching this + * filter are written out by writeFun + * @param[in] rock opaque pointer passed to judgeFun and writeFun * - * Return values: - * < 0 - an error - * > = 0 - number of AFS files found. + * @return operation status + * @retval <0 error + * @retval >=0 number of matching inodes found + * + * @todo the salsrv implementation may consume a lot of + * memory for a large volume. at some point we should + * probably write a background thread to asynchronously + * clean up the resultlist nodes to reduce memory footprint + * + * @internal */ static int namei_ListAFSSubDirs(IHandle_t * dirIH, int (*writeFun) (FILE *, struct ViceInodeInfo *, char *, - char *), FILE * fp, + char *), + FILE * fp, int (*judgeFun) (struct ViceInodeInfo *, afs_uint32, void *), afs_uint32 singleVolumeNumber, void *rock) { + int code = 0, ret = 0; IHandle_t myIH = *dirIH; namei_t name; char path1[512], path2[512], path3[512]; DIR *dirp1, *dirp2, *dirp3; struct dirent *dp1, *dp2, *dp3; - struct ViceInodeInfo info; FdHandle_t linkHandle; int ninodes = 0; + struct listsubdirs_work_node work; +#ifdef AFS_SALSRV_ENV + int error = 0; + struct afs_work_queue *wq; + int wq_up = 0; + struct rx_queue resultlist; +#endif #ifdef DELETE_ZLC int i; static void AddToZLCDeleteList(char dir, char *name); @@ -1344,41 +1937,82 @@ namei_ListAFSSubDirs(IHandle_t * dirIH, (void)strcat(path1, NAMEI_SPECDIR); linkHandle.fd_fd = -1; +#ifdef AFS_SALSRV_ENV + osi_Assert(pthread_once(&wq_once, _namei_wq_keycreate) == 0); + + wq = pthread_getspecific(wq_key); + if (!wq) { + ret = -1; + goto error; + } + wq_up = 1; + queue_Init(&resultlist); +#endif + + memset(&work, 0, sizeof(work)); + work.linkHandle = &linkHandle; + work.IH = &myIH; + work.fp = fp; + work.writeFun = writeFun; + work.judgeFun = judgeFun; + work.singleVolumeNumber = singleVolumeNumber; + work.rock = rock; + work.special = 1; +#ifdef AFS_SALSRV_ENV + work.error = &error; +#endif + dirp1 = opendir(path1); if (dirp1) { while ((dp1 = readdir(dirp1))) { if (*dp1->d_name == '.') continue; - if (DecodeInode(path1, dp1->d_name, &info, myIH.ih_vid) < 0) - continue; - if (info.u.param[2] != VI_LINKTABLE) { - info.linkCount = 1; - } else { - /* Open this handle */ - (void)afs_snprintf(path2, sizeof path2, "%s/%s", path1, - dp1->d_name); - linkHandle.fd_fd = afs_open(path2, Testing ? O_RDONLY : O_RDWR, 0666); - info.linkCount = - namei_GetLinkCount2(&linkHandle, (Inode) 0, 1, 1, Testing); + +#ifdef AFS_SALSRV_ENV + if (error) { + closedir(dirp1); + ret = -1; + goto error; } - if (judgeFun && !(*judgeFun) (&info, singleVolumeNumber, rock)) - continue; +#endif /* AFS_SALSRV_ENV */ + + code = _namei_examine_file_spawn(&work, path1, dp1->d_name, wq, &resultlist); - if ((*writeFun) (fp, &info, path1, dp1->d_name) < 0) { - if (linkHandle.fd_fd >= 0) - close(linkHandle.fd_fd); + switch (code) { + case -1: + /* fatal error */ closedir(dirp1); - return -1; + ret = -1; + goto error; + + case 1: + /* count this inode */ +#ifndef AFS_SALSRV_ENV + ninodes++; +#endif + break; } - ninodes++; } closedir(dirp1); } +#ifdef AFS_SALSRV_ENV + /* effectively a barrier */ + code = _namei_listsubdirs_wait(wq, &resultlist); + if (code < 0 || error) { + ret = -1; + goto error; + } + error = 0; + ninodes += code; +#endif + /* Now run through all the other subdirs */ namei_HandleToVolDir(&name, &myIH); strlcpy(path1, name.n_path, sizeof(path1)); + work.special = 0; + dirp1 = opendir(path1); if (dirp1) { while ((dp1 = readdir(dirp1))) { @@ -1398,40 +2032,41 @@ namei_ListAFSSubDirs(IHandle_t * dirIH, /* Now we've got to the actual data */ afs_snprintf(path3, sizeof(path3), "%s/%s", path2, dp2->d_name); + dirp3 = opendir(path3); if (dirp3) { while ((dp3 = readdir(dirp3))) { if (*dp3->d_name == '.') continue; - if (DecodeInode - (path3, dp3->d_name, &info, myIH.ih_vid) < 0) - continue; - info.linkCount = - namei_GetLinkCount2(&linkHandle, - info.inodeNumber, 1, 1, Testing); - if (info.linkCount == 0) { -#ifdef DELETE_ZLC - Log("Found 0 link count file %s/%s, deleting it.\n", path3, dp3->d_name); - AddToZLCDeleteList((char)i, dp3->d_name); -#else - Log("Found 0 link count file %s/%s.\n", path3, - dp3->d_name); -#endif - continue; + +#ifdef AFS_SALSRV_ENV + if (error) { + closedir(dirp3); + closedir(dirp2); + closedir(dirp1); + ret = -1; + goto error; } - if (judgeFun - && !(*judgeFun) (&info, singleVolumeNumber, rock)) - continue; +#endif /* AFS_SALSRV_ENV */ - if ((*writeFun) (fp, &info, path3, dp3->d_name) < - 0) { - close(linkHandle.fd_fd); + code = _namei_examine_file_spawn(&work, path3, + dp3->d_name, wq, + &resultlist); + + switch (code) { + case -1: closedir(dirp3); closedir(dirp2); closedir(dirp1); - return -1; + ret = -1; + goto error; + + case 1: +#ifndef AFS_SALSRV_ENV + ninodes++; +#endif + break; } - ninodes++; } closedir(dirp3); } @@ -1442,17 +2077,42 @@ namei_ListAFSSubDirs(IHandle_t * dirIH, closedir(dirp1); } - if (linkHandle.fd_fd >= 0) - close(linkHandle.fd_fd); +#ifdef AFS_SALSRV_ENV + /* effectively a barrier */ + code = _namei_listsubdirs_wait(wq, &resultlist); + if (code < 0 || error) { + ret = -1; + goto error; + } + error = 0; + ninodes += code; + wq_up = 0; +#endif + if (!ninodes) { /* Then why does this directory exist? Blow it away. */ namei_HandleToVolDir(&name, dirIH); namei_RemoveDataDirectories(&name); } - return ninodes; + error: +#ifdef AFS_SALSRV_ENV + if (wq_up) { + afs_wq_wait_all(wq); + } + _namei_listsubdirs_cleanup_results(&resultlist); +#endif + if (linkHandle.fd_fd >= 0) + close(linkHandle.fd_fd); + + if (!ret) { + ret = ninodes; + } + return ret; } +/*@}*/ + static int DecodeVolumeName(char *name, unsigned int *vid) { diff --git a/src/vol/namei_ops.h b/src/vol/namei_ops.h index b76cdf08a..6705ebb0e 100644 --- a/src/vol/namei_ops.h +++ b/src/vol/namei_ops.h @@ -77,6 +77,11 @@ void namei_HandleToName(namei_t * name, IHandle_t * h); int namei_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId); int namei_replace_file_by_hardlink(IHandle_t *hLink, IHandle_t *hTarget); +# ifdef AFS_SALSRV_ENV +# include +extern void namei_SetWorkQueue(struct afs_work_queue *wq); +# endif + #endif /* AFS_NAMEI_ENV */ #endif /* _AFS_NAMEI_OPS_H_H_ */