Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ffdea7e authored by Al Viro's avatar Al Viro Committed by Eric Van Hensbergen
Browse files

locking in fs/9p ->readdir()



	... is really excessive.  First of all, ->readdir() is serialized by
file->f_path.dentry->d_inode->i_mutex; playing with file->f_path.dentry->d_lock
is not buying you anything.  Moreover, rdir->mutex is pointless for exactly
the same reason - you'll never see contention on it.

	While we are at it, there's no point in having rdir->buf a pointer -
you have it point just past the end of rdir, so it might as well be a flex
array (and no, it's not a gccism).

	Absolutely untested patch follows:

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarEric Van Hensbergen <ericvh@gmail.com>
parent 836dc9e3
Loading
Loading
Loading
Loading
+23 −69
Original line number Diff line number Diff line
@@ -52,10 +52,9 @@
 */

struct p9_rdir {
	struct mutex mutex;
	int head;
	int tail;
	uint8_t *buf;
	uint8_t buf[];
};

/**
@@ -93,33 +92,12 @@ static void p9stat_init(struct p9_wstat *stbuf)
 *
 */

static int v9fs_alloc_rdir_buf(struct file *filp, int buflen)
static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
{
	struct p9_rdir *rdir;
	struct p9_fid *fid;
	int err = 0;

	fid = filp->private_data;
	if (!fid->rdir) {
		rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);

		if (rdir == NULL) {
			err = -ENOMEM;
			goto exit;
		}
		spin_lock(&filp->f_dentry->d_lock);
		if (!fid->rdir) {
			rdir->buf = (uint8_t *)rdir + sizeof(struct p9_rdir);
			mutex_init(&rdir->mutex);
			rdir->head = rdir->tail = 0;
			fid->rdir = (void *) rdir;
			rdir = NULL;
		}
		spin_unlock(&filp->f_dentry->d_lock);
		kfree(rdir);
	}
exit:
	return err;
	struct p9_fid *fid = filp->private_data;
	if (!fid->rdir)
		fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
	return fid->rdir;
}

/**
@@ -145,20 +123,16 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)

	buflen = fid->clnt->msize - P9_IOHDRSZ;

	err = v9fs_alloc_rdir_buf(filp, buflen);
	if (err)
		goto exit;
	rdir = (struct p9_rdir *) fid->rdir;
	rdir = v9fs_alloc_rdir_buf(filp, buflen);
	if (!rdir)
		return -ENOMEM;

	err = mutex_lock_interruptible(&rdir->mutex);
	if (err)
		return err;
	while (err == 0) {
	while (1) {
		if (rdir->tail == rdir->head) {
			err = v9fs_file_readn(filp, rdir->buf, NULL,
							buflen, filp->f_pos);
			if (err <= 0)
				goto unlock_and_exit;
				return err;

			rdir->head = 0;
			rdir->tail = err;
@@ -169,9 +143,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
					  rdir->tail - rdir->head, &st);
			if (err) {
				p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
				err = -EIO;
				p9stat_free(&st);
				goto unlock_and_exit;
				return -EIO;
			}
			reclen = st.size+2;

@@ -180,19 +153,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)

			p9stat_free(&st);

			if (over) {
				err = 0;
				goto unlock_and_exit;
			}
			if (over)
				return 0;

			rdir->head += reclen;
			filp->f_pos += reclen;
		}
	}

unlock_and_exit:
	mutex_unlock(&rdir->mutex);
exit:
	return err;
}

/**
@@ -218,21 +185,16 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,

	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;
	rdir = v9fs_alloc_rdir_buf(filp, buflen);
	if (!rdir)
		return -ENOMEM;

	while (err == 0) {
	while (1) {
		if (rdir->tail == rdir->head) {
			err = p9_client_readdir(fid, rdir->buf, buflen,
						filp->f_pos);
			if (err <= 0)
				goto unlock_and_exit;
				return err;

			rdir->head = 0;
			rdir->tail = err;
@@ -245,8 +207,7 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
					    &curdirent);
			if (err < 0) {
				p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
				err = -EIO;
				goto unlock_and_exit;
				return -EIO;
			}

			/* d_off in dirent structure tracks the offset into
@@ -261,20 +222,13 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
					curdirent.d_type);
			oldoffset = curdirent.d_off;

			if (over) {
				err = 0;
				goto unlock_and_exit;
			}
			if (over)
				return 0;

			filp->f_pos = curdirent.d_off;
			rdir->head += err;
		}
	}

unlock_and_exit:
	mutex_unlock(&rdir->mutex);
exit:
	return err;
}