Пример #1
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;
		}
	}
}
Пример #2
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;
}
Пример #3
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;
}
Пример #4
0
static int
p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
             va_list ap)
{
    const char *ptr;
    int errcode = 0;

    for (ptr = fmt; *ptr; ptr++) {
        switch (*ptr) {
        case 'b': {
            int8_t *val = va_arg(ap, int8_t *);
            if (pdu_read(pdu, val, sizeof(*val))) {
                errcode = -EFAULT;
                break;
            }
        }
        break;
        case 'w': {
            int16_t *val = va_arg(ap, int16_t *);
            __le16 le_val;
            if (pdu_read(pdu, &le_val, sizeof(le_val))) {
                errcode = -EFAULT;
                break;
            }
            *val = le16_to_cpu(le_val);
        }
        break;
        case 'd': {
            int32_t *val = va_arg(ap, int32_t *);
            __le32 le_val;
            if (pdu_read(pdu, &le_val, sizeof(le_val))) {
                errcode = -EFAULT;
                break;
            }
            *val = le32_to_cpu(le_val);
        }
        break;
        case 'q': {
            int64_t *val = va_arg(ap, int64_t *);
            __le64 le_val;
            if (pdu_read(pdu, &le_val, sizeof(le_val))) {
                errcode = -EFAULT;
                break;
            }
            *val = le64_to_cpu(le_val);
        }
        break;
        case 's': {
            char **sptr = va_arg(ap, char **);
            int16_t len;
            int size;

            errcode = p9pdu_readf(pdu, proto_version,
                                  "w", &len);
            if (errcode)
                break;

            size = MAX(len, 0);

            *sptr = kmalloc(size + 1, GFP_KERNEL);
            if (*sptr == NULL) {
                errcode = -EFAULT;
                break;
            }
            if (pdu_read(pdu, *sptr, size)) {
                errcode = -EFAULT;
                kfree(*sptr);
                *sptr = NULL;
            } else
                (*sptr)[size] = 0;
        }
        break;
        case 'Q': {
            struct p9_qid *qid =
                va_arg(ap, struct p9_qid *);

            errcode = p9pdu_readf(pdu, proto_version, "bdq",
                                  &qid->type, &qid->version,
                                  &qid->path);
        }
        break;
        case 'S': {
            struct p9_wstat *stbuf =
                va_arg(ap, struct p9_wstat *);

            memset(stbuf, 0, sizeof(struct p9_wstat));
            stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
                                              -1;
            errcode =
                p9pdu_readf(pdu, proto_version,
                            "wwdQdddqssss?sddd",
                            &stbuf->size, &stbuf->type,
                            &stbuf->dev, &stbuf->qid,
                            &stbuf->mode, &stbuf->atime,
                            &stbuf->mtime, &stbuf->length,
                            &stbuf->name, &stbuf->uid,
                            &stbuf->gid, &stbuf->muid,
                            &stbuf->extension,
                            &stbuf->n_uid, &stbuf->n_gid,
                            &stbuf->n_muid);
            if (errcode)
                p9stat_free(stbuf);
        }
        break;
        case 'D': {
            int32_t *count = va_arg(ap, int32_t *);
            void **data = va_arg(ap, void **);

            errcode =
                p9pdu_readf(pdu, proto_version, "d", count);
            if (!errcode) {
                *count =
                    MIN(*count,
                        pdu->size - pdu->offset);
                *data = &pdu->sdata[pdu->offset];
            }
        }
        break;
        case 'T': {
            int16_t *nwname = va_arg(ap, int16_t *);
            char ***wnames = va_arg(ap, char ***);

            errcode = p9pdu_readf(pdu, proto_version,
                                  "w", nwname);
            if (!errcode) {
                *wnames =
                    kmalloc(sizeof(char *) * *nwname,
                            GFP_KERNEL);
                if (!*wnames)
                    errcode = -ENOMEM;
            }

            if (!errcode) {
                int i;

                for (i = 0; i < *nwname; i++) {
                    errcode =
                        p9pdu_readf(pdu,
                                    proto_version,
                                    "s",
                                    &(*wnames)[i]);
                    if (errcode)
                        break;
                }
            }

            if (errcode) {
                if (*wnames) {
                    int i;

                    for (i = 0; i < *nwname; i++)
                        kfree((*wnames)[i]);
                }
                kfree(*wnames);
                *wnames = NULL;
            }
        }
        break;
        case 'R': {
            int16_t *nwqid = va_arg(ap, int16_t *);
            struct p9_qid **wqids =
                va_arg(ap, struct p9_qid **);

            *wqids = NULL;

            errcode =
                p9pdu_readf(pdu, proto_version, "w", nwqid);
            if (!errcode) {
                *wqids =
                    kmalloc(*nwqid *
                            sizeof(struct p9_qid),
                            GFP_KERNEL);
                if (*wqids == NULL)
                    errcode = -ENOMEM;
            }

            if (!errcode) {
                int i;

                for (i = 0; i < *nwqid; i++) {
                    errcode =
                        p9pdu_readf(pdu,
                                    proto_version,
                                    "Q",
                                    &(*wqids)[i]);
                    if (errcode)
                        break;
                }
            }

            if (errcode) {
                kfree(*wqids);
                *wqids = NULL;
            }
        }
        break;
        case '?':
            if ((proto_version != p9_proto_2000u) &&
                    (proto_version != p9_proto_2000L))
                return 0;
            break;
        default:
            BUG();
            break;
        }

        if (errcode)
            break;
    }

    return errcode;
}
Пример #5
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;
}
Пример #6
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);
}