static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	int over;
	struct p9_fid *fid;
	struct v9fs_session_info *v9ses;
	struct inode *inode;
	struct p9_stat *st;

	P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
	inode = filp->f_path.dentry->d_inode;
	v9ses = v9fs_inode2v9ses(inode);
	fid = filp->private_data;
	while ((st = p9_client_dirread(fid, filp->f_pos)) != NULL) {
		if (IS_ERR(st))
			return PTR_ERR(st);

		over = filldir(dirent, st->name.str, st->name.len, filp->f_pos,
			v9fs_qid2ino(&st->qid), dt_type(st));

		if (over)
			break;

		filp->f_pos += st->size;
		kfree(st);
		st = NULL;
	}

	kfree(st);
	return 0;
}
Esempio n. 2
0
static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
{
	bool over;
	struct p9_wstat st;
	int err = 0;
	struct p9_fid *fid;
	int buflen;
	int reclen = 0;
	struct p9_rdir *rdir;
	struct kvec kvec;

	p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
	fid = file->private_data;

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

	rdir = v9fs_alloc_rdir_buf(file, buflen);
	if (!rdir)
		return -ENOMEM;
	kvec.iov_base = rdir->buf;
	kvec.iov_len = buflen;

	while (1) {
		if (rdir->tail == rdir->head) {
			struct iov_iter to;
			int n;
			iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buflen);
			n = p9_client_read(file->private_data, ctx->pos, &to,
					   &err);
			if (err)
				return err;

			rdir->head = 0;
			rdir->tail = n;
		}
		while (rdir->head < rdir->tail) {
			p9stat_init(&st);
			err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
					  rdir->tail - rdir->head, &st);
			if (err) {
				p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
				p9stat_free(&st);
				return -EIO;
			}
			reclen = st.size+2;

			over = !dir_emit(ctx, st.name, strlen(st.name),
					 v9fs_qid2ino(&st.qid), dt_type(&st));
			p9stat_free(&st);
			if (over)
				return 0;

			rdir->head += reclen;
			ctx->pos += reclen;
		}
	}
}
Esempio n. 3
0
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	int over;
	struct p9_wstat st;
	int err;
	struct p9_fid *fid;
	int buflen;
	char *statbuf;
	int n, i = 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_IOHDRSZ;
	statbuf = kmalloc(buflen, GFP_KERNEL);
	if (!statbuf)
		return -ENOMEM;

	while (1) {
		err = v9fs_file_readn(filp, statbuf, NULL, buflen,
								fid->rdir_fpos);
		if (err <= 0)
			break;

		n = err;
		while (i < n) {
			err = p9stat_read(statbuf + i, buflen-i, &st,
							fid->clnt->dotu);
			if (err) {
				P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
				err = -EIO;
				p9stat_free(&st);
				goto free_and_exit;
			}

			i += st.size+2;
			fid->rdir_fpos += st.size+2;

			over = filldir(dirent, st.name, strlen(st.name),
			    filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st));

			filp->f_pos += st.size+2;

			p9stat_free(&st);

			if (over) {
				err = 0;
				goto free_and_exit;
			}
		}
	}

free_and_exit:
	kfree(statbuf);
	return err;
}
Esempio n. 4
0
/**
 * 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;
		}
	}
}
static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
					struct p9_qid *qid,
					struct p9_fid *fid,
					struct p9_stat_dotl *st)
{
	int retval;
	unsigned long i_ino;
	struct inode *inode;
	struct v9fs_session_info *v9ses = sb->s_fs_info;

	i_ino = v9fs_qid2ino(qid);
	inode = iget_locked(sb, i_ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;
	/*
	 * initialize the inode with the stat info
	 * FIXME!! we may need support for stale inodes
	 * later.
	 */
	retval = v9fs_init_inode(v9ses, inode, st->st_mode);
	if (retval)
		goto error;

	v9fs_stat2inode_dotl(st, inode);
#ifdef CONFIG_9P_FSCACHE
	v9fs_fscache_set_key(inode, &st->qid);
	v9fs_cache_inode_get_cookie(inode);
#endif
	retval = v9fs_get_acl(inode, fid);
	if (retval)
		goto error;

	unlock_new_inode(inode);
	return inode;
