- if (n > 0)
- NFS_BUF_MAP(bp);
- } else if (vtype == VDIR) {
- OSAddAtomic(1, (SInt32*)&nfsstats.biocache_readdirs);
- error = nfs_lock(np, NFS_NODE_LOCK_SHARED);
- if (error || (np->n_direofoffset && (uio->uio_offset >= np->n_direofoffset))) {
- if (!error)
- nfs_unlock(np);
- if (eofflag)
- *eofflag = 1;
- FSDBG_BOT(514, np, 0xde0f0001, 0, 0);
- return (0);
- }
- nfs_unlock(np);
- lbn = uio->uio_offset / NFS_DIRBLKSIZ;
- on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
- error = nfs_buf_get(np, lbn, NFS_DIRBLKSIZ, thd, NBLK_READ, &bp);
- if (error) {
- FSDBG_BOT(514, np, 0xd1e0012, 0, error);
- return (error);
- }
- if (!ISSET(bp->nb_flags, NB_CACHE)) {
- SET(bp->nb_flags, NB_READ);
- error = nfs_buf_readdir(bp, ctx);
- if (error)
- nfs_buf_release(bp, 1);
- while (error == NFSERR_BAD_COOKIE) {
- error = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE);
- if (!error) {
- nfs_invaldir(np);
- nfs_unlock(np);
- }
- error = nfs_vinvalbuf(vp, 0, ctx, 1);
- /*
- * Yuck! The directory has been modified on the
- * server. The only way to get the block is by
- * reading from the beginning to get all the
- * offset cookies.
- */
- for (tlbn = 0; tlbn <= lbn && !error; tlbn++) {
- if ((error = nfs_lock(np, NFS_NODE_LOCK_SHARED)))
- break;
- if (np->n_direofoffset
- && (tlbn * NFS_DIRBLKSIZ) >= np->n_direofoffset) {
- nfs_unlock(np);
- if (eofflag)
- *eofflag = 1;
- FSDBG_BOT(514, np, 0xde0f0002, 0, 0);
- return (0);
- }
- nfs_unlock(np);
- error = nfs_buf_get(np, tlbn, NFS_DIRBLKSIZ, thd, NBLK_READ, &bp);
- if (error) {
- FSDBG_BOT(514, np, 0xd1e0013, 0, error);
- return (error);
- }
- if (!ISSET(bp->nb_flags, NB_CACHE)) {
- SET(bp->nb_flags, NB_READ);
- error = nfs_buf_readdir(bp, ctx);
- /*
- * no error + NB_INVAL == directory EOF,
- * use the block.
- */
- if (error == 0 && ISSET(bp->nb_flags, NB_INVAL)) {
- if (eofflag)
- *eofflag = 1;
- break;
- }
- }
- /*
- * An error will throw away the block and the
- * for loop will break out. If no error and this
- * is not the block we want, we throw away the
- * block and go for the next one via the for loop.
- */
- if (error || (tlbn < lbn))
- nfs_buf_release(bp, 1);
- }
- }
- /*
- * The above while is repeated if we hit another cookie
- * error. If we hit an error and it wasn't a cookie error,
- * we give up.
- */
- if (error) {
- FSDBG_BOT(514, np, 0xd1e0014, 0, error);
- return (error);
- }
- }
- /*
- * Make sure we use a signed variant of min() since
- * the second term may be negative.
- */
- // LP64todo - fix this!
- n = lmin(uio_uio_resid(uio), bp->nb_validend - on);
- /*
- * We keep track of the directory eof in
- * np->n_direofoffset and chop it off as an
- * extra step right here.
- */
- if ((error = nfs_lock(np, NFS_NODE_LOCK_SHARED))) {
- FSDBG_BOT(514, np, 0xd1e0115, 0, error);
- return (error);
- }
- if (np->n_direofoffset &&
- n > np->n_direofoffset - uio->uio_offset)
- n = np->n_direofoffset - uio->uio_offset;
- nfs_unlock(np);
- /*
- * Make sure that we return an integral number of entries so
- * that any subsequent calls will start copying from the start
- * of the next entry.
- *
- * If the current value of n has the last entry cut short,
- * set n to copy everything up to the last entry instead.
- */