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: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
This commit is contained in:
		
							parent
							
								
									836dc9e3fb
								
							
						
					
					
						commit
						7ffdea7ea3
					
				| @ -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; | ||||
| 	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 = 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; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user