Commit 77acfa29 authored by Al Viro's avatar Al Viro
Browse files

[readdir] convert ceph



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 23db8620
Loading
Loading
Loading
Loading
+48 −51
Original line number Diff line number Diff line
@@ -111,11 +111,10 @@ static unsigned fpos_off(loff_t p)
 * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by
 * the MDS if/when the directory is modified).
 */
static int __dcache_readdir(struct file *filp,
			    void *dirent, filldir_t filldir)
static int __dcache_readdir(struct file *file, struct dir_context *ctx)
{
	struct ceph_file_info *fi = filp->private_data;
	struct dentry *parent = filp->f_dentry;
	struct ceph_file_info *fi = file->private_data;
	struct dentry *parent = file->f_dentry;
	struct inode *dir = parent->d_inode;
	struct list_head *p;
	struct dentry *dentry, *last;
@@ -126,14 +125,14 @@ static int __dcache_readdir(struct file *filp,
	last = fi->dentry;
	fi->dentry = NULL;

	dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos,
	dout("__dcache_readdir %p at %llu (last %p)\n", dir, ctx->pos,
	     last);

	spin_lock(&parent->d_lock);

	/* start at beginning? */
	if (filp->f_pos == 2 || last == NULL ||
	    filp->f_pos < ceph_dentry(last)->offset) {
	if (ctx->pos == 2 || last == NULL ||
	    ctx->pos < ceph_dentry(last)->offset) {
		if (list_empty(&parent->d_subdirs))
			goto out_unlock;
		p = parent->d_subdirs.prev;
@@ -157,11 +156,11 @@ more:
		if (!d_unhashed(dentry) && dentry->d_inode &&
		    ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
		    ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
		    filp->f_pos <= di->offset)
		    ctx->pos <= di->offset)
			break;
		dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
		     dentry->d_name.len, dentry->d_name.name, di->offset,
		     filp->f_pos, d_unhashed(dentry) ? " unhashed" : "",
		     ctx->pos, d_unhashed(dentry) ? " unhashed" : "",
		     !dentry->d_inode ? " null" : "");
		spin_unlock(&dentry->d_lock);
		p = p->prev;
@@ -173,29 +172,27 @@ more:
	spin_unlock(&dentry->d_lock);
	spin_unlock(&parent->d_lock);

	dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos,
	dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, ctx->pos,
	     dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
	filp->f_pos = di->offset;
	err = filldir(dirent, dentry->d_name.name,
		      dentry->d_name.len, di->offset,
	ctx->pos = di->offset;
	if (!dir_emit(ctx, dentry->d_name.name,
		      dentry->d_name.len,
		      ceph_translate_ino(dentry->d_sb, dentry->d_inode->i_ino),
		      dentry->d_inode->i_mode >> 12);

		      dentry->d_inode->i_mode >> 12)) {
		if (last) {
		if (err < 0) {
			/* remember our position */
			fi->dentry = last;
			fi->next_offset = di->offset;
		} else {
			dput(last);
		}
		dput(dentry);
		return 0;
	}
	last = dentry;

	if (err < 0)
		goto out;
	if (last)
		dput(last);
	last = dentry;

	filp->f_pos++;
	ctx->pos++;

	/* make sure a dentry wasn't dropped while we didn't have parent lock */
	if (!ceph_dir_is_complete(dir)) {
@@ -235,59 +232,59 @@ static int note_last_dentry(struct ceph_file_info *fi, const char *name,
	return 0;
}

static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int ceph_readdir(struct file *file, struct dir_context *ctx)
{
	struct ceph_file_info *fi = filp->private_data;
	struct inode *inode = file_inode(filp);
	struct ceph_file_info *fi = file->private_data;
	struct inode *inode = file_inode(file);
	struct ceph_inode_info *ci = ceph_inode(inode);
	struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
	struct ceph_mds_client *mdsc = fsc->mdsc;
	unsigned frag = fpos_frag(filp->f_pos);
	int off = fpos_off(filp->f_pos);
	unsigned frag = fpos_frag(ctx->pos);
	int off = fpos_off(ctx->pos);
	int err;
	u32 ftype;
	struct ceph_mds_reply_info_parsed *rinfo;
	const int max_entries = fsc->mount_options->max_readdir;
	const int max_bytes = fsc->mount_options->max_readdir_bytes;

	dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off);
	dout("readdir %p file %p frag %u off %u\n", inode, file, frag, off);
	if (fi->flags & CEPH_F_ATEND)
		return 0;

	/* always start with . and .. */
	if (filp->f_pos == 0) {
	if (ctx->pos == 0) {
		/* note dir version at start of readdir so we can tell
		 * if any dentries get dropped */
		fi->dir_release_count = atomic_read(&ci->i_release_count);

		dout("readdir off 0 -> '.'\n");
		if (filldir(dirent, ".", 1, ceph_make_fpos(0, 0),
		if (!dir_emit(ctx, ".", 1, 
			    ceph_translate_ino(inode->i_sb, inode->i_ino),
			    inode->i_mode >> 12) < 0)
			    inode->i_mode >> 12))
			return 0;
		filp->f_pos = 1;
		ctx->pos = 1;
		off = 1;
	}
	if (filp->f_pos == 1) {
		ino_t ino = parent_ino(filp->f_dentry);
	if (ctx->pos == 1) {
		ino_t ino = parent_ino(file->f_dentry);
		dout("readdir off 1 -> '..'\n");
		if (filldir(dirent, "..", 2, ceph_make_fpos(0, 1),
		if (!dir_emit(ctx, "..", 2,
			    ceph_translate_ino(inode->i_sb, ino),
			    inode->i_mode >> 12) < 0)
			    inode->i_mode >> 12))
			return 0;
		filp->f_pos = 2;
		ctx->pos = 2;
		off = 2;
	}

	/* can we use the dcache? */
	spin_lock(&ci->i_ceph_lock);
	if ((filp->f_pos == 2 || fi->dentry) &&
	if ((ctx->pos == 2 || fi->dentry) &&
	    !ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
	    ceph_snap(inode) != CEPH_SNAPDIR &&
	    __ceph_dir_is_complete(ci) &&
	    __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
		spin_unlock(&ci->i_ceph_lock);
		err = __dcache_readdir(filp, dirent, filldir);
		err = __dcache_readdir(file, ctx);
		if (err != -EAGAIN)
			return err;
	} else {
@@ -327,7 +324,7 @@ more:
			return PTR_ERR(req);
		req->r_inode = inode;
		ihold(inode);
		req->r_dentry = dget(filp->f_dentry);
		req->r_dentry = dget(file->f_dentry);
		/* hints to request -> mds selection code */
		req->r_direct_mode = USE_AUTH_MDS;
		req->r_direct_hash = ceph_frag_value(frag);
@@ -379,15 +376,16 @@ more:
	rinfo = &fi->last_readdir->r_reply_info;
	dout("readdir frag %x num %d off %d chunkoff %d\n", frag,
	     rinfo->dir_nr, off, fi->offset);

	ctx->pos = ceph_make_fpos(frag, off);
	while (off >= fi->offset && off - fi->offset < rinfo->dir_nr) {
		u64 pos = ceph_make_fpos(frag, off);
		struct ceph_mds_reply_inode *in =
			rinfo->dir_in[off - fi->offset].in;
		struct ceph_vino vino;
		ino_t ino;

		dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n",
		     off, off - fi->offset, rinfo->dir_nr, pos,
		     off, off - fi->offset, rinfo->dir_nr, ctx->pos,
		     rinfo->dir_dname_len[off - fi->offset],
		     rinfo->dir_dname[off - fi->offset], in);
		BUG_ON(!in);
@@ -395,16 +393,15 @@ more:
		vino.ino = le64_to_cpu(in->ino);
		vino.snap = le64_to_cpu(in->snapid);
		ino = ceph_vino_to_ino(vino);
		if (filldir(dirent,
		if (!dir_emit(ctx,
			    rinfo->dir_dname[off - fi->offset],
			    rinfo->dir_dname_len[off - fi->offset],
			    pos,
			    ceph_translate_ino(inode->i_sb, ino), ftype) < 0) {
			    ceph_translate_ino(inode->i_sb, ino), ftype)) {
			dout("filldir stopping us...\n");
			return 0;
		}
		off++;
		filp->f_pos = pos + 1;
		ctx->pos++;
	}

	if (fi->last_name) {
@@ -417,7 +414,7 @@ more:
	if (!ceph_frag_is_rightmost(frag)) {
		frag = ceph_frag_next(frag);
		off = 0;
		filp->f_pos = ceph_make_fpos(frag, off);
		ctx->pos = ceph_make_fpos(frag, off);
		dout("readdir next frag is %x\n", frag);
		goto more;
	}
@@ -432,11 +429,11 @@ more:
	if (atomic_read(&ci->i_release_count) == fi->dir_release_count) {
		dout(" marking %p complete\n", inode);
		__ceph_dir_set_complete(ci, fi->dir_release_count);
		ci->i_max_offset = filp->f_pos;
		ci->i_max_offset = ctx->pos;
	}
	spin_unlock(&ci->i_ceph_lock);

	dout("readdir %p filp %p done.\n", inode, filp);
	dout("readdir %p file %p done.\n", inode, file);
	return 0;
}

@@ -1268,7 +1265,7 @@ unsigned ceph_dentry_hash(struct inode *dir, struct dentry *dn)

const struct file_operations ceph_dir_fops = {
	.read = ceph_read_dir,
	.readdir = ceph_readdir,
	.iterate = ceph_readdir,
	.llseek = ceph_dir_llseek,
	.open = ceph_open,
	.release = ceph_release,