error:
	unlock_new_inode(inode);
	iput(inode);
	return ERR_PTR(retval);

}
Esempio n. 6
0
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	struct v9fs_fcall *fcall = NULL;
	struct inode *inode = filp->f_path.dentry->d_inode;
	struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
	struct v9fs_fid *file = filp->private_data;
	unsigned int i, n, s;
	int fid = -1;
	int ret = 0;
	struct v9fs_stat stat;
	int over = 0;

	dprintk(DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);

	fid = file->fid;

	if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) {
		kfree(file->rdir_fcall);
		file->rdir_fcall = NULL;
	}

	if (file->rdir_fcall) {
		n = file->rdir_fcall->params.rread.count;
		i = file->rdir_fpos;
		while (i < n) {
			s = v9fs_deserialize_stat(
				file->rdir_fcall->params.rread.data + i,
				n - i, &stat, v9ses->extended);

			if (s == 0) {
				dprintk(DEBUG_ERROR,
					"error while deserializing stat\n");
				ret = -EIO;
				goto FreeStructs;
			}

			over = filldir(dirent, stat.name.str, stat.name.len,
				    filp->f_pos, v9fs_qid2ino(&stat.qid),
				    dt_type(&stat));

			if (over) {
				file->rdir_fpos = i;
				file->rdir_pos = filp->f_pos;
				break;
			}

			i += s;
			filp->f_pos += s;
		}

		if (!over) {
			kfree(file->rdir_fcall);
			file->rdir_fcall = NULL;
		}
	}

	while (!over) {
		ret = v9fs_t_read(v9ses, fid, filp->f_pos,
			v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
		if (ret < 0) {
			dprintk(DEBUG_ERROR, "error while reading: %d: %p\n",
				ret, fcall);
			goto FreeStructs;
		} else if (ret == 0)
			break;

		n = ret;
		i = 0;
		while (i < n) {
			s = v9fs_deserialize_stat(fcall->params.rread.data + i,
				n - i, &stat, v9ses->extended);

			if (s == 0) {
				dprintk(DEBUG_ERROR,
					"error while deserializing stat\n");
				return -EIO;
			}

			over = filldir(dirent, stat.name.str, stat.name.len,
				    filp->f_pos, v9fs_qid2ino(&stat.qid),
				    dt_type(&stat));

			if (over) {
				file->rdir_fcall = fcall;
				file->rdir_fpos = i;
				file->rdir_pos = filp->f_pos;
				fcall = NULL;
				break;
			}

			i += s;
			filp->f_pos += s;
		}

		kfree(fcall);
	}

      FreeStructs:
	kfree(fcall);
	return ret;
}
Esempio n. 7
0
static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
		       const char *dev_name, void *data,
		       struct vfsmount *mnt)
{
	struct super_block *sb = NULL;
	struct inode *inode = NULL;
	struct dentry *root = NULL;
	struct v9fs_session_info *v9ses = NULL;
	struct p9_stat *st = NULL;
	int mode = S_IRWXUGO | S_ISVTX;
	uid_t uid = current->fsuid;
	gid_t gid = current->fsgid;
	struct p9_fid *fid;
	int retval = 0;

	P9_DPRINTK(P9_DEBUG_VFS, " \n");

	st = NULL;
	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
	if (!v9ses)
		return -ENOMEM;

	fid = v9fs_session_init(v9ses, dev_name, data);
	if (IS_ERR(fid)) {
		retval = PTR_ERR(fid);
		fid = NULL;
		kfree(v9ses);
		v9ses = NULL;
		goto error;
	}

	st = p9_client_stat(fid);
	if (IS_ERR(st)) {
		retval = PTR_ERR(st);
		goto error;
	}

	sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
	if (IS_ERR(sb)) {
		retval = PTR_ERR(sb);
		goto error;
	}
	v9fs_fill_super(sb, v9ses, flags);

	inode = v9fs_get_inode(sb, S_IFDIR | mode);
	if (IS_ERR(inode)) {
		retval = PTR_ERR(inode);
		goto error;
	}

	inode->i_uid = uid;
	inode->i_gid = gid;

	root = d_alloc_root(inode);
	if (!root) {
		retval = -ENOMEM;
		goto error;
	}

	sb->s_root = root;
	root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
	v9fs_stat2inode(st, root->d_inode, sb);
	v9fs_fid_add(root, fid);
	kfree(st);

	return simple_set_mnt(mnt, sb);

error:
	kfree(st);
	if (fid)
		p9_client_clunk(fid);

	if (v9ses) {
		v9fs_session_close(v9ses);
		kfree(v9ses);
	}

	if (sb) {
		up_write(&sb->s_umount);
		deactivate_super(sb);
	}

	return retval;
}
Esempio n. 8
0
static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
		       const char *dev_name, void *data,
		       struct vfsmount *mnt)
{
	struct super_block *sb = NULL;
	struct inode *inode = NULL;
	struct dentry *root = NULL;
	struct v9fs_session_info *v9ses = NULL;
	int mode = S_IRWXUGO | S_ISVTX;
	struct p9_fid *fid;
	int retval = 0;

