Commit 051e7cd4 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Tim Shimmin

[XFS] use filldir internally

Currently xfs has a rather complicated internal scheme to allow for
different directory formats in IRIX. This patch rips all code related to
this out and pushes useage of the Linux filldir callback into the lowlevel
directory code. This does not make the code any less portable because
filldir can be used to create dirents of all possible variations
(including the IRIX ones as proved by the IRIX binary emulation code under
arch/mips/).

This patch get rid of an unessecary copy in the readdir path, about 400
lines of code and one of the last two users of the uio structure.

This version is updated to deal with dmapi aswell which greatly simplifies
the get_dirattrs code. The dmapi part has been tested using the
get_dirattrs tools from the xfstest dmapi suite1 with various small and
large directories.

SGI-PV: 968563
SGI-Modid: xfs-linux-melb:xfs-kern:29478a
Signed-off-by: default avatarChristoph Hellwig <hch@infradead.org>
Signed-off-by: default avatarDavid Chinner <dgc@sgi.com>
Signed-off-by: default avatarTim Shimmin <tes@sgi.com>
parent 2bdf7cd0
...@@ -233,74 +233,30 @@ xfs_file_readdir( ...@@ -233,74 +233,30 @@ xfs_file_readdir(
void *dirent, void *dirent,
filldir_t filldir) filldir_t filldir)
{ {
int error = 0; struct inode *inode = filp->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(filp->f_path.dentry->d_inode); bhv_vnode_t *vp = vn_from_inode(inode);
uio_t uio; int error;
iovec_t iov; size_t bufsize;
int eof = 0;
caddr_t read_buf; /*
int namelen, size = 0; * The Linux API doesn't pass down the total size of the buffer
size_t rlen = PAGE_CACHE_SIZE; * we read into down to the filesystem. With the filldir concept
xfs_off_t start_offset, curr_offset; * it's not needed for correct information, but the XFS dir2 leaf
xfs_dirent_t *dbp = NULL; * code wants an estimate of the buffer size to calculate it's
* readahead window and size the buffers used for mapping to
/* Try fairly hard to get memory */ * physical blocks.
do { *
if ((read_buf = kmalloc(rlen, GFP_KERNEL))) * Try to give it an estimate that's good enough, maybe at some
break; * point we can change the ->readdir prototype to include the
rlen >>= 1; * buffer size.
} while (rlen >= 1024); */
bufsize = (size_t)min_t(loff_t, PAGE_SIZE, inode->i_size);
if (read_buf == NULL)
return -ENOMEM;
uio.uio_iov = &iov;
uio.uio_segflg = UIO_SYSSPACE;
curr_offset = filp->f_pos;
if (filp->f_pos != 0x7fffffff)
uio.uio_offset = filp->f_pos;
else
uio.uio_offset = 0xffffffff;
while (!eof) {
uio.uio_resid = iov.iov_len = rlen;
iov.iov_base = read_buf;
uio.uio_iovcnt = 1;
start_offset = uio.uio_offset;
error = bhv_vop_readdir(vp, &uio, NULL, &eof);
if ((uio.uio_offset == start_offset) || error) {
size = 0;
break;
}
size = rlen - uio.uio_resid;
dbp = (xfs_dirent_t *)read_buf;
while (size > 0) {
namelen = strlen(dbp->d_name);
if (filldir(dirent, dbp->d_name, namelen,
(loff_t) curr_offset & 0x7fffffff,
(ino_t) dbp->d_ino,
DT_UNKNOWN)) {
goto done;
}
size -= dbp->d_reclen;
curr_offset = (loff_t)dbp->d_off /* & 0x7fffffff */;
dbp = (xfs_dirent_t *)((char *)dbp + dbp->d_reclen);
}
}
done:
if (!error) {
if (size == 0)
filp->f_pos = uio.uio_offset & 0x7fffffff;
else if (dbp)
filp->f_pos = curr_offset;
}
kfree(read_buf); error = bhv_vop_readdir(vp, dirent, bufsize,
return -error; (xfs_off_t *)&filp->f_pos, filldir);
if (error)
return -error;
return 0;
} }
STATIC int STATIC int
......
...@@ -161,8 +161,8 @@ typedef int (*vop_rename_t)(bhv_desc_t *, bhv_vname_t *, bhv_vnode_t *, ...@@ -161,8 +161,8 @@ typedef int (*vop_rename_t)(bhv_desc_t *, bhv_vname_t *, bhv_vnode_t *,
typedef int (*vop_mkdir_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *, typedef int (*vop_mkdir_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *,
bhv_vnode_t **, struct cred *); bhv_vnode_t **, struct cred *);
typedef int (*vop_rmdir_t)(bhv_desc_t *, bhv_vname_t *, struct cred *); typedef int (*vop_rmdir_t)(bhv_desc_t *, bhv_vname_t *, struct cred *);
typedef int (*vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *, typedef int (*vop_readdir_t)(bhv_desc_t *, void *dirent, size_t bufsize,
int *); xfs_off_t *offset, filldir_t filldir);
typedef int (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*, typedef int (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*,
char *, bhv_vnode_t **, struct cred *); char *, bhv_vnode_t **, struct cred *);
typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int, typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int,
...@@ -267,8 +267,8 @@ typedef struct bhv_vnodeops { ...@@ -267,8 +267,8 @@ typedef struct bhv_vnodeops {
#define bhv_vop_mkdir(dp,d,vap,vpp,cr) \ #define bhv_vop_mkdir(dp,d,vap,vpp,cr) \
VOP(vop_mkdir, dp)(VNHEAD(dp),d,vap,vpp,cr) VOP(vop_mkdir, dp)(VNHEAD(dp),d,vap,vpp,cr)
#define bhv_vop_rmdir(dp,d,cr) VOP(vop_rmdir, dp)(VNHEAD(dp),d,cr) #define bhv_vop_rmdir(dp,d,cr) VOP(vop_rmdir, dp)(VNHEAD(dp),d,cr)
#define bhv_vop_readdir(vp,uiop,cr,eofp) \ #define bhv_vop_readdir(vp,dirent,bufsize,offset,filldir) \
VOP(vop_readdir, vp)(VNHEAD(vp),uiop,cr,eofp) VOP(vop_readdir, vp)(VNHEAD(vp),dirent,bufsize,offset,filldir)
#define bhv_vop_symlink(dvp,d,vap,tnm,vpp,cr) \ #define bhv_vop_symlink(dvp,d,vap,tnm,vpp,cr) \
VOP(vop_symlink, dvp)(VNHEAD(dvp),d,vap,tnm,vpp,cr) VOP(vop_symlink, dvp)(VNHEAD(dvp),d,vap,tnm,vpp,cr)
#define bhv_vop_readlink(vp,uiop,fl,cr) \ #define bhv_vop_readlink(vp,uiop,fl,cr) \
......
...@@ -43,8 +43,6 @@ ...@@ -43,8 +43,6 @@
#include "xfs_dir2_trace.h" #include "xfs_dir2_trace.h"
#include "xfs_error.h" #include "xfs_error.h"
static int xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa);
static int xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa);
void void
xfs_dir_mount( xfs_dir_mount(
...@@ -293,47 +291,35 @@ xfs_dir_removename( ...@@ -293,47 +291,35 @@ xfs_dir_removename(
* Read a directory. * Read a directory.
*/ */
int int
xfs_dir_getdents( xfs_readdir(
xfs_trans_t *tp, bhv_desc_t *dir_bdp,
xfs_inode_t *dp, void *dirent,
uio_t *uio, /* caller's buffer control */ size_t bufsize,
int *eofp) /* out: eof reached */ xfs_off_t *offset,
filldir_t filldir)
{ {
int alignment; /* alignment required for ABI */ xfs_inode_t *dp = XFS_BHVTOI(dir_bdp);
xfs_dirent_t *dbp; /* malloc'ed buffer */
xfs_dir2_put_t put; /* entry formatting routine */
int rval; /* return value */ int rval; /* return value */
int v; /* type-checking value */ int v; /* type-checking value */
vn_trace_entry(BHV_TO_VNODE(dir_bdp), __FUNCTION__,
(inst_t *)__return_address);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return XFS_ERROR(EIO);
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
XFS_STATS_INC(xs_dir_getdents); XFS_STATS_INC(xs_dir_getdents);
/*
* If our caller has given us a single contiguous aligned memory buffer,
* just work directly within that buffer. If it's in user memory,
* lock it down first.
*/
alignment = sizeof(xfs_off_t) - 1;
if ((uio->uio_iovcnt == 1) &&
(((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) &&
((uio->uio_iov[0].iov_len & alignment) == 0)) {
dbp = NULL;
put = xfs_dir2_put_dirent64_direct;
} else {
dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP);
put = xfs_dir2_put_dirent64_uio;
}
*eofp = 0;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put); rval = xfs_dir2_sf_getdents(dp, dirent, offset, filldir);
else if ((rval = xfs_dir2_isblock(tp, dp, &v))) else if ((rval = xfs_dir2_isblock(NULL, dp, &v)))
; ;
else if (v) else if (v)
rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put); rval = xfs_dir2_block_getdents(dp, dirent, offset, filldir);
else else
rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put); rval = xfs_dir2_leaf_getdents(dp, dirent, bufsize, offset,
if (dbp != NULL) filldir);
kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN);
return rval; return rval;
} }
...@@ -612,77 +598,6 @@ xfs_dir2_isleaf( ...@@ -612,77 +598,6 @@ xfs_dir2_isleaf(
return 0; return 0;
} }
/*
* Getdents put routine for 64-bit ABI, direct form.
*/
static int
xfs_dir2_put_dirent64_direct(
xfs_dir2_put_args_t *pa)
{
xfs_dirent_t *idbp; /* dirent pointer */
iovec_t *iovp; /* io vector */
int namelen; /* entry name length */
int reclen; /* entry total length */
uio_t *uio; /* I/O control */
namelen = pa->namelen;
reclen = DIRENTSIZE(namelen);
uio = pa->uio;
/*
* Won't fit in the remaining space.
*/
if (reclen > uio->uio_resid) {
pa->done = 0;
return 0;
}
iovp = uio->uio_iov;
idbp = (xfs_dirent_t *)iovp->iov_base;
iovp->iov_base = (char *)idbp + reclen;
iovp->iov_len -= reclen;
uio->uio_resid -= reclen;
idbp->d_reclen = reclen;
idbp->d_ino = pa->ino;
idbp->d_off = pa->cook;
idbp->d_name[namelen] = '\0';
pa->done = 1;
memcpy(idbp->d_name, pa->name, namelen);
return 0;
}
/*
* Getdents put routine for 64-bit ABI, uio form.
*/
static int
xfs_dir2_put_dirent64_uio(
xfs_dir2_put_args_t *pa)
{
xfs_dirent_t *idbp; /* dirent pointer */
int namelen; /* entry name length */
int reclen; /* entry total length */
int rval; /* return value */
uio_t *uio; /* I/O control */
namelen = pa->namelen;
reclen = DIRENTSIZE(namelen);
uio = pa->uio;
/*
* Won't fit in the remaining space.
*/
if (reclen > uio->uio_resid) {
pa->done = 0;
return 0;
}
idbp = pa->dbp;
idbp->d_reclen = reclen;
idbp->d_ino = pa->ino;
idbp->d_off = pa->cook;
idbp->d_name[namelen] = '\0';
memcpy(idbp->d_name, pa->name, namelen);
rval = xfs_uio_read((caddr_t)idbp, reclen, uio);
pa->done = (rval == 0);
return rval;
}
/* /*
* Remove the given block from the directory. * Remove the given block from the directory.
* This routine is used for data and free blocks, leaf/node are done * This routine is used for data and free blocks, leaf/node are done
......
...@@ -59,21 +59,6 @@ typedef __uint32_t xfs_dir2_db_t; ...@@ -59,21 +59,6 @@ typedef __uint32_t xfs_dir2_db_t;
*/ */
typedef xfs_off_t xfs_dir2_off_t; typedef xfs_off_t xfs_dir2_off_t;
/*
* For getdents, argument struct for put routines.
*/
typedef int (*xfs_dir2_put_t)(struct xfs_dir2_put_args *pa);
typedef struct xfs_dir2_put_args {
xfs_off_t cook; /* cookie of (next) entry */
xfs_intino_t ino; /* inode number */
xfs_dirent_t *dbp; /* buffer pointer */
char *name; /* directory entry name */
int namelen; /* length of name */
int done; /* output: set if value was stored */
xfs_dir2_put_t put; /* put function ptr (i/o) */
struct uio *uio; /* uio control structure */
} xfs_dir2_put_args_t;
/* /*
* Generic directory interface routines * Generic directory interface routines
*/ */
...@@ -92,8 +77,6 @@ extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, ...@@ -92,8 +77,6 @@ extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
char *name, int namelen, xfs_ino_t ino, char *name, int namelen, xfs_ino_t ino,
xfs_fsblock_t *first, xfs_fsblock_t *first,
struct xfs_bmap_free *flist, xfs_extlen_t tot); struct xfs_bmap_free *flist, xfs_extlen_t tot);
extern int xfs_dir_getdents(struct xfs_trans *tp, struct xfs_inode *dp,
uio_t *uio, int *eofp);
extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp, extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
char *name, int namelen, xfs_ino_t inum, char *name, int namelen, xfs_ino_t inum,
xfs_fsblock_t *first, xfs_fsblock_t *first,
...@@ -101,6 +84,8 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp, ...@@ -101,6 +84,8 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp, extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
char *name, int namelen); char *name, int namelen);
extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
extern int xfs_readdir(bhv_desc_t *dir_bdp, void *dirent, size_t bufsize,
xfs_off_t *offset, filldir_t filldir);
/* /*
* Utility routines for v2 directories. * Utility routines for v2 directories.
......
...@@ -432,12 +432,10 @@ xfs_dir2_block_addname( ...@@ -432,12 +432,10 @@ xfs_dir2_block_addname(
*/ */
int /* error */ int /* error */
xfs_dir2_block_getdents( xfs_dir2_block_getdents(
xfs_trans_t *tp, /* transaction (NULL) */
xfs_inode_t *dp, /* incore inode */ xfs_inode_t *dp, /* incore inode */
uio_t *uio, /* caller's buffer control */ void *dirent,
int *eofp, /* eof reached? (out) */ xfs_off_t *offset,
xfs_dirent_t *dbp, /* caller's buffer */ filldir_t filldir)
xfs_dir2_put_t put) /* abi's formatting function */
{ {
xfs_dir2_block_t *block; /* directory block structure */ xfs_dir2_block_t *block; /* directory block structure */
xfs_dabuf_t *bp; /* buffer for block */ xfs_dabuf_t *bp; /* buffer for block */
...@@ -447,31 +445,32 @@ xfs_dir2_block_getdents( ...@@ -447,31 +445,32 @@ xfs_dir2_block_getdents(
char *endptr; /* end of the data entries */ char *endptr; /* end of the data entries */
int error; /* error return value */ int error; /* error return value */
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_put_args_t p; /* arg package for put rtn */
char *ptr; /* current data entry */ char *ptr; /* current data entry */
int wantoff; /* starting block offset */ int wantoff; /* starting block offset */
xfs_ino_t ino;
xfs_off_t cook;
mp = dp->i_mount; mp = dp->i_mount;
/* /*
* If the block number in the offset is out of range, we're done. * If the block number in the offset is out of range, we're done.
*/ */
if (xfs_dir2_dataptr_to_db(mp, uio->uio_offset) > mp->m_dirdatablk) { if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) {
*eofp = 1;
return 0; return 0;
} }
/* /*
* Can't read the block, give up, else get dabuf in bp. * Can't read the block, give up, else get dabuf in bp.
*/ */
if ((error = error = xfs_da_read_buf(NULL, dp, mp->m_dirdatablk, -1,
xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { &bp, XFS_DATA_FORK);
if (error)
return error; return error;
}
ASSERT(bp != NULL); ASSERT(bp != NULL);
/* /*
* Extract the byte offset we start at from the seek pointer. * Extract the byte offset we start at from the seek pointer.
* We'll skip entries before this. * We'll skip entries before this.
*/ */
wantoff = xfs_dir2_dataptr_to_off(mp, uio->uio_offset); wantoff = xfs_dir2_dataptr_to_off(mp, *offset);
block = bp->data; block = bp->data;
xfs_dir2_data_check(dp, bp); xfs_dir2_data_check(dp, bp);
/* /*
...@@ -480,9 +479,7 @@ xfs_dir2_block_getdents( ...@@ -480,9 +479,7 @@ xfs_dir2_block_getdents(
btp = xfs_dir2_block_tail_p(mp, block); btp = xfs_dir2_block_tail_p(mp, block);
ptr = (char *)block->u; ptr = (char *)block->u;
endptr = (char *)xfs_dir2_block_leaf_p(btp); endptr = (char *)xfs_dir2_block_leaf_p(btp);
p.dbp = dbp;
p.put = put;
p.uio = uio;
/* /*
* Loop over the data portion of the block. * Loop over the data portion of the block.
* Each object is a real entry (dep) or an unused one (dup). * Each object is a real entry (dep) or an unused one (dup).
...@@ -508,33 +505,24 @@ xfs_dir2_block_getdents( ...@@ -508,33 +505,24 @@ xfs_dir2_block_getdents(
*/ */
if ((char *)dep - (char *)block < wantoff) if ((char *)dep - (char *)block < wantoff)
continue; continue;
/*
* Set up argument structure for put routine.
*/
p.namelen = dep->namelen;
p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
ptr - (char *)block); ptr - (char *)block);
p.ino = be64_to_cpu(dep->inumber); ino = be64_to_cpu(dep->inumber);
#if XFS_BIG_INUMS #if XFS_BIG_INUMS
p.ino += mp->m_inoadd; ino += mp->m_inoadd;
#endif #endif
p.name = (char *)dep->name;
/*
* Put the entry in the caller's buffer.
*/
error = p.put(&p);
/* /*
* If it didn't fit, set the final offset to here & return. * If it didn't fit, set the final offset to here & return.
*/ */
if (!p.done) { if (filldir(dirent, dep->name, dep->namelen, cook,
uio->uio_offset = ino, DT_UNKNOWN)) {
xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, *offset = xfs_dir2_db_off_to_dataptr(mp,
mp->m_dirdatablk,
(char *)dep - (char *)block); (char *)dep - (char *)block);
xfs_da_brelse(tp, bp); xfs_da_brelse(NULL, bp);
return error; return 0;
} }
} }
...@@ -542,13 +530,8 @@ xfs_dir2_block_getdents( ...@@ -542,13 +530,8 @@ xfs_dir2_block_getdents(
* Reached the end of the block. * Reached the end of the block.
* Set the offset to a non-existent block 1 and return. * Set the offset to a non-existent block 1 and return.
*/ */
*eofp = 1; *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
xfs_da_brelse(NULL, bp);
uio->uio_offset =
xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
xfs_da_brelse(tp, bp);
return 0; return 0;
} }
......
...@@ -80,9 +80,8 @@ xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp) ...@@ -80,9 +80,8 @@ xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp)
* Function declarations. * Function declarations.
*/ */
extern int xfs_dir2_block_addname(struct xfs_da_args *args); extern int xfs_dir2_block_addname(struct xfs_da_args *args);
extern int xfs_dir2_block_getdents(struct xfs_trans *tp, struct xfs_inode *dp, extern int xfs_dir2_block_getdents(struct xfs_inode *dp, void *dirent,
struct uio *uio, int *eofp, xfs_off_t *offset, filldir_t filldir);
struct xfs_dirent *dbp, xfs_dir2_put_t put);
extern int xfs_dir2_block_lookup(struct xfs_da_args *args); extern int xfs_dir2_block_lookup(struct xfs_da_args *args);
extern int xfs_dir2_block_removename(struct xfs_da_args *args); extern int xfs_dir2_block_removename(struct xfs_da_args *args);
extern int xfs_dir2_block_replace(struct xfs_da_args *args); extern int xfs_dir2_block_replace(struct xfs_da_args *args);
......
...@@ -749,12 +749,11 @@ xfs_dir2_leaf_compact_x1( ...@@ -749,12 +749,11 @@ xfs_dir2_leaf_compact_x1(
*/ */
int /* error */ int /* error */
xfs_dir2_leaf_getdents( xfs_dir2_leaf_getdents(
xfs_trans_t *tp, /* transaction pointer */
xfs_inode_t *dp, /* incore directory inode */ xfs_inode_t *dp, /* incore directory inode */
uio_t *uio, /* I/O control & vectors */ void *dirent,
int *eofp, /* out: reached end of dir */ size_t bufsize,
xfs_dirent_t *dbp, /* caller's buffer */ xfs_off_t *offset,
xfs_dir2_put_t put) /* ABI formatting routine */ filldir_t filldir)
{ {
xfs_dabuf_t *bp; /* data block buffer */ xfs_dabuf_t *bp; /* data block buffer */
int byteoff; /* offset in current block */ int byteoff; /* offset in current block */
...@@ -763,7 +762,6 @@ xfs_dir2_leaf_getdents( ...@@ -763,7 +762,6 @@ xfs_dir2_leaf_getdents(
xfs_dir2_data_t *data; /* data block structure */ xfs_dir2_data_t *data; /* data block structure */
xfs_dir2_data_entry_t *dep; /* data entry */ xfs_dir2_data_entry_t *dep; /* data entry */
xfs_dir2_data_unused_t *dup; /* unused entry */ xfs_dir2_data_unused_t *dup; /* unused entry */
int eof; /* reached end of directory */
int error = 0; /* error return value */ int error = 0; /* error return value */
int i; /* temporary loop index */ int i; /* temporary loop index */
int j; /* temporary loop index */ int j; /* temporary loop index */
...@@ -776,46 +774,38 @@ xfs_dir2_leaf_getdents( ...@@ -776,46 +774,38 @@ xfs_dir2_leaf_getdents(
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_off_t newoff; /* new curoff after new blk */ xfs_dir2_off_t newoff; /* new curoff after new blk */
int nmap; /* mappings to ask xfs_bmapi */ int nmap; /* mappings to ask xfs_bmapi */
xfs_dir2_put_args_t *p; /* formatting arg bundle */
char *ptr = NULL; /* pointer to current data */ char *ptr = NULL; /* pointer to current data */
int ra_current; /* number of read-ahead blks */ int ra_current; /* number of read-ahead blks */
int ra_index; /* *map index for read-ahead */ int ra_index; /* *map index for read-ahead */
int ra_offset; /* map entry offset for ra */ int ra_offset; /* map entry offset for ra */
int ra_want; /* readahead count wanted */ int ra_want; /* readahead count wanted */
xfs_ino_t ino;
/* /*
* If the offset is at or past the largest allowed value, * If the offset is at or past the largest allowed value,
* give up right away, return eof. * give up right away.
*/ */
if (uio->uio_offset >= XFS_DIR2_MAX_DATAPTR) { if (*offset >= XFS_DIR2_MAX_DATAPTR)
*eofp = 1;
return 0; return 0;
}
mp = dp->i_mount; mp = dp->i_mount;
/*
* Setup formatting arguments.
*/
p = kmem_alloc(sizeof(*p), KM_SLEEP);
p->dbp = dbp;
p->put = put;
p->uio = uio;
/* /*
* Set up to bmap a number of blocks based on the caller's * Set up to bmap a number of blocks based on the caller's
* buffer size, the directory block size, and the filesystem * buffer size, the directory block size, and the filesystem
* block size. * block size.
*/ */
map_size = map_size = howmany(bufsize + mp->m_dirblksize, mp->m_sb.sb_blocksize);
howmany(uio->uio_resid + mp->m_dirblksize,
mp->m_sb.sb_blocksize);
map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP); map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP);
map_valid = ra_index = ra_offset = ra_current = map_blocks = 0; map_valid = ra_index = ra_offset = ra_current = map_blocks = 0;
bp = NULL; bp = NULL;
eof = 1;
/* /*
* Inside the loop we keep the main offset value as a byte offset * Inside the loop we keep the main offset value as a byte offset
* in the directory file. * in the directory file.
*/ */
curoff = xfs_dir2_dataptr_to_byte(mp, uio->uio_offset); curoff = xfs_dir2_dataptr_to_byte(mp, *offset);
/* /*
* Force this conversion through db so we truncate the offset * Force this conversion through db so we truncate the offset
* down to get the start of the data block. * down to get the start of the data block.
...@@ -836,7 +826,7 @@ xfs_dir2_leaf_getdents( ...@@ -836,7 +826,7 @@ xfs_dir2_leaf_getdents(
* take it out of the mapping. * take it out of the mapping.
*/ */
if (bp) { if (bp) {
xfs_da_brelse(tp, bp); xfs_da_brelse(NULL, bp);
bp = NULL; bp = NULL;
map_blocks -= mp->m_dirblkfsbs; map_blocks -= mp->m_dirblkfsbs;
/* /*
...@@ -862,8 +852,9 @@ xfs_dir2_leaf_getdents( ...@@ -862,8 +852,9 @@ xfs_dir2_leaf_getdents(
/* /*
* Recalculate the readahead blocks wanted. * Recalculate the readahead blocks wanted.
*/ */
ra_want = howmany(uio->uio_resid + mp->m_dirblksize, ra_want = howmany(bufsize + mp->m_dirblksize,
mp->m_sb.sb_blocksize) - 1; mp->m_sb.sb_blocksize) - 1;
/* /*
* If we don't have as many as we want, and we haven't * If we don't have as many as we want, and we haven't
* run out of data blocks, get some more mappings. * run out of data blocks, get some more mappings.
...@@ -876,7 +867,7 @@ xfs_dir2_leaf_getdents( ...@@ -876,7 +867,7 @@ xfs_dir2_leaf_getdents(
* we already have in the table. * we already have in the table.
*/ */
nmap = map_size - map_valid; nmap = map_size - map_valid;
error = xfs_bmapi(tp, dp, error = xfs_bmapi(NULL, dp,
map_off, map_off,
xfs_dir2_byte_to_da(mp, xfs_dir2_byte_to_da(mp,
XFS_DIR2_LEAF_OFFSET) - map_off, XFS_DIR2_LEAF_OFFSET) - map_off,
...@@ -939,7 +930,7 @@ xfs_dir2_leaf_getdents( ...@@ -939,7 +930,7 @@ xfs_dir2_leaf_getdents(
* mapping. * mapping.
*/ */
curdb = xfs_dir2_da_to_db(mp, map->br_startoff); curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
error = xfs_da_read_buf(tp, dp, map->br_startoff, error = xfs_da_read_buf(NULL, dp, map->br_startoff,
map->br_blockcount >= mp->m_dirblkfsbs ? map->br_blockcount >= mp->m_dirblkfsbs ?
XFS_FSB_TO_DADDR(mp, map->br_startblock) : XFS_FSB_TO_DADDR(mp, map->br_startblock) :
-1, -1,
...@@ -982,7 +973,7 @@ xfs_dir2_leaf_getdents( ...@@ -982,7 +973,7 @@ xfs_dir2_leaf_getdents(
* is a very rare case. * is a very rare case.
*/ */
else if (i > ra_current) { else if (i > ra_current) {
(void)xfs_da_reada_buf(tp, dp, (void)xfs_da_reada_buf(NULL, dp,
map[ra_index].br_startoff + map[ra_index].br_startoff +
ra_offset, XFS_DATA_FORK); ra_offset, XFS_DATA_FORK);
ra_current = i; ra_current = i;
...@@ -1089,46 +1080,39 @@ xfs_dir2_leaf_getdents( ...@@ -1089,46 +1080,39 @@ xfs_dir2_leaf_getdents(
*/ */
dep = (xfs_dir2_data_entry_t *)ptr; dep = (xfs_dir2_data_entry_t *)ptr;
p->namelen = dep->namelen; length = xfs_dir2_data_entsize(dep->namelen);
length = xfs_dir2_data_entsize(p->namelen);
p->cook = xfs_dir2_byte_to_dataptr(mp, curoff + length);
p->ino = be64_to_cpu(dep->inumber); ino = be64_to_cpu(dep->inumber);
#if XFS_BIG_INUMS #if XFS_BIG_INUMS
p->ino += mp->m_inoadd; ino += mp->m_inoadd;
#endif #endif
p->name = (char *)dep->name;
error = p->put(p);
/* /*
* Won't fit. Return to caller. * Won't fit. Return to caller.
*/ */
if (!p->done) { if (filldir(dirent, dep->name, dep->namelen,
eof = 0; xfs_dir2_byte_to_dataptr(mp, curoff + length),
ino, DT_UNKNOWN))
break; break;
}
/* /*
* Advance to next entry in the block. * Advance to next entry in the block.
*/ */
ptr += length; ptr += length;
curoff += length; curoff += length;
bufsize -= length;
} }
/* /*
* All done. Set output offset value to current offset. * All done. Set output offset value to current offset.
*/ */
*eofp = eof;
if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR)) if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
uio->uio_offset = XFS_DIR2_MAX_DATAPTR; *offset = XFS_DIR2_MAX_DATAPTR;
else else
uio->uio_offset = xfs_dir2_byte_to_dataptr(mp, curoff); *offset = xfs_dir2_byte_to_dataptr(mp, curoff);
kmem_free(map, map_size * sizeof(*map)); kmem_free(map, map_size * sizeof(*map));
kmem_free(p, sizeof(*p));
if (bp) if (bp)
xfs_da_brelse(tp, bp); xfs_da_brelse(NULL, bp);
return error; return error;
} }
......
...@@ -232,9 +232,9 @@ extern void xfs_dir2_leaf_compact(struct xfs_da_args *args, ...@@ -232,9 +232,9 @@ extern void xfs_dir2_leaf_compact(struct xfs_da_args *args,
extern void xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp, extern void xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp,
int *lowstalep, int *highstalep, int *lowstalep, int *highstalep,
int *lowlogp, int *highlogp); int *lowlogp, int *highlogp);
extern int xfs_dir2_leaf_getdents(struct xfs_trans *tp, struct xfs_inode *dp, extern int xfs_dir2_leaf_getdents(struct xfs_inode *dp, void *dirent,
struct uio *uio, int *eofp, size_t bufsize, xfs_off_t *offset,
struct xfs_dirent *dbp, xfs_dir2_put_t put); filldir_t filldir);
extern int xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno, extern int xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno,
struct xfs_dabuf **bpp, int magic); struct xfs_dabuf **bpp, int magic);
extern void xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp, extern void xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp,
......
...@@ -695,19 +695,18 @@ xfs_dir2_sf_create( ...@@ -695,19 +695,18 @@ xfs_dir2_sf_create(
int /* error */ int /* error */
xfs_dir2_sf_getdents( xfs_dir2_sf_getdents(
xfs_inode_t *dp, /* incore directory inode */ xfs_inode_t *dp, /* incore directory inode */
uio_t *uio, /* caller's buffer control */ void *dirent,
int *eofp, /* eof reached? (out) */ xfs_off_t *offset,
xfs_dirent_t *dbp, /* caller's buffer */ filldir_t filldir)
xfs_dir2_put_t put) /* abi's formatting function */
{ {
int error; /* error return value */
int i; /* shortform entry number */ int i; /* shortform entry number */
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_dataptr_t off; /* current entry's offset */ xfs_dir2_dataptr_t off; /* current entry's offset */
xfs_dir2_put_args_t p; /* arg package for put rtn */
xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
xfs_dir2_sf_t *sfp; /* shortform structure */ xfs_dir2_sf_t *sfp; /* shortform structure */
xfs_off_t dir_offset; xfs_dir2_dataptr_t dot_offset;
xfs_dir2_dataptr_t dotdot_offset;
xfs_ino_t ino;
mp = dp->i_mount; mp = dp->i_mount;
...@@ -720,8 +719,6 @@ xfs_dir2_sf_getdents( ...@@ -720,8 +719,6 @@ xfs_dir2_sf_getdents(
return XFS_ERROR(EIO); return XFS_ERROR(EIO);
} }
dir_offset = uio->uio_offset;
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL); ASSERT(dp->i_df.if_u1.if_data != NULL);
...@@ -732,108 +729,78 @@ xfs_dir2_sf_getdents( ...@@ -732,108 +729,78 @@ xfs_dir2_sf_getdents(
/* /*
* If the block number in the offset is out of range, we're done. * If the block number in the offset is out of range, we're done.
*/ */
if (xfs_dir2_dataptr_to_db(mp, dir_offset) > mp->m_dirdatablk) { if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk)
*eofp = 1;
return 0; return 0;
}
/* /*
* Set up putargs structure. * Precalculate offsets for . and .. as we will always need them.
*
* XXX(hch): the second argument is sometimes 0 and sometimes
* mp->m_dirdatablk.
*/ */
p.dbp = dbp; dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
p.put = put; XFS_DIR2_DATA_DOT_OFFSET);
p.uio = uio; dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOTDOT_OFFSET);
/* /*
* Put . entry unless we're starting past it. * Put . entry unless we're starting past it.
*/ */
if (dir_offset <= if (*offset <= dot_offset) {
xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, ino = dp->i_ino;
XFS_DIR2_DATA_DOT_OFFSET)) {
p.cook = xfs_dir2_db_off_to_dataptr(mp, 0,
XFS_DIR2_DATA_DOTDOT_OFFSET);
p.ino = dp->i_ino;
#if XFS_BIG_INUMS #if XFS_BIG_INUMS
p.ino += mp->m_inoadd; ino += mp->m_inoadd;
#endif #endif
p.name = "."; if (filldir(dirent, ".", 1, dotdot_offset, ino, DT_DIR)) {
p.namelen = 1; *offset = dot_offset;
return 0;
error = p.put(&p);
if (!p.done) {
uio->uio_offset =
xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOT_OFFSET);
return error;
} }
} }
/* /*
* Put .. entry unless we're starting past it. * Put .. entry unless we're starting past it.
*/ */
if (dir_offset <= if (*offset <= dotdot_offset) {
xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOTDOT_OFFSET)) { XFS_DIR2_DATA_FIRST_OFFSET);
p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
XFS_DIR2_DATA_FIRST_OFFSET);
p.ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
#if XFS_BIG_INUMS #if XFS_BIG_INUMS
p.ino += mp->m_inoadd; ino += mp->m_inoadd;
#endif #endif
p.name = ".."; if (filldir(dirent, "..", 2, off, ino, DT_DIR)) {
p.namelen = 2; *offset = dotdot_offset;
return 0;
error = p.put(&p);
if (!p.done) {
uio->uio_offset =
xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOTDOT_OFFSET);
return error;
} }
} }
/* /*
* Loop while there are more entries and put'ing works. * Loop while there are more entries and put'ing works.
*/ */
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count; for (i = 0; i < sfp->hdr.count; i++) {
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
xfs_dir2_sf_get_offset(sfep)); xfs_dir2_sf_get_offset(sfep));
if (dir_offset > off) if (*offset > off) {
sfep = xfs_dir2_sf_nextentry(sfp, sfep);
continue; continue;
}
p.namelen = sfep->namelen; ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
xfs_dir2_sf_get_offset(sfep) +
xfs_dir2_data_entsize(p.namelen));
p.ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
#if XFS_BIG_INUMS #if XFS_BIG_INUMS
p.ino += mp->m_inoadd; ino += mp->m_inoadd;
#endif #endif
p.name = (char *)sfep->name;
error = p.put(&p);
if (!p.done) { if (filldir(dirent, sfep->name, sfep->namelen,
uio->uio_offset = off; off + xfs_dir2_data_entsize(sfep->namelen),
return error; ino, DT_UNKNOWN)) {
*offset = off;
return 0;
} }
sfep = xfs_dir2_sf_nextentry(sfp, sfep);
} }
/* *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
* They all fit.
*/
*eofp = 1;
uio->uio_offset =
xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
return 0; return 0;
} }
......
...@@ -169,9 +169,8 @@ extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_dabuf *bp, ...@@ -169,9 +169,8 @@ extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_dabuf *bp,
int size, xfs_dir2_sf_hdr_t *sfhp); int size, xfs_dir2_sf_hdr_t *sfhp);
extern int xfs_dir2_sf_addname(struct xfs_da_args *args); extern int xfs_dir2_sf_addname(struct xfs_da_args *args);
extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino);
extern int xfs_dir2_sf_getdents(struct xfs_inode *dp, struct uio *uio, extern int xfs_dir2_sf_getdents(struct xfs_inode *dp, void *dirent,
int *eofp, struct xfs_dirent *dbp, xfs_off_t *offset, filldir_t filldir);
xfs_dir2_put_t put);
extern int xfs_dir2_sf_lookup(struct xfs_da_args *args); extern int xfs_dir2_sf_lookup(struct xfs_da_args *args);
extern int xfs_dir2_sf_removename(struct xfs_da_args *args); extern int xfs_dir2_sf_removename(struct xfs_da_args *args);
extern int xfs_dir2_sf_replace(struct xfs_da_args *args); extern int xfs_dir2_sf_replace(struct xfs_da_args *args);
......
...@@ -151,18 +151,6 @@ typedef __uint8_t xfs_arch_t; /* architecture of an xfs fs */ ...@@ -151,18 +151,6 @@ typedef __uint8_t xfs_arch_t; /* architecture of an xfs fs */
*/ */
#define MAXNAMELEN 256 #define MAXNAMELEN 256
typedef struct xfs_dirent { /* data from readdir() */
xfs_ino_t d_ino; /* inode number of entry */
xfs_off_t d_off; /* offset of disk directory entry */
unsigned short d_reclen; /* length of this record */
char d_name[1]; /* name of file */
} xfs_dirent_t;
#define DIRENTBASESIZE (((xfs_dirent_t *)0)->d_name - (char *)0)
#define DIRENTSIZE(namelen) \
((DIRENTBASESIZE + (namelen) + \
sizeof(xfs_off_t)) & ~(sizeof(xfs_off_t) - 1))
typedef enum { typedef enum {
XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
} xfs_lookup_t; } xfs_lookup_t;
......
...@@ -3284,37 +3284,6 @@ xfs_rmdir( ...@@ -3284,37 +3284,6 @@ xfs_rmdir(
goto std_return; goto std_return;
} }
/*
* Read dp's entries starting at uiop->uio_offset and translate them into
* bufsize bytes worth of struct dirents starting at bufbase.
*/
STATIC int
xfs_readdir(
bhv_desc_t *dir_bdp,
uio_t *uiop,
cred_t *credp,
int *eofp)
{
xfs_inode_t *dp;
xfs_trans_t *tp = NULL;
int error = 0;
uint lock_mode;
vn_trace_entry(BHV_TO_VNODE(dir_bdp), __FUNCTION__,
(inst_t *)__return_address);
dp = XFS_BHVTOI(dir_bdp);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return XFS_ERROR(EIO);
lock_mode = xfs_ilock_map_shared(dp);
error = xfs_dir_getdents(tp, dp, uiop, eofp);
xfs_iunlock_map_shared(dp, lock_mode);
return error;
}
STATIC int STATIC int
xfs_symlink( xfs_symlink(
bhv_desc_t *dir_bdp, bhv_desc_t *dir_bdp,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment