mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
e3b862ed89
- improve p9_check_errors to check buffer size instead of msize when possible (e.g. not zero-copy) - some more syzbot and KCSAN fixes - minor headers include cleanup -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE/IPbcYBuWt0zoYhOq06b7GqY5nAFAmOljPwACgkQq06b7GqY 5nDRjw//aJU+tdcKCMije/ul4hMWDlvMwxn7x6p0ELdomefs+ykS/knBxXSVIoEs PrbVJVZVqOOOAn/IwWe8cMBD+hal0fLUErRbfrtzmOdkiF7z8PavJ209OeJLKBgD ffL+bq6FhcVC6jVXcwVHoZkX9bb4pnM7/lsJrO0UjBw+fT3ceqtK0vsTa+R2xEOj 9lOS5124u69GVa9UvwQzqHko+UUx5T6XlULZYjNBEdtJqGULGi2oAABrae64R3N2 auaj5LRKzAFOx4zkJ+crCH1h08uZ4bfTyCHpfCeTHwWb1duKD3u4jMq9PhdetF4E A6NYnOdeMxbV/sZfFOjjNWQrzP1TQJLmF6IVGSZkVQrlCjrZh7xQ5dr/AHrKr6be U+NXb0UCmAS6/Gs7Sxq5jnihDHzJ4rYG+oFdYdNrwPrrpQXsYmmRh+bm61m/t40T 2JxBIiSt2KWL487AHsKisb6OsiH65N1ojntO5QJObZId4UdnhFJU6OaAzqv0Cojv mqKlZ0UPyxICXNCL227w+SdDFgK25efdLF1Z1547hS5DO0+43oWAtnvd3KrRpjZ6 CmV9ARvdhHt49lNedbxmJAre5FusJQLeULuRzhMbd4mdcG7mKAmGTdM3u+AlFRIu Te1ZotTJXxs16Yn/whWRShAooUnK9FbXzC3kViiibziYZlCfK+s= =xLkl -----END PGP SIGNATURE----- Merge tag '9p-for-6.2-rc1' of https://github.com/martinetd/linux Pull 9p updates from Dominique Martinet: - improve p9_check_errors to check buffer size instead of msize when possible (e.g. not zero-copy) - some more syzbot and KCSAN fixes - minor headers include cleanup * tag '9p-for-6.2-rc1' of https://github.com/martinetd/linux: 9p/client: fix data race on req->status net/9p: fix response size check in p9_check_errors() net/9p: distinguish zero-copy requests 9p/xen: do not memcpy header into req->rc 9p: set req refcount to zero to avoid uninitialized usage 9p/net: Remove unneeded idr.h #include 9p/fs: Remove unneeded idr.h #include
250 lines
5.2 KiB
C
250 lines
5.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* This file contains vfs directory ops for the 9P2000 protocol.
|
|
*
|
|
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
|
|
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/file.h>
|
|
#include <linux/stat.h>
|
|
#include <linux/string.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/inet.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/uio.h>
|
|
#include <linux/fscache.h>
|
|
#include <net/9p/9p.h>
|
|
#include <net/9p/client.h>
|
|
|
|
#include "v9fs.h"
|
|
#include "v9fs_vfs.h"
|
|
#include "fid.h"
|
|
|
|
/**
|
|
* struct p9_rdir - readdir accounting
|
|
* @head: start offset of current dirread buffer
|
|
* @tail: end offset of current dirread buffer
|
|
* @buf: dirread buffer
|
|
*
|
|
* private structure for keeping track of readdir
|
|
* allocated on demand
|
|
*/
|
|
|
|
struct p9_rdir {
|
|
int head;
|
|
int tail;
|
|
uint8_t buf[];
|
|
};
|
|
|
|
/**
|
|
* dt_type - return file type
|
|
* @mistat: mistat structure
|
|
*
|
|
*/
|
|
|
|
static inline int dt_type(struct p9_wstat *mistat)
|
|
{
|
|
unsigned long perm = mistat->mode;
|
|
int rettype = DT_REG;
|
|
|
|
if (perm & P9_DMDIR)
|
|
rettype = DT_DIR;
|
|
if (perm & P9_DMSYMLINK)
|
|
rettype = DT_LNK;
|
|
|
|
return rettype;
|
|
}
|
|
|
|
/**
|
|
* v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
|
|
* @filp: opened file structure
|
|
* @buflen: Length in bytes of buffer to allocate
|
|
*
|
|
*/
|
|
|
|
static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
|
|
{
|
|
struct p9_fid *fid = filp->private_data;
|
|
|
|
if (!fid->rdir)
|
|
fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
|
|
return fid->rdir;
|
|
}
|
|
|
|
/**
|
|
* v9fs_dir_readdir - iterate through a directory
|
|
* @file: opened file structure
|
|
* @ctx: actor we feed the entries to
|
|
*
|
|
*/
|
|
|
|
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;
|
|
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, ITER_DEST, &kvec, 1, buflen);
|
|
n = p9_client_read(file->private_data, ctx->pos, &to,
|
|
&err);
|
|
if (err)
|
|
return err;
|
|
if (n == 0)
|
|
return 0;
|
|
|
|
rdir->head = 0;
|
|
rdir->tail = n;
|
|
}
|
|
while (rdir->head < rdir->tail) {
|
|
err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
|
|
rdir->tail - rdir->head, &st);
|
|
if (err <= 0) {
|
|
p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
|
|
return -EIO;
|
|
}
|
|
|
|
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 += err;
|
|
ctx->pos += err;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* v9fs_dir_release - close a directory
|
|
* @inode: inode of the directory
|
|
* @filp: file pointer to a directory
|
|
*
|
|
*/
|
|
|
|
int v9fs_dir_release(struct inode *inode, struct file *filp)
|
|
{
|
|
struct v9fs_inode *v9inode = V9FS_I(inode);
|
|
struct p9_fid *fid;
|
|
__le32 version;
|
|
loff_t i_size;
|
|
|
|
fid = filp->private_data;
|
|
p9_debug(P9_DEBUG_VFS, "inode: %p filp: %p fid: %d\n",
|
|
inode, filp, fid ? fid->fid : -1);
|
|
if (fid) {
|
|
spin_lock(&inode->i_lock);
|
|
hlist_del(&fid->ilist);
|
|
spin_unlock(&inode->i_lock);
|
|
p9_fid_put(fid);
|
|
}
|
|
|
|
if ((filp->f_mode & FMODE_WRITE)) {
|
|
version = cpu_to_le32(v9inode->qid.version);
|
|
i_size = i_size_read(inode);
|
|
fscache_unuse_cookie(v9fs_inode_cookie(v9inode),
|
|
&version, &i_size);
|
|
} else {
|
|
fscache_unuse_cookie(v9fs_inode_cookie(v9inode), NULL, NULL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const struct file_operations v9fs_dir_operations = {
|
|
.read = generic_read_dir,
|
|
.llseek = generic_file_llseek,
|
|
.iterate_shared = v9fs_dir_readdir,
|
|
.open = v9fs_file_open,
|
|
.release = v9fs_dir_release,
|
|
};
|
|
|
|
const struct file_operations v9fs_dir_operations_dotl = {
|
|
.read = generic_read_dir,
|
|
.llseek = generic_file_llseek,
|
|
.iterate_shared = v9fs_dir_readdir_dotl,
|
|
.open = v9fs_file_open,
|
|
.release = v9fs_dir_release,
|
|
.fsync = v9fs_file_fsync_dotl,
|
|
};
|