/** * v9fs_dir_readdir_dotl - iterate through a directory * @file: opened file structure * @ctx: actor we feed the entries to * */ static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx) { int err = 0; struct p9_fid *fid; int buflen; struct p9_rdir *rdir; struct p9_dirent curdirent; p9_debug(P9_DEBUG_VFS, "name %pD\n", file); fid = file->private_data; buflen = fid->clnt->msize - P9_READDIRHDRSZ; rdir = v9fs_alloc_rdir_buf(file, buflen); if (!rdir) return -ENOMEM; while (1) { if (rdir->tail == rdir->head) { err = p9_client_readdir(fid, rdir->buf, buflen, ctx->pos); if (err <= 0) return err; rdir->head = 0; rdir->tail = err; } while (rdir->head < rdir->tail) { err = p9dirent_read(fid->clnt, rdir->buf + rdir->head, rdir->tail - rdir->head, &curdirent); if (err < 0) { p9_debug(P9_DEBUG_VFS, "returned %d\n", err); return -EIO; } if (!dir_emit(ctx, curdirent.d_name, strlen(curdirent.d_name), v9fs_qid2ino(&curdirent.qid), curdirent.d_type)) return 0; ctx->pos = curdirent.d_off; rdir->head += err; } } }
/** * v9fs_dir_readdir_dotl - read a directory * @filp: opened file structure * @dirent: buffer to fill dirent structures * @filldir: function to populate dirent structures * */ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent, filldir_t filldir) { int over; int err = 0; struct p9_fid *fid; int buflen; struct p9_rdir *rdir; struct p9_dirent curdirent; u64 oldoffset = 0; P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); fid = filp->private_data; buflen = fid->clnt->msize - P9_READDIRHDRSZ; err = v9fs_alloc_rdir_buf(filp, buflen); if (err) goto exit; rdir = (struct p9_rdir *) fid->rdir; err = mutex_lock_interruptible(&rdir->mutex); if (err) return err; while (err == 0) { if (rdir->tail == rdir->head) { err = p9_client_readdir(fid, rdir->buf, buflen, filp->f_pos); if (err <= 0) goto unlock_and_exit; rdir->head = 0; rdir->tail = err; } while (rdir->head < rdir->tail) { err = p9dirent_read(rdir->buf + rdir->head, rdir->tail - rdir->head, &curdirent, fid->clnt->proto_version); if (err < 0) { P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); err = -EIO; goto unlock_and_exit; } /* d_off in dirent structure tracks the offset into * the next dirent in the dir. However, filldir() * expects offset into the current dirent. Hence * while calling filldir send the offset from the * previous dirent structure. */ over = filldir(dirent, curdirent.d_name, strlen(curdirent.d_name), oldoffset, v9fs_qid2ino(&curdirent.qid), curdirent.d_type); oldoffset = curdirent.d_off; if (over) { err = 0; goto unlock_and_exit; } filp->f_pos = curdirent.d_off; rdir->head += err; } } unlock_and_exit: mutex_unlock(&rdir->mutex); exit: return err; }