	P9_DPRINTK(P9_DEBUG_VFS, " \n");

	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
	if (!v9ses)
		return -ENOMEM;

	fid = v9fs_session_init(v9ses, dev_name, data);
	if (IS_ERR(fid)) {
		retval = PTR_ERR(fid);
		/*
		 * we need to call session_close to tear down some
		 * of the data structure setup by session_init
		 */
		goto close_session;
	}

	sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
	if (IS_ERR(sb)) {
		retval = PTR_ERR(sb);
		goto clunk_fid;
	}
	v9fs_fill_super(sb, v9ses, flags, data);

	inode = v9fs_get_inode(sb, S_IFDIR | mode);
	if (IS_ERR(inode)) {
		retval = PTR_ERR(inode);
		goto release_sb;
	}

	root = d_alloc_root(inode);
	if (!root) {
		iput(inode);
		retval = -ENOMEM;
		goto release_sb;
	}
	sb->s_root = root;
	if (v9fs_proto_dotl(v9ses)) {
		struct p9_stat_dotl *st = NULL;
		st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
		if (IS_ERR(st)) {
			retval = PTR_ERR(st);
			goto release_sb;
		}

		v9fs_stat2inode_dotl(st, root->d_inode);
		kfree(st);
	} else {
		struct p9_wstat *st = NULL;
		st = p9_client_stat(fid);
		if (IS_ERR(st)) {
			retval = PTR_ERR(st);
			goto release_sb;
		}

		root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
		v9fs_stat2inode(st, root->d_inode, sb);

		p9stat_free(st);
		kfree(st);
	}
	retval = v9fs_get_acl(inode, fid);
	if (retval)
		goto release_sb;
	v9fs_fid_add(root, fid);

	P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
	simple_set_mnt(mnt, sb);
	return 0;

clunk_fid:
	p9_client_clunk(fid);
close_session:
	v9fs_session_close(v9ses);
	kfree(v9ses);
	return retval;
release_sb:
	/*
	 * we will do the session_close and root dentry release
	 * in the below call. But we need to clunk fid, because we haven't
	 * attached the fid to dentry so it won't get clunked
	 * automatically.
	 */
	p9_client_clunk(fid);
	deactivate_locked_super(sb);
	return retval;
}
Esempio n. 9
0
static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
		       const char *dev_name, void *data,
		       struct vfsmount *mnt)
{
	struct super_block *sb = NULL;
	struct v9fs_fcall *fcall = NULL;
	struct inode *inode = NULL;
	struct dentry *root = NULL;
	struct v9fs_session_info *v9ses = NULL;
	struct v9fs_fid *root_fid = NULL;
	int mode = S_IRWXUGO | S_ISVTX;
	uid_t uid = current->fsuid;
	gid_t gid = current->fsgid;
	int stat_result = 0;
	int newfid = 0;
	int retval = 0;

	dprintk(DEBUG_VFS, " \n");

	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
	if (!v9ses)
		return -ENOMEM;

	if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
		dprintk(DEBUG_ERROR, "problem initiating session\n");
		retval = newfid;
		goto out_free_session;
	}

	sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
	if (IS_ERR(sb)) {
		retval = PTR_ERR(sb);
		goto out_close_session;
	}
	v9fs_fill_super(sb, v9ses, flags);

	inode = v9fs_get_inode(sb, S_IFDIR | mode);
	if (IS_ERR(inode)) {
		retval = PTR_ERR(inode);
		goto put_back_sb;
	}

	inode->i_uid = uid;
	inode->i_gid = gid;

	root = d_alloc_root(inode);
	if (!root) {
		retval = -ENOMEM;
		goto put_back_sb;
	}

	sb->s_root = root;

	stat_result = v9fs_t_stat(v9ses, newfid, &fcall);
	if (stat_result < 0) {
		dprintk(DEBUG_ERROR, "stat error\n");
		v9fs_t_clunk(v9ses, newfid);
	} else {
		/* Setup the Root Inode */
		root_fid = v9fs_fid_create(v9ses, newfid);
		if (root_fid == NULL) {
			retval = -ENOMEM;
			goto put_back_sb;
		}

		retval = v9fs_fid_insert(root_fid, root);
		if (retval < 0) {
			kfree(fcall);
			goto put_back_sb;
		}

		root_fid->qid = fcall->params.rstat.stat.qid;
		root->d_inode->i_ino =
		    v9fs_qid2ino(&fcall->params.rstat.stat.qid);
		v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb);
	}

	kfree(fcall);

	if (stat_result < 0) {
		retval = stat_result;
		goto put_back_sb;
	}

	return simple_set_mnt(mnt, sb);

