void *dirent,
filldir_t filldir)
{
- int error = 0;
- bhv_vnode_t *vp = vn_from_inode(filp->f_path.dentry->d_inode);
- uio_t uio;
- iovec_t iov;
- int eof = 0;
- caddr_t read_buf;
- int namelen, size = 0;
- size_t rlen = PAGE_CACHE_SIZE;
- xfs_off_t start_offset, curr_offset;
- xfs_dirent_t *dbp = NULL;
-
- /* Try fairly hard to get memory */
- do {
- if ((read_buf = kmalloc(rlen, GFP_KERNEL)))
- break;
- rlen >>= 1;
- } while (rlen >= 1024);
-
- 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;
- }
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ bhv_vnode_t *vp = vn_from_inode(inode);
+ int error;
+ size_t bufsize;
+
+ /*
+ * The Linux API doesn't pass down the total size of the buffer
+ * we read into down to the filesystem. With the filldir concept
+ * it's not needed for correct information, but the XFS dir2 leaf
+ * code wants an estimate of the buffer size to calculate it's
+ * readahead window and size the buffers used for mapping to
+ * physical blocks.
+ *
+ * Try to give it an estimate that's good enough, maybe at some
+ * point we can change the ->readdir prototype to include the
+ * buffer size.
+ */
+ bufsize = (size_t)min_t(loff_t, PAGE_SIZE, inode->i_size);
- kfree(read_buf);
- return -error;
+ error = bhv_vop_readdir(vp, dirent, bufsize,
+ (xfs_off_t *)&filp->f_pos, filldir);
+ if (error)
+ return -error;
+ return 0;
}
STATIC int
typedef int (*vop_mkdir_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *,
bhv_vnode_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 *,
- int *);
+typedef int (*vop_readdir_t)(bhv_desc_t *, void *dirent, size_t bufsize,
+ xfs_off_t *offset, filldir_t filldir);
typedef int (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*,
char *, bhv_vnode_t **, struct cred *);
typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int,
#define bhv_vop_mkdir(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_readdir(vp,uiop,cr,eofp) \
- VOP(vop_readdir, vp)(VNHEAD(vp),uiop,cr,eofp)
+#define bhv_vop_readdir(vp,dirent,bufsize,offset,filldir) \
+ VOP(vop_readdir, vp)(VNHEAD(vp),dirent,bufsize,offset,filldir)
#define bhv_vop_symlink(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) \
#include "xfs_dir2_trace.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
xfs_dir_mount(
* Read a directory.
*/
int
-xfs_dir_getdents(
- xfs_trans_t *tp,
- xfs_inode_t *dp,
- uio_t *uio, /* caller's buffer control */
- int *eofp) /* out: eof reached */
+xfs_readdir(
+ bhv_desc_t *dir_bdp,
+ void *dirent,
+ size_t bufsize,
+ xfs_off_t *offset,
+ filldir_t filldir)
{
- int alignment; /* alignment required for ABI */
- xfs_dirent_t *dbp; /* malloc'ed buffer */
- xfs_dir2_put_t put; /* entry formatting routine */
+ xfs_inode_t *dp = XFS_BHVTOI(dir_bdp);
int rval; /* return 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);
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)
- rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put);
- else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
+ rval = xfs_dir2_sf_getdents(dp, dirent, offset, filldir);
+ else if ((rval = xfs_dir2_isblock(NULL, dp, &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
- rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put);
- if (dbp != NULL)
- kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN);
+ rval = xfs_dir2_leaf_getdents(dp, dirent, bufsize, offset,
+ filldir);
return rval;
}
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.
* This routine is used for data and free blocks, leaf/node are done
*/
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
*/
char *name, int namelen, xfs_ino_t ino,
xfs_fsblock_t *first,
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,
char *name, int namelen, xfs_ino_t inum,
xfs_fsblock_t *first,
extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
char *name, int namelen);
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.
*/
int /* error */
xfs_dir2_block_getdents(
- xfs_trans_t *tp, /* transaction (NULL) */
xfs_inode_t *dp, /* incore inode */
- uio_t *uio, /* caller's buffer control */
- int *eofp, /* eof reached? (out) */
- xfs_dirent_t *dbp, /* caller's buffer */
- xfs_dir2_put_t put) /* abi's formatting function */
+ void *dirent,
+ xfs_off_t *offset,
+ filldir_t filldir)
{
xfs_dir2_block_t *block; /* directory block structure */
xfs_dabuf_t *bp; /* buffer for block */
char *endptr; /* end of the data entries */
int error; /* error return value */
xfs_mount_t *mp; /* filesystem mount point */
- xfs_dir2_put_args_t p; /* arg package for put rtn */
char *ptr; /* current data entry */
int wantoff; /* starting block offset */
+ xfs_ino_t ino;
+ xfs_off_t cook;
mp = dp->i_mount;
/*
* 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) {
- *eofp = 1;
+ if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) {
return 0;
}
/*
* Can't read the block, give up, else get dabuf in bp.
*/
- if ((error =
- xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) {
+ error = xfs_da_read_buf(NULL, dp, mp->m_dirdatablk, -1,
+ &bp, XFS_DATA_FORK);
+ if (error)
return error;
- }
+
ASSERT(bp != NULL);
/*
* Extract the byte offset we start at from the seek pointer.
* 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;
xfs_dir2_data_check(dp, bp);
/*
btp = xfs_dir2_block_tail_p(mp, block);
ptr = (char *)block->u;
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.
* Each object is a real entry (dep) or an unused one (dup).
*/
if ((char *)dep - (char *)block < wantoff)
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);
- p.ino = be64_to_cpu(dep->inumber);
+ ino = be64_to_cpu(dep->inumber);
#if XFS_BIG_INUMS
- p.ino += mp->m_inoadd;
+ ino += mp->m_inoadd;
#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 (!p.done) {
- uio->uio_offset =
- xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+ if (filldir(dirent, dep->name, dep->namelen, cook,
+ ino, DT_UNKNOWN)) {
+ *offset = xfs_dir2_db_off_to_dataptr(mp,
+ mp->m_dirdatablk,
(char *)dep - (char *)block);
- xfs_da_brelse(tp, bp);
- return error;
+ xfs_da_brelse(NULL, bp);
+ return 0;
}
}
* Reached the end of the block.
* Set the offset to a non-existent block 1 and return.
*/
- *eofp = 1;
-
- uio->uio_offset =
- xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
-
- xfs_da_brelse(tp, bp);
-
+ *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
+ xfs_da_brelse(NULL, bp);
return 0;
}
* Function declarations.
*/
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,
- struct uio *uio, int *eofp,
- struct xfs_dirent *dbp, xfs_dir2_put_t put);
+extern int xfs_dir2_block_getdents(struct xfs_inode *dp, void *dirent,
+ xfs_off_t *offset, filldir_t filldir);
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_replace(struct xfs_da_args *args);
*/
int /* error */
xfs_dir2_leaf_getdents(
- xfs_trans_t *tp, /* transaction pointer */
xfs_inode_t *dp, /* incore directory inode */
- uio_t *uio, /* I/O control & vectors */
- int *eofp, /* out: reached end of dir */
- xfs_dirent_t *dbp, /* caller's buffer */
- xfs_dir2_put_t put) /* ABI formatting routine */
+ void *dirent,
+ size_t bufsize,
+ xfs_off_t *offset,
+ filldir_t filldir)
{
xfs_dabuf_t *bp; /* data block buffer */
int byteoff; /* offset in current block */
xfs_dir2_data_t *data; /* data block structure */
xfs_dir2_data_entry_t *dep; /* data entry */
xfs_dir2_data_unused_t *dup; /* unused entry */
- int eof; /* reached end of directory */
int error = 0; /* error return value */
int i; /* temporary loop index */
int j; /* temporary loop index */
xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_off_t newoff; /* new curoff after new blk */
int nmap; /* mappings to ask xfs_bmapi */
- xfs_dir2_put_args_t *p; /* formatting arg bundle */
char *ptr = NULL; /* pointer to current data */
int ra_current; /* number of read-ahead blks */
int ra_index; /* *map index for read-ahead */
int ra_offset; /* map entry offset for ra */
int ra_want; /* readahead count wanted */
+ xfs_ino_t ino;
/*
* 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) {
- *eofp = 1;
+ if (*offset >= XFS_DIR2_MAX_DATAPTR)
return 0;
- }
+
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
* buffer size, the directory block size, and the filesystem
* block size.
*/
- map_size =
- howmany(uio->uio_resid + mp->m_dirblksize,
- mp->m_sb.sb_blocksize);
+ map_size = howmany(bufsize + mp->m_dirblksize, mp->m_sb.sb_blocksize);
map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP);
map_valid = ra_index = ra_offset = ra_current = map_blocks = 0;
bp = NULL;
- eof = 1;
+
/*
* Inside the loop we keep the main offset value as a byte offset
* 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
* down to get the start of the data block.
* take it out of the mapping.
*/
if (bp) {
- xfs_da_brelse(tp, bp);
+ xfs_da_brelse(NULL, bp);
bp = NULL;
map_blocks -= mp->m_dirblkfsbs;
/*
/*
* 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;
+
/*
* If we don't have as many as we want, and we haven't
* run out of data blocks, get some more mappings.
* we already have in the table.
*/
nmap = map_size - map_valid;
- error = xfs_bmapi(tp, dp,
+ error = xfs_bmapi(NULL, dp,
map_off,
xfs_dir2_byte_to_da(mp,
XFS_DIR2_LEAF_OFFSET) - map_off,
* mapping.
*/
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 ?
XFS_FSB_TO_DADDR(mp, map->br_startblock) :
-1,
* is a very rare case.
*/
else if (i > ra_current) {
- (void)xfs_da_reada_buf(tp, dp,
+ (void)xfs_da_reada_buf(NULL, dp,
map[ra_index].br_startoff +
ra_offset, XFS_DATA_FORK);
ra_current = i;
*/
dep = (xfs_dir2_data_entry_t *)ptr;
- p->namelen = dep->namelen;
-
- length = xfs_dir2_data_entsize(p->namelen);
-
- p->cook = xfs_dir2_byte_to_dataptr(mp, curoff + length);
+ length = xfs_dir2_data_entsize(dep->namelen);
- p->ino = be64_to_cpu(dep->inumber);
+ ino = be64_to_cpu(dep->inumber);
#if XFS_BIG_INUMS
- p->ino += mp->m_inoadd;
+ ino += mp->m_inoadd;
#endif
- p->name = (char *)dep->name;
-
- error = p->put(p);
/*
* Won't fit. Return to caller.
*/
- if (!p->done) {
- eof = 0;
+ if (filldir(dirent, dep->name, dep->namelen,
+ xfs_dir2_byte_to_dataptr(mp, curoff + length),
+ ino, DT_UNKNOWN))
break;
- }
+
/*
* Advance to next entry in the block.
*/
ptr += length;
curoff += length;
+ bufsize -= length;
}
/*
* All done. Set output offset value to current offset.
*/
- *eofp = eof;
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
- 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(p, sizeof(*p));
if (bp)
- xfs_da_brelse(tp, bp);
+ xfs_da_brelse(NULL, bp);
return error;
}
extern void xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp,
int *lowstalep, int *highstalep,
int *lowlogp, int *highlogp);
-extern int xfs_dir2_leaf_getdents(struct xfs_trans *tp, struct xfs_inode *dp,
- struct uio *uio, int *eofp,
- struct xfs_dirent *dbp, xfs_dir2_put_t put);
+extern int xfs_dir2_leaf_getdents(struct xfs_inode *dp, void *dirent,
+ size_t bufsize, xfs_off_t *offset,
+ filldir_t filldir);
extern int xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno,
struct xfs_dabuf **bpp, int magic);
extern void xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp,
int /* error */
xfs_dir2_sf_getdents(
xfs_inode_t *dp, /* incore directory inode */
- uio_t *uio, /* caller's buffer control */
- int *eofp, /* eof reached? (out) */
- xfs_dirent_t *dbp, /* caller's buffer */
- xfs_dir2_put_t put) /* abi's formatting function */
+ void *dirent,
+ xfs_off_t *offset,
+ filldir_t filldir)
{
- int error; /* error return value */
int i; /* shortform entry number */
xfs_mount_t *mp; /* filesystem mount point */
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_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;
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_u1.if_data != NULL);
/*
* 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) {
- *eofp = 1;
+ if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk)
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;
- p.put = put;
- p.uio = uio;
+ dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+ XFS_DIR2_DATA_DOT_OFFSET);
+ 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.
*/
- if (dir_offset <=
- xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
- 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 (*offset <= dot_offset) {
+ ino = dp->i_ino;
#if XFS_BIG_INUMS
- p.ino += mp->m_inoadd;
+ ino += mp->m_inoadd;
#endif
- p.name = ".";
- p.namelen = 1;
-
- 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;
+ if (filldir(dirent, ".", 1, dotdot_offset, ino, DT_DIR)) {
+ *offset = dot_offset;
+ return 0;
}
}
/*
* Put .. entry unless we're starting past it.
*/
- if (dir_offset <=
- xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
- XFS_DIR2_DATA_DOTDOT_OFFSET)) {
- p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
- XFS_DIR2_DATA_FIRST_OFFSET);
- p.ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
+ if (*offset <= dotdot_offset) {
+ off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+ XFS_DIR2_DATA_FIRST_OFFSET);
+ ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
#if XFS_BIG_INUMS
- p.ino += mp->m_inoadd;
+ ino += mp->m_inoadd;
#endif
- p.name = "..";
- p.namelen = 2;
-
- 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;
+ if (filldir(dirent, "..", 2, off, ino, DT_DIR)) {
+ *offset = dotdot_offset;
+ return 0;
}
}
/*
* Loop while there are more entries and put'ing works.
*/
- for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
- i < sfp->hdr.count;
- i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
-
+ sfep = xfs_dir2_sf_firstentry(sfp);
+ for (i = 0; i < sfp->hdr.count; i++) {
off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
xfs_dir2_sf_get_offset(sfep));
- if (dir_offset > off)
+ if (*offset > off) {
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
continue;
+ }
- p.namelen = sfep->namelen;
-
- 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));
+ ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
#if XFS_BIG_INUMS
- p.ino += mp->m_inoadd;
+ ino += mp->m_inoadd;
#endif
- p.name = (char *)sfep->name;
-
- error = p.put(&p);
- if (!p.done) {
- uio->uio_offset = off;
- return error;
+ if (filldir(dirent, sfep->name, sfep->namelen,
+ off + xfs_dir2_data_entsize(sfep->namelen),
+ ino, DT_UNKNOWN)) {
+ *offset = off;
+ return 0;
}
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
}
- /*
- * They all fit.
- */
- *eofp = 1;
-
- uio->uio_offset =
- xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
-
+ *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
return 0;
}
int size, xfs_dir2_sf_hdr_t *sfhp);
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_getdents(struct xfs_inode *dp, struct uio *uio,
- int *eofp, struct xfs_dirent *dbp,
- xfs_dir2_put_t put);
+extern int xfs_dir2_sf_getdents(struct xfs_inode *dp, void *dirent,
+ xfs_off_t *offset, filldir_t filldir);
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_replace(struct xfs_da_args *args);
*/
#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 {
XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
} xfs_lookup_t;
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
xfs_symlink(
bhv_desc_t *dir_bdp,