out_close_session:
	v9fs_session_close(v9ses);
out_free_session:
	kfree(v9ses);
	return retval;

put_back_sb:
	/* deactivate_super calls v9fs_kill_super which will frees the rest */
	up_write(&sb->s_umount);
	deactivate_super(sb);
	return retval;
}
Esempio n. 10
0
/**
 * 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;
}
Esempio n. 11
0
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	int over;
	struct p9_wstat st;
	int err = 0;
	struct p9_fid *fid;
	int buflen;
	int reclen = 0;
	struct p9_rdir *rdir;

	P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
	fid = filp->private_data;

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

	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 = v9fs_file_readn(filp, rdir->buf, NULL,
							buflen, filp->f_pos);
			if (err <= 0)
				goto unlock_and_exit;

			rdir->head = 0;
			rdir->tail = err;
		}
		while (rdir->head < rdir->tail) {
			p9stat_init(&st);
			err = p9stat_read(rdir->buf + rdir->head,
						rdir->tail - rdir->head, &st,
						fid->clnt->proto_version);
			if (err) {
				P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
				err = -EIO;
				p9stat_free(&st);
				goto unlock_and_exit;
			}
			reclen = st.size+2;

			over = filldir(dirent, st.name, strlen(st.name),
			    filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st));

			p9stat_free(&st);

			if (over) {
				err = 0;
				goto unlock_and_exit;
			}
			rdir->head += reclen;
			filp->f_pos += reclen;
		}
	}

unlock_and_exit:
	mutex_unlock(&rdir->mutex);
exit:
	return err;
}
Esempio n. 12
0
static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
		       const char *dev_name, void *data)
{
	struct super_block *sb = NULL;
	struct inode *inode = NULL;
	struct dentry *root = NULL;
	struct v9fs_session_info *v9ses = NULL;
	umode_t mode = S_IRWXUGO | S_ISVTX;
	struct p9_fid *fid;
	int retval = 0;

	p9_debug(P9_DEBUG_VFS, "\n");

	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
	if (!v9ses)
		return ERR_PTR(-ENOMEM);

	fid = v9fs_session_init(v9ses, dev_name, data);
	if (IS_ERR(fid)) {
		retval = PTR_ERR(fid);
		goto free_session;
	}

	sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses);
	if (IS_ERR(sb)) {
		retval = PTR_ERR(sb);
		goto clunk_fid;
	}
	v9fs_fill_super(sb, v9ses, flags, data);

	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
		sb->s_d_op = &v9fs_cached_dentry_operations;
	else
		sb->s_d_op = &v9fs_dentry_operations;

	inode = v9fs_get_inode(sb, S_IFDIR | mode, 0);
	if (IS_ERR(inode)) {
		retval = PTR_ERR(inode);
		goto release_sb;
	}

	root = d_make_root(inode);
	if (!root) {
		retval = -ENOMEM;
		goto release_sb;
	}
	sb->s_root = root;
	if (v9fs_proto_dotl(v9ses)) {
		struct p9_stat_dotl *st = NULL;
		st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
		if (IS_ERR(st)) {
			retval = PTR_ERR(st);
			goto release_sb;
		}
		d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
		v9fs_stat2inode_dotl(st, d_inode(root));
		kfree(st);
	} else {
		struct p9_wstat *st = NULL;
		st = p9_client_stat(fid);
		if (IS_ERR(st)) {
			retval = PTR_ERR(st);
			goto release_sb;
		}

		d_inode(root)->i_ino = v9fs_qid2ino(&st->qid);
		v9fs_stat2inode(st, d_inode(root), sb);

		p9stat_free(st);
		kfree(st);
	}
	retval = v9fs_get_acl(inode, fid);
	if (retval)
		goto release_sb;
	v9fs_fid_add(root, fid);

	p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n");
	return dget(sb->s_root);

clunk_fid:
	p9_client_clunk(fid);
	v9fs_session_close(v9ses);
free_session:
	kfree(v9ses);
	return ERR_PTR(retval);

release_sb:
	/*
	 * we will do the session_close and root dentry release
	 * in the below call. But we need to clunk fid, because we haven't
	 * attached the fid to dentry so it won't get clunked
	 * automatically.
	 */
	p9_client_clunk(fid);
	deactivate_locked_super(sb);
	return ERR_PTR(retval);
}