Merge branch 'work.afs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull AFS updates from Al Viro:
 "AFS series, with some iov_iter bits included"

* 'work.afs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (26 commits)
  missing bits of "iov_iter: Separate type from direction and use accessor functions"
  afs: Probe multiple fileservers simultaneously
  afs: Fix callback handling
  afs: Eliminate the address pointer from the address list cursor
  afs: Allow dumping of server cursor on operation failure
  afs: Implement YFS support in the fs client
  afs: Expand data structure fields to support YFS
  afs: Get the target vnode in afs_rmdir() and get a callback on it
  afs: Calc callback expiry in op reply delivery
  afs: Fix FS.FetchStatus delivery from updating wrong vnode
  afs: Implement the YFS cache manager service
  afs: Remove callback details from afs_callback_break struct
  afs: Commit the status on a new file/dir/symlink
  afs: Increase to 64-bit volume ID and 96-bit vnode ID for YFS
  afs: Don't invoke the server to read data beyond EOF
  afs: Add a couple of tracepoints to log I/O errors
  afs: Handle EIO from delivery function
  afs: Fix TTL on VL server and address lists
  afs: Implement VL server rotation
  afs: Improve FS server rotation error handling
  ...
This commit is contained in:
Linus Torvalds 2018-11-01 19:58:52 -07:00
commit 9931a07d51
85 changed files with 5632 additions and 1239 deletions

View File

@ -1256,7 +1256,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
/* /*
* success * success
*/ */
if (((iter->type & WRITE) && (!map_data || !map_data->null_mapped)) || if ((iov_iter_rw(iter) == WRITE && (!map_data || !map_data->null_mapped)) ||
(map_data && map_data->from_user)) { (map_data && map_data->from_user)) {
ret = bio_copy_from_iter(bio, iter); ret = bio_copy_from_iter(bio, iter);
if (ret) if (ret)

View File

@ -1856,7 +1856,7 @@ int drbd_send(struct drbd_connection *connection, struct socket *sock,
/* THINK if (signal_pending) return ... ? */ /* THINK if (signal_pending) return ... ? */
iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iov, 1, size); iov_iter_kvec(&msg.msg_iter, WRITE, &iov, 1, size);
if (sock == connection->data.socket) { if (sock == connection->data.socket) {
rcu_read_lock(); rcu_read_lock();

View File

@ -516,7 +516,7 @@ static int drbd_recv_short(struct socket *sock, void *buf, size_t size, int flag
struct msghdr msg = { struct msghdr msg = {
.msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL) .msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL)
}; };
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, size); iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
return sock_recvmsg(sock, &msg, msg.msg_flags); return sock_recvmsg(sock, &msg, msg.msg_flags);
} }

View File

@ -269,7 +269,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos)
struct iov_iter i; struct iov_iter i;
ssize_t bw; ssize_t bw;
iov_iter_bvec(&i, ITER_BVEC | WRITE, bvec, 1, bvec->bv_len); iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len);
file_start_write(file); file_start_write(file);
bw = vfs_iter_write(file, &i, ppos, 0); bw = vfs_iter_write(file, &i, ppos, 0);
@ -347,7 +347,7 @@ static int lo_read_simple(struct loop_device *lo, struct request *rq,
ssize_t len; ssize_t len;
rq_for_each_segment(bvec, rq, iter) { rq_for_each_segment(bvec, rq, iter) {
iov_iter_bvec(&i, ITER_BVEC, &bvec, 1, bvec.bv_len); iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len);
len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0); len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
if (len < 0) if (len < 0)
return len; return len;
@ -388,7 +388,7 @@ static int lo_read_transfer(struct loop_device *lo, struct request *rq,
b.bv_offset = 0; b.bv_offset = 0;
b.bv_len = bvec.bv_len; b.bv_len = bvec.bv_len;
iov_iter_bvec(&i, ITER_BVEC, &b, 1, b.bv_len); iov_iter_bvec(&i, READ, &b, 1, b.bv_len);
len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0); len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
if (len < 0) { if (len < 0) {
ret = len; ret = len;
@ -555,8 +555,7 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
} }
atomic_set(&cmd->ref, 2); atomic_set(&cmd->ref, 2);
iov_iter_bvec(&iter, ITER_BVEC | rw, bvec, iov_iter_bvec(&iter, rw, bvec, segments, blk_rq_bytes(rq));
segments, blk_rq_bytes(rq));
iter.iov_offset = offset; iter.iov_offset = offset;
cmd->iocb.ki_pos = pos; cmd->iocb.ki_pos = pos;

View File

@ -473,7 +473,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
u32 nbd_cmd_flags = 0; u32 nbd_cmd_flags = 0;
int sent = nsock->sent, skip = 0; int sent = nsock->sent, skip = 0;
iov_iter_kvec(&from, WRITE | ITER_KVEC, &iov, 1, sizeof(request)); iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
switch (req_op(req)) { switch (req_op(req)) {
case REQ_OP_DISCARD: case REQ_OP_DISCARD:
@ -564,8 +564,7 @@ send_pages:
dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n", dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n",
req, bvec.bv_len); req, bvec.bv_len);
iov_iter_bvec(&from, ITER_BVEC | WRITE, iov_iter_bvec(&from, WRITE, &bvec, 1, bvec.bv_len);
&bvec, 1, bvec.bv_len);
if (skip) { if (skip) {
if (skip >= iov_iter_count(&from)) { if (skip >= iov_iter_count(&from)) {
skip -= iov_iter_count(&from); skip -= iov_iter_count(&from);
@ -624,7 +623,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
int ret = 0; int ret = 0;
reply.magic = 0; reply.magic = 0;
iov_iter_kvec(&to, READ | ITER_KVEC, &iov, 1, sizeof(reply)); iov_iter_kvec(&to, READ, &iov, 1, sizeof(reply));
result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
if (result <= 0) { if (result <= 0) {
if (!nbd_disconnected(config)) if (!nbd_disconnected(config))
@ -678,8 +677,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
struct bio_vec bvec; struct bio_vec bvec;
rq_for_each_segment(bvec, req, iter) { rq_for_each_segment(bvec, req, iter) {
iov_iter_bvec(&to, ITER_BVEC | READ, iov_iter_bvec(&to, READ, &bvec, 1, bvec.bv_len);
&bvec, 1, bvec.bv_len);
result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL);
if (result <= 0) { if (result <= 0) {
dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n", dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
@ -1073,7 +1071,7 @@ static void send_disconnects(struct nbd_device *nbd)
for (i = 0; i < config->num_connections; i++) { for (i = 0; i < config->num_connections; i++) {
struct nbd_sock *nsock = config->socks[i]; struct nbd_sock *nsock = config->socks[i];
iov_iter_kvec(&from, WRITE | ITER_KVEC, &iov, 1, sizeof(request)); iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));
mutex_lock(&nsock->tx_lock); mutex_lock(&nsock->tx_lock);
ret = sock_xmit(nbd, i, 1, &from, 0, NULL); ret = sock_xmit(nbd, i, 1, &from, 0, NULL);
if (ret <= 0) if (ret <= 0)

View File

@ -638,7 +638,7 @@ static void sbefifo_collect_async_ffdc(struct sbefifo *sbefifo)
} }
ffdc_iov.iov_base = ffdc; ffdc_iov.iov_base = ffdc;
ffdc_iov.iov_len = SBEFIFO_MAX_FFDC_SIZE; ffdc_iov.iov_len = SBEFIFO_MAX_FFDC_SIZE;
iov_iter_kvec(&ffdc_iter, WRITE | ITER_KVEC, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE); iov_iter_kvec(&ffdc_iter, WRITE, &ffdc_iov, 1, SBEFIFO_MAX_FFDC_SIZE);
cmd[0] = cpu_to_be32(2); cmd[0] = cpu_to_be32(2);
cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_SBE_FFDC); cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_SBE_FFDC);
rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter); rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter);
@ -735,7 +735,7 @@ int sbefifo_submit(struct device *dev, const __be32 *command, size_t cmd_len,
rbytes = (*resp_len) * sizeof(__be32); rbytes = (*resp_len) * sizeof(__be32);
resp_iov.iov_base = response; resp_iov.iov_base = response;
resp_iov.iov_len = rbytes; resp_iov.iov_len = rbytes;
iov_iter_kvec(&resp_iter, WRITE | ITER_KVEC, &resp_iov, 1, rbytes); iov_iter_kvec(&resp_iter, WRITE, &resp_iov, 1, rbytes);
/* Perform the command */ /* Perform the command */
mutex_lock(&sbefifo->lock); mutex_lock(&sbefifo->lock);

View File

@ -40,8 +40,6 @@
#define LITTLEENDIAN_CPU #define LITTLEENDIAN_CPU
#endif #endif
#undef READ
#undef WRITE
#undef FRAME_SIZE #undef FRAME_SIZE
#define dm_output_to_console(fmt, ...) DRM_DEBUG_KMS(fmt, ##__VA_ARGS__) #define dm_output_to_console(fmt, ...) DRM_DEBUG_KMS(fmt, ##__VA_ARGS__)

View File

@ -718,8 +718,7 @@ l1oip_socket_thread(void *data)
printk(KERN_DEBUG "%s: socket created and open\n", printk(KERN_DEBUG "%s: socket created and open\n",
__func__); __func__);
while (!signal_pending(current)) { while (!signal_pending(current)) {
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, recvbuf_size);
recvbuf_size);
recvlen = sock_recvmsg(socket, &msg, 0); recvlen = sock_recvmsg(socket, &msg, 0);
if (recvlen > 0) { if (recvlen > 0) {
l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen);

View File

@ -3030,7 +3030,7 @@ ssize_t vmci_qpair_enqueue(struct vmci_qp *qpair,
if (!qpair || !buf) if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS; return VMCI_ERROR_INVALID_ARGS;
iov_iter_kvec(&from, WRITE | ITER_KVEC, &v, 1, buf_size); iov_iter_kvec(&from, WRITE, &v, 1, buf_size);
qp_lock(qpair); qp_lock(qpair);
@ -3074,7 +3074,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,
if (!qpair || !buf) if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS; return VMCI_ERROR_INVALID_ARGS;
iov_iter_kvec(&to, READ | ITER_KVEC, &v, 1, buf_size); iov_iter_kvec(&to, READ, &v, 1, buf_size);
qp_lock(qpair); qp_lock(qpair);
@ -3119,7 +3119,7 @@ ssize_t vmci_qpair_peek(struct vmci_qp *qpair,
if (!qpair || !buf) if (!qpair || !buf)
return VMCI_ERROR_INVALID_ARGS; return VMCI_ERROR_INVALID_ARGS;
iov_iter_kvec(&to, READ | ITER_KVEC, &v, 1, buf_size); iov_iter_kvec(&to, READ, &v, 1, buf_size);
qp_lock(qpair); qp_lock(qpair);

View File

@ -101,7 +101,7 @@ static ssize_t nvmet_file_submit_bvec(struct nvmet_req *req, loff_t pos,
rw = READ; rw = READ;
} }
iov_iter_bvec(&iter, ITER_BVEC | rw, req->f.bvec, nr_segs, count); iov_iter_bvec(&iter, rw, req->f.bvec, nr_segs, count);
iocb->ki_pos = pos; iocb->ki_pos = pos;
iocb->ki_filp = req->ns->file; iocb->ki_filp = req->ns->file;

View File

@ -1245,8 +1245,7 @@ static int iscsit_do_rx_data(
return -1; return -1;
memset(&msg, 0, sizeof(struct msghdr)); memset(&msg, 0, sizeof(struct msghdr));
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, iov_iter_kvec(&msg.msg_iter, READ, count->iov, count->iov_count, data);
count->iov, count->iov_count, data);
while (msg_data_left(&msg)) { while (msg_data_left(&msg)) {
rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL); rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL);
@ -1302,8 +1301,7 @@ int tx_data(
memset(&msg, 0, sizeof(struct msghdr)); memset(&msg, 0, sizeof(struct msghdr));
iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov_iter_kvec(&msg.msg_iter, WRITE, iov, iov_count, data);
iov, iov_count, data);
while (msg_data_left(&msg)) { while (msg_data_left(&msg)) {
int tx_loop = sock_sendmsg(conn->sock, &msg); int tx_loop = sock_sendmsg(conn->sock, &msg);

View File

@ -303,7 +303,7 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
len += sg->length; len += sg->length;
} }
iov_iter_bvec(&iter, ITER_BVEC | is_write, bvec, sgl_nents, len); iov_iter_bvec(&iter, is_write, bvec, sgl_nents, len);
aio_cmd->cmd = cmd; aio_cmd->cmd = cmd;
aio_cmd->len = len; aio_cmd->len = len;
@ -353,7 +353,7 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd,
len += sg->length; len += sg->length;
} }
iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len); iov_iter_bvec(&iter, READ, bvec, sgl_nents, len);
if (is_write) if (is_write)
ret = vfs_iter_write(fd, &iter, &pos, 0); ret = vfs_iter_write(fd, &iter, &pos, 0);
else else
@ -490,7 +490,7 @@ fd_execute_write_same(struct se_cmd *cmd)
len += se_dev->dev_attrib.block_size; len += se_dev->dev_attrib.block_size;
} }
iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len); iov_iter_bvec(&iter, READ, bvec, nolb, len);
ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0); ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0);
kfree(bvec); kfree(bvec);

View File

@ -309,7 +309,7 @@ int usbip_recv(struct socket *sock, void *buf, int size)
if (!sock || !buf || !size) if (!sock || !buf || !size)
return -EINVAL; return -EINVAL;
iov_iter_kvec(&msg.msg_iter, READ|ITER_KVEC, &iov, 1, size); iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, size);
usbip_dbg_xmit("enter\n"); usbip_dbg_xmit("enter\n");

View File

@ -137,13 +137,13 @@ static void pvcalls_conn_back_read(void *opaque)
if (masked_prod < masked_cons) { if (masked_prod < masked_cons) {
vec[0].iov_base = data->in + masked_prod; vec[0].iov_base = data->in + masked_prod;
vec[0].iov_len = wanted; vec[0].iov_len = wanted;
iov_iter_kvec(&msg.msg_iter, ITER_KVEC|WRITE, vec, 1, wanted); iov_iter_kvec(&msg.msg_iter, WRITE, vec, 1, wanted);
} else { } else {
vec[0].iov_base = data->in + masked_prod; vec[0].iov_base = data->in + masked_prod;
vec[0].iov_len = array_size - masked_prod; vec[0].iov_len = array_size - masked_prod;
vec[1].iov_base = data->in; vec[1].iov_base = data->in;
vec[1].iov_len = wanted - vec[0].iov_len; vec[1].iov_len = wanted - vec[0].iov_len;
iov_iter_kvec(&msg.msg_iter, ITER_KVEC|WRITE, vec, 2, wanted); iov_iter_kvec(&msg.msg_iter, WRITE, vec, 2, wanted);
} }
atomic_set(&map->read, 0); atomic_set(&map->read, 0);
@ -195,13 +195,13 @@ static void pvcalls_conn_back_write(struct sock_mapping *map)
if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) { if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) {
vec[0].iov_base = data->out + pvcalls_mask(cons, array_size); vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
vec[0].iov_len = size; vec[0].iov_len = size;
iov_iter_kvec(&msg.msg_iter, ITER_KVEC|READ, vec, 1, size); iov_iter_kvec(&msg.msg_iter, READ, vec, 1, size);
} else { } else {
vec[0].iov_base = data->out + pvcalls_mask(cons, array_size); vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
vec[0].iov_len = array_size - pvcalls_mask(cons, array_size); vec[0].iov_len = array_size - pvcalls_mask(cons, array_size);
vec[1].iov_base = data->out; vec[1].iov_base = data->out;
vec[1].iov_len = size - vec[0].iov_len; vec[1].iov_len = size - vec[0].iov_len;
iov_iter_kvec(&msg.msg_iter, ITER_KVEC|READ, vec, 2, size); iov_iter_kvec(&msg.msg_iter, READ, vec, 2, size);
} }
atomic_set(&map->write, 0); atomic_set(&map->write, 0);

View File

@ -65,7 +65,7 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
if (retval == 0) if (retval == 0)
return retval; return retval;
iov_iter_bvec(&to, ITER_BVEC | READ, &bvec, 1, PAGE_SIZE); iov_iter_bvec(&to, READ, &bvec, 1, PAGE_SIZE);
retval = p9_client_read(fid, page_offset(page), &to, &err); retval = p9_client_read(fid, page_offset(page), &to, &err);
if (err) { if (err) {
@ -175,7 +175,7 @@ static int v9fs_vfs_writepage_locked(struct page *page)
bvec.bv_page = page; bvec.bv_page = page;
bvec.bv_offset = 0; bvec.bv_offset = 0;
bvec.bv_len = len; bvec.bv_len = len;
iov_iter_bvec(&from, ITER_BVEC | WRITE, &bvec, 1, len); iov_iter_bvec(&from, WRITE, &bvec, 1, len);
/* We should have writeback_fid always set */ /* We should have writeback_fid always set */
BUG_ON(!v9inode->writeback_fid); BUG_ON(!v9inode->writeback_fid);

View File

@ -123,7 +123,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
if (rdir->tail == rdir->head) { if (rdir->tail == rdir->head) {
struct iov_iter to; struct iov_iter to;
int n; int n;
iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buflen); iov_iter_kvec(&to, READ, &kvec, 1, buflen);
n = p9_client_read(file->private_data, ctx->pos, &to, n = p9_client_read(file->private_data, ctx->pos, &to,
&err); &err);
if (err) if (err)

View File

@ -32,7 +32,7 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
struct iov_iter to; struct iov_iter to;
int err; int err;
iov_iter_kvec(&to, READ | ITER_KVEC, &kvec, 1, buffer_size); iov_iter_kvec(&to, READ, &kvec, 1, buffer_size);
attr_fid = p9_client_xattrwalk(fid, name, &attr_size); attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
if (IS_ERR(attr_fid)) { if (IS_ERR(attr_fid)) {
@ -107,7 +107,7 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
struct iov_iter from; struct iov_iter from;
int retval, err; int retval, err;
iov_iter_kvec(&from, WRITE | ITER_KVEC, &kvec, 1, value_len); iov_iter_kvec(&from, WRITE, &kvec, 1, value_len);
p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n", p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n",
name, value_len, flags); name, value_len, flags);

View File

@ -27,3 +27,15 @@ config AFS_FSCACHE
help help
Say Y here if you want AFS data to be cached locally on disk through Say Y here if you want AFS data to be cached locally on disk through
the generic filesystem cache manager the generic filesystem cache manager
config AFS_DEBUG_CURSOR
bool "AFS server cursor debugging"
depends on AFS_FS
help
Say Y here to cause the contents of a server cursor to be dumped to
the dmesg log if the server rotation algorithm fails to successfully
contact a server.
See <file:Documentation/filesystems/afs.txt> for more information.
If unsure, say N.

View File

@ -17,6 +17,7 @@ kafs-y := \
file.o \ file.o \
flock.o \ flock.o \
fsclient.o \ fsclient.o \
fs_probe.o \
inode.o \ inode.o \
main.o \ main.o \
misc.o \ misc.o \
@ -29,9 +30,13 @@ kafs-y := \
super.o \ super.o \
netdevices.o \ netdevices.o \
vlclient.o \ vlclient.o \
vl_list.o \
vl_probe.o \
vl_rotate.o \
volume.o \ volume.o \
write.o \ write.o \
xattr.o xattr.o \
yfsclient.o
kafs-$(CONFIG_PROC_FS) += proc.o kafs-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_AFS_FS) := kafs.o obj-$(CONFIG_AFS_FS) := kafs.o

View File

@ -64,19 +64,25 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr,
/* /*
* Parse a text string consisting of delimited addresses. * Parse a text string consisting of delimited addresses.
*/ */
struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *net,
const char *text, size_t len,
char delim, char delim,
unsigned short service, unsigned short service,
unsigned short port) unsigned short port)
{ {
struct afs_vlserver_list *vllist;
struct afs_addr_list *alist; struct afs_addr_list *alist;
const char *p, *end = text + len; const char *p, *end = text + len;
const char *problem;
unsigned int nr = 0; unsigned int nr = 0;
int ret = -ENOMEM;
_enter("%*.*s,%c", (int)len, (int)len, text, delim); _enter("%*.*s,%c", (int)len, (int)len, text, delim);
if (!len) if (!len) {
_leave(" = -EDESTADDRREQ [empty]");
return ERR_PTR(-EDESTADDRREQ); return ERR_PTR(-EDESTADDRREQ);
}
if (delim == ':' && (memchr(text, ',', len) || !memchr(text, '.', len))) if (delim == ':' && (memchr(text, ',', len) || !memchr(text, '.', len)))
delim = ','; delim = ',';
@ -84,18 +90,24 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
/* Count the addresses */ /* Count the addresses */
p = text; p = text;
do { do {
if (!*p) if (!*p) {
return ERR_PTR(-EINVAL); problem = "nul";
goto inval;
}
if (*p == delim) if (*p == delim)
continue; continue;
nr++; nr++;
if (*p == '[') { if (*p == '[') {
p++; p++;
if (p == end) if (p == end) {
return ERR_PTR(-EINVAL); problem = "brace1";
goto inval;
}
p = memchr(p, ']', end - p); p = memchr(p, ']', end - p);
if (!p) if (!p) {
return ERR_PTR(-EINVAL); problem = "brace2";
goto inval;
}
p++; p++;
if (p >= end) if (p >= end)
break; break;
@ -109,10 +121,19 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
_debug("%u/%u addresses", nr, AFS_MAX_ADDRESSES); _debug("%u/%u addresses", nr, AFS_MAX_ADDRESSES);
alist = afs_alloc_addrlist(nr, service, port); vllist = afs_alloc_vlserver_list(1);
if (!alist) if (!vllist)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
vllist->nr_servers = 1;
vllist->servers[0].server = afs_alloc_vlserver("<dummy>", 7, AFS_VL_PORT);
if (!vllist->servers[0].server)
goto error_vl;
alist = afs_alloc_addrlist(nr, service, AFS_VL_PORT);
if (!alist)
goto error;
/* Extract the addresses */ /* Extract the addresses */
p = text; p = text;
do { do {
@ -135,17 +156,21 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
break; break;
} }
if (in4_pton(p, q - p, (u8 *)&x[0], -1, &stop)) if (in4_pton(p, q - p, (u8 *)&x[0], -1, &stop)) {
family = AF_INET; family = AF_INET;
else if (in6_pton(p, q - p, (u8 *)x, -1, &stop)) } else if (in6_pton(p, q - p, (u8 *)x, -1, &stop)) {
family = AF_INET6; family = AF_INET6;
else } else {
goto bad_address; problem = "family";
if (stop != q)
goto bad_address; goto bad_address;
}
p = q; p = q;
if (stop != p) {
problem = "nostop";
goto bad_address;
}
if (q < end && *q == ']') if (q < end && *q == ']')
p++; p++;
@ -154,18 +179,23 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
/* Port number specification "+1234" */ /* Port number specification "+1234" */
xport = 0; xport = 0;
p++; p++;
if (p >= end || !isdigit(*p)) if (p >= end || !isdigit(*p)) {
problem = "port";
goto bad_address; goto bad_address;
}
do { do {
xport *= 10; xport *= 10;
xport += *p - '0'; xport += *p - '0';
if (xport > 65535) if (xport > 65535) {
problem = "pval";
goto bad_address; goto bad_address;
}
p++; p++;
} while (p < end && isdigit(*p)); } while (p < end && isdigit(*p));
} else if (*p == delim) { } else if (*p == delim) {
p++; p++;
} else { } else {
problem = "weird";
goto bad_address; goto bad_address;
} }
} }
@ -177,12 +207,23 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
} while (p < end); } while (p < end);
rcu_assign_pointer(vllist->servers[0].server->addresses, alist);
_leave(" = [nr %u]", alist->nr_addrs); _leave(" = [nr %u]", alist->nr_addrs);
return alist; return vllist;
bad_address: inval:
kfree(alist); _leave(" = -EINVAL [%s %zu %*.*s]",
problem, p - text, (int)len, (int)len, text);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
bad_address:
_leave(" = -EINVAL [%s %zu %*.*s]",
problem, p - text, (int)len, (int)len, text);
ret = -EINVAL;
error:
afs_put_addrlist(alist);
error_vl:
afs_put_vlserverlist(net, vllist);
return ERR_PTR(ret);
} }
/* /*
@ -201,30 +242,34 @@ static int afs_cmp_addr_list(const struct afs_addr_list *a1,
/* /*
* Perform a DNS query for VL servers and build a up an address list. * Perform a DNS query for VL servers and build a up an address list.
*/ */
struct afs_addr_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry) struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry)
{ {
struct afs_addr_list *alist; struct afs_vlserver_list *vllist;
char *vllist = NULL; char *result = NULL;
int ret; int ret;
_enter("%s", cell->name); _enter("%s", cell->name);
ret = dns_query("afsdb", cell->name, cell->name_len, ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1",
"", &vllist, _expiry); &result, _expiry);
if (ret < 0) if (ret < 0) {
_leave(" = %d [dns]", ret);
return ERR_PTR(ret); return ERR_PTR(ret);
alist = afs_parse_text_addrs(vllist, strlen(vllist), ',',
VL_SERVICE, AFS_VL_PORT);
if (IS_ERR(alist)) {
kfree(vllist);
if (alist != ERR_PTR(-ENOMEM))
pr_err("Failed to parse DNS data\n");
return alist;
} }
kfree(vllist); if (*_expiry == 0)
return alist; *_expiry = ktime_get_real_seconds() + 60;
if (ret > 1 && result[0] == 0)
vllist = afs_extract_vlserver_list(cell, result, ret);
else
vllist = afs_parse_text_addrs(cell->net, result, ret, ',',
VL_SERVICE, AFS_VL_PORT);
kfree(result);
if (IS_ERR(vllist) && vllist != ERR_PTR(-ENOMEM))
pr_err("Failed to parse DNS data %ld\n", PTR_ERR(vllist));
return vllist;
} }
/* /*
@ -258,6 +303,8 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); sizeof(alist->addrs[0]) * (alist->nr_addrs - i));
srx = &alist->addrs[i]; srx = &alist->addrs[i];
srx->srx_family = AF_RXRPC;
srx->transport_type = SOCK_DGRAM;
srx->transport_len = sizeof(srx->transport.sin); srx->transport_len = sizeof(srx->transport.sin);
srx->transport.sin.sin_family = AF_INET; srx->transport.sin.sin_family = AF_INET;
srx->transport.sin.sin_port = htons(port); srx->transport.sin.sin_port = htons(port);
@ -296,6 +343,8 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); sizeof(alist->addrs[0]) * (alist->nr_addrs - i));
srx = &alist->addrs[i]; srx = &alist->addrs[i];
srx->srx_family = AF_RXRPC;
srx->transport_type = SOCK_DGRAM;
srx->transport_len = sizeof(srx->transport.sin6); srx->transport_len = sizeof(srx->transport.sin6);
srx->transport.sin6.sin6_family = AF_INET6; srx->transport.sin6.sin6_family = AF_INET6;
srx->transport.sin6.sin6_port = htons(port); srx->transport.sin6.sin6_port = htons(port);
@ -308,25 +357,33 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
*/ */
bool afs_iterate_addresses(struct afs_addr_cursor *ac) bool afs_iterate_addresses(struct afs_addr_cursor *ac)
{ {
_enter("%hu+%hd", ac->start, (short)ac->index); unsigned long set, failed;
int index;
if (!ac->alist) if (!ac->alist)
return false; return false;
if (ac->begun) { set = ac->alist->responded;
ac->index++; failed = ac->alist->failed;
if (ac->index == ac->alist->nr_addrs) _enter("%lx-%lx-%lx,%d", set, failed, ac->tried, ac->index);
ac->index = 0;
if (ac->index == ac->start) { ac->nr_iterations++;
ac->error = -EDESTADDRREQ;
set &= ~(failed | ac->tried);
if (!set)
return false; return false;
}
}
ac->begun = true; index = READ_ONCE(ac->alist->preferred);
if (test_bit(index, &set))
goto selected;
index = __ffs(set);
selected:
ac->index = index;
set_bit(index, &ac->tried);
ac->responded = false; ac->responded = false;
ac->addr = &ac->alist->addrs[ac->index];
return true; return true;
} }
@ -339,53 +396,13 @@ int afs_end_cursor(struct afs_addr_cursor *ac)
alist = ac->alist; alist = ac->alist;
if (alist) { if (alist) {
if (ac->responded && ac->index != ac->start) if (ac->responded &&
WRITE_ONCE(alist->index, ac->index); ac->index != alist->preferred &&
test_bit(ac->alist->preferred, &ac->tried))
WRITE_ONCE(alist->preferred, ac->index);
afs_put_addrlist(alist); afs_put_addrlist(alist);
ac->alist = NULL;
} }
ac->addr = NULL;
ac->alist = NULL;
ac->begun = false;
return ac->error; return ac->error;
} }
/*
* Set the address cursor for iterating over VL servers.
*/
int afs_set_vl_cursor(struct afs_addr_cursor *ac, struct afs_cell *cell)
{
struct afs_addr_list *alist;
int ret;
if (!rcu_access_pointer(cell->vl_addrs)) {
ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET,
TASK_INTERRUPTIBLE);
if (ret < 0)
return ret;
if (!rcu_access_pointer(cell->vl_addrs) &&
ktime_get_real_seconds() < cell->dns_expiry)
return cell->error;
}
read_lock(&cell->vl_addrs_lock);
alist = rcu_dereference_protected(cell->vl_addrs,
lockdep_is_held(&cell->vl_addrs_lock));
if (alist->nr_addrs > 0)
afs_get_addrlist(alist);
else
alist = NULL;
read_unlock(&cell->vl_addrs_lock);
if (!alist)
return -EDESTADDRREQ;
ac->alist = alist;
ac->addr = NULL;
ac->start = READ_ONCE(alist->index);
ac->index = ac->start;
ac->error = 0;
ac->begun = false;
return 0;
}

View File

@ -23,9 +23,9 @@
#define AFSPATHMAX 1024 /* Maximum length of a pathname plus NUL */ #define AFSPATHMAX 1024 /* Maximum length of a pathname plus NUL */
#define AFSOPAQUEMAX 1024 /* Maximum length of an opaque field */ #define AFSOPAQUEMAX 1024 /* Maximum length of an opaque field */
typedef unsigned afs_volid_t; typedef u64 afs_volid_t;
typedef unsigned afs_vnodeid_t; typedef u64 afs_vnodeid_t;
typedef unsigned long long afs_dataversion_t; typedef u64 afs_dataversion_t;
typedef enum { typedef enum {
AFSVL_RWVOL, /* read/write volume */ AFSVL_RWVOL, /* read/write volume */
@ -52,8 +52,9 @@ typedef enum {
*/ */
struct afs_fid { struct afs_fid {
afs_volid_t vid; /* volume ID */ afs_volid_t vid; /* volume ID */
afs_vnodeid_t vnode; /* file index within volume */ afs_vnodeid_t vnode; /* Lower 64-bits of file index within volume */
unsigned unique; /* unique ID number (file index version) */ u32 vnode_hi; /* Upper 32-bits of file index */
u32 unique; /* unique ID number (file index version) */
}; };
/* /*
@ -67,14 +68,14 @@ typedef enum {
} afs_callback_type_t; } afs_callback_type_t;
struct afs_callback { struct afs_callback {
time64_t expires_at; /* Time at which expires */
unsigned version; /* Callback version */ unsigned version; /* Callback version */
unsigned expiry; /* Time at which expires */
afs_callback_type_t type; /* Type of callback */ afs_callback_type_t type; /* Type of callback */
}; };
struct afs_callback_break { struct afs_callback_break {
struct afs_fid fid; /* File identifier */ struct afs_fid fid; /* File identifier */
struct afs_callback cb; /* Callback details */ //struct afs_callback cb; /* Callback details */
}; };
#define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */ #define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */
@ -129,19 +130,18 @@ typedef u32 afs_access_t;
struct afs_file_status { struct afs_file_status {
u64 size; /* file size */ u64 size; /* file size */
afs_dataversion_t data_version; /* current data version */ afs_dataversion_t data_version; /* current data version */
time_t mtime_client; /* last time client changed data */ struct timespec64 mtime_client; /* Last time client changed data */
time_t mtime_server; /* last time server changed data */ struct timespec64 mtime_server; /* Last time server changed data */
unsigned abort_code; /* Abort if bulk-fetching this failed */ s64 author; /* author ID */
s64 owner; /* owner ID */
afs_file_type_t type; /* file type */ s64 group; /* group ID */
unsigned nlink; /* link count */
u32 author; /* author ID */
u32 owner; /* owner ID */
u32 group; /* group ID */
afs_access_t caller_access; /* access rights for authenticated caller */ afs_access_t caller_access; /* access rights for authenticated caller */
afs_access_t anon_access; /* access rights for unauthenticated caller */ afs_access_t anon_access; /* access rights for unauthenticated caller */
umode_t mode; /* UNIX mode */ umode_t mode; /* UNIX mode */
afs_file_type_t type; /* file type */
u32 nlink; /* link count */
s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */ s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */
u32 abort_code; /* Abort if bulk-fetching this failed */
}; };
/* /*
@ -158,25 +158,27 @@ struct afs_file_status {
* AFS volume synchronisation information * AFS volume synchronisation information
*/ */
struct afs_volsync { struct afs_volsync {
time_t creation; /* volume creation time */ time64_t creation; /* volume creation time */
}; };
/* /*
* AFS volume status record * AFS volume status record
*/ */
struct afs_volume_status { struct afs_volume_status {
u32 vid; /* volume ID */ afs_volid_t vid; /* volume ID */
u32 parent_id; /* parent volume ID */ afs_volid_t parent_id; /* parent volume ID */
u8 online; /* true if volume currently online and available */ u8 online; /* true if volume currently online and available */
u8 in_service; /* true if volume currently in service */ u8 in_service; /* true if volume currently in service */
u8 blessed; /* same as in_service */ u8 blessed; /* same as in_service */
u8 needs_salvage; /* true if consistency checking required */ u8 needs_salvage; /* true if consistency checking required */
u32 type; /* volume type (afs_voltype_t) */ u32 type; /* volume type (afs_voltype_t) */
u32 min_quota; /* minimum space set aside (blocks) */ u64 min_quota; /* minimum space set aside (blocks) */
u32 max_quota; /* maximum space this volume may occupy (blocks) */ u64 max_quota; /* maximum space this volume may occupy (blocks) */
u32 blocks_in_use; /* space this volume currently occupies (blocks) */ u64 blocks_in_use; /* space this volume currently occupies (blocks) */
u32 part_blocks_avail; /* space available in volume's partition */ u64 part_blocks_avail; /* space available in volume's partition */
u32 part_max_blocks; /* size of volume's partition */ u64 part_max_blocks; /* size of volume's partition */
s64 vol_copy_date;
s64 vol_backup_date;
}; };
#define AFS_BLOCK_SIZE 1024 #define AFS_BLOCK_SIZE 1024

View File

@ -49,7 +49,7 @@ static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
struct afs_vnode *vnode = cookie_netfs_data; struct afs_vnode *vnode = cookie_netfs_data;
struct afs_vnode_cache_aux aux; struct afs_vnode_cache_aux aux;
_enter("{%x,%x,%llx},%p,%u", _enter("{%llx,%x,%llx},%p,%u",
vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
buffer, buflen); buffer, buflen);

View File

@ -210,12 +210,10 @@ void afs_init_callback_state(struct afs_server *server)
/* /*
* actually break a callback * actually break a callback
*/ */
void afs_break_callback(struct afs_vnode *vnode) void __afs_break_callback(struct afs_vnode *vnode)
{ {
_enter(""); _enter("");
write_seqlock(&vnode->cb_lock);
clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
vnode->cb_break++; vnode->cb_break++;
@ -230,7 +228,12 @@ void afs_break_callback(struct afs_vnode *vnode)
afs_lock_may_be_available(vnode); afs_lock_may_be_available(vnode);
spin_unlock(&vnode->lock); spin_unlock(&vnode->lock);
} }
}
void afs_break_callback(struct afs_vnode *vnode)
{
write_seqlock(&vnode->cb_lock);
__afs_break_callback(vnode);
write_sequnlock(&vnode->cb_lock); write_sequnlock(&vnode->cb_lock);
} }
@ -310,14 +313,10 @@ void afs_break_callbacks(struct afs_server *server, size_t count,
/* TODO: Sort the callback break list by volume ID */ /* TODO: Sort the callback break list by volume ID */
for (; count > 0; callbacks++, count--) { for (; count > 0; callbacks++, count--) {
_debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", _debug("- Fid { vl=%08llx n=%llu u=%u }",
callbacks->fid.vid, callbacks->fid.vid,
callbacks->fid.vnode, callbacks->fid.vnode,
callbacks->fid.unique, callbacks->fid.unique);
callbacks->cb.version,
callbacks->cb.expiry,
callbacks->cb.type
);
afs_break_one_callback(server, &callbacks->fid); afs_break_one_callback(server, &callbacks->fid);
} }

View File

@ -20,6 +20,8 @@
#include "internal.h" #include "internal.h"
static unsigned __read_mostly afs_cell_gc_delay = 10; static unsigned __read_mostly afs_cell_gc_delay = 10;
static unsigned __read_mostly afs_cell_min_ttl = 10 * 60;
static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60;
static void afs_manage_cell(struct work_struct *); static void afs_manage_cell(struct work_struct *);
@ -119,7 +121,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
*/ */
static struct afs_cell *afs_alloc_cell(struct afs_net *net, static struct afs_cell *afs_alloc_cell(struct afs_net *net,
const char *name, unsigned int namelen, const char *name, unsigned int namelen,
const char *vllist) const char *addresses)
{ {
struct afs_cell *cell; struct afs_cell *cell;
int i, ret; int i, ret;
@ -134,7 +136,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
if (namelen == 5 && memcmp(name, "@cell", 5) == 0) if (namelen == 5 && memcmp(name, "@cell", 5) == 0)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
_enter("%*.*s,%s", namelen, namelen, name, vllist); _enter("%*.*s,%s", namelen, namelen, name, addresses);
cell = kzalloc(sizeof(struct afs_cell), GFP_KERNEL); cell = kzalloc(sizeof(struct afs_cell), GFP_KERNEL);
if (!cell) { if (!cell) {
@ -153,23 +155,26 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
(1 << AFS_CELL_FL_NO_LOOKUP_YET)); (1 << AFS_CELL_FL_NO_LOOKUP_YET));
INIT_LIST_HEAD(&cell->proc_volumes); INIT_LIST_HEAD(&cell->proc_volumes);
rwlock_init(&cell->proc_lock); rwlock_init(&cell->proc_lock);
rwlock_init(&cell->vl_addrs_lock); rwlock_init(&cell->vl_servers_lock);
/* Fill in the VL server list if we were given a list of addresses to /* Fill in the VL server list if we were given a list of addresses to
* use. * use.
*/ */
if (vllist) { if (addresses) {
struct afs_addr_list *alist; struct afs_vlserver_list *vllist;
alist = afs_parse_text_addrs(vllist, strlen(vllist), ':', vllist = afs_parse_text_addrs(net,
addresses, strlen(addresses), ':',
VL_SERVICE, AFS_VL_PORT); VL_SERVICE, AFS_VL_PORT);
if (IS_ERR(alist)) { if (IS_ERR(vllist)) {
ret = PTR_ERR(alist); ret = PTR_ERR(vllist);
goto parse_failed; goto parse_failed;
} }
rcu_assign_pointer(cell->vl_addrs, alist); rcu_assign_pointer(cell->vl_servers, vllist);
cell->dns_expiry = TIME64_MAX; cell->dns_expiry = TIME64_MAX;
} else {
cell->dns_expiry = ktime_get_real_seconds();
} }
_leave(" = %p", cell); _leave(" = %p", cell);
@ -356,26 +361,40 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
*/ */
static void afs_update_cell(struct afs_cell *cell) static void afs_update_cell(struct afs_cell *cell)
{ {
struct afs_addr_list *alist, *old; struct afs_vlserver_list *vllist, *old;
time64_t now, expiry; unsigned int min_ttl = READ_ONCE(afs_cell_min_ttl);
unsigned int max_ttl = READ_ONCE(afs_cell_max_ttl);
time64_t now, expiry = 0;
_enter("%s", cell->name); _enter("%s", cell->name);
alist = afs_dns_query(cell, &expiry); vllist = afs_dns_query(cell, &expiry);
if (IS_ERR(alist)) {
switch (PTR_ERR(alist)) { now = ktime_get_real_seconds();
if (min_ttl > max_ttl)
max_ttl = min_ttl;
if (expiry < now + min_ttl)
expiry = now + min_ttl;
else if (expiry > now + max_ttl)
expiry = now + max_ttl;
if (IS_ERR(vllist)) {
switch (PTR_ERR(vllist)) {
case -ENODATA: case -ENODATA:
/* The DNS said that the cell does not exist */ case -EDESTADDRREQ:
/* The DNS said that the cell does not exist or there
* weren't any addresses to be had.
*/
set_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags); set_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags); clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
cell->dns_expiry = ktime_get_real_seconds() + 61; cell->dns_expiry = expiry;
break; break;
case -EAGAIN: case -EAGAIN:
case -ECONNREFUSED: case -ECONNREFUSED:
default: default:
set_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags); set_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
cell->dns_expiry = ktime_get_real_seconds() + 10; cell->dns_expiry = now + 10;
break; break;
} }
@ -387,12 +406,12 @@ static void afs_update_cell(struct afs_cell *cell)
/* Exclusion on changing vl_addrs is achieved by a /* Exclusion on changing vl_addrs is achieved by a
* non-reentrant work item. * non-reentrant work item.
*/ */
old = rcu_dereference_protected(cell->vl_addrs, true); old = rcu_dereference_protected(cell->vl_servers, true);
rcu_assign_pointer(cell->vl_addrs, alist); rcu_assign_pointer(cell->vl_servers, vllist);
cell->dns_expiry = expiry; cell->dns_expiry = expiry;
if (old) if (old)
afs_put_addrlist(old); afs_put_vlserverlist(cell->net, old);
} }
if (test_and_clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags)) if (test_and_clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags))
@ -414,7 +433,7 @@ static void afs_cell_destroy(struct rcu_head *rcu)
ASSERTCMP(atomic_read(&cell->usage), ==, 0); ASSERTCMP(atomic_read(&cell->usage), ==, 0);
afs_put_addrlist(rcu_access_pointer(cell->vl_addrs)); afs_put_vlserverlist(cell->net, rcu_access_pointer(cell->vl_servers));
key_put(cell->anonymous_key); key_put(cell->anonymous_key);
kfree(cell); kfree(cell);

View File

@ -16,6 +16,7 @@
#include <linux/ip.h> #include <linux/ip.h>
#include "internal.h" #include "internal.h"
#include "afs_cm.h" #include "afs_cm.h"
#include "protocol_yfs.h"
static int afs_deliver_cb_init_call_back_state(struct afs_call *); static int afs_deliver_cb_init_call_back_state(struct afs_call *);
static int afs_deliver_cb_init_call_back_state3(struct afs_call *); static int afs_deliver_cb_init_call_back_state3(struct afs_call *);
@ -30,6 +31,8 @@ static void SRXAFSCB_Probe(struct work_struct *);
static void SRXAFSCB_ProbeUuid(struct work_struct *); static void SRXAFSCB_ProbeUuid(struct work_struct *);
static void SRXAFSCB_TellMeAboutYourself(struct work_struct *); static void SRXAFSCB_TellMeAboutYourself(struct work_struct *);
static int afs_deliver_yfs_cb_callback(struct afs_call *);
#define CM_NAME(name) \ #define CM_NAME(name) \
const char afs_SRXCB##name##_name[] __tracepoint_string = \ const char afs_SRXCB##name##_name[] __tracepoint_string = \
"CB." #name "CB." #name
@ -100,13 +103,26 @@ static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
.work = SRXAFSCB_TellMeAboutYourself, .work = SRXAFSCB_TellMeAboutYourself,
}; };
/*
* YFS CB.CallBack operation type
*/
static CM_NAME(YFS_CallBack);
static const struct afs_call_type afs_SRXYFSCB_CallBack = {
.name = afs_SRXCBYFS_CallBack_name,
.deliver = afs_deliver_yfs_cb_callback,
.destructor = afs_cm_destructor,
.work = SRXAFSCB_CallBack,
};
/* /*
* route an incoming cache manager call * route an incoming cache manager call
* - return T if supported, F if not * - return T if supported, F if not
*/ */
bool afs_cm_incoming_call(struct afs_call *call) bool afs_cm_incoming_call(struct afs_call *call)
{ {
_enter("{CB.OP %u}", call->operation_ID); _enter("{%u, CB.OP %u}", call->service_id, call->operation_ID);
call->epoch = rxrpc_kernel_get_epoch(call->net->socket, call->rxcall);
switch (call->operation_ID) { switch (call->operation_ID) {
case CBCallBack: case CBCallBack:
@ -127,11 +143,101 @@ bool afs_cm_incoming_call(struct afs_call *call)
case CBTellMeAboutYourself: case CBTellMeAboutYourself:
call->type = &afs_SRXCBTellMeAboutYourself; call->type = &afs_SRXCBTellMeAboutYourself;
return true; return true;
case YFSCBCallBack:
if (call->service_id != YFS_CM_SERVICE)
return false;
call->type = &afs_SRXYFSCB_CallBack;
return true;
default: default:
return false; return false;
} }
} }
/*
* Record a probe to the cache manager from a server.
*/
static int afs_record_cm_probe(struct afs_call *call, struct afs_server *server)
{
_enter("");
if (test_bit(AFS_SERVER_FL_HAVE_EPOCH, &server->flags) &&
!test_bit(AFS_SERVER_FL_PROBING, &server->flags)) {
if (server->cm_epoch == call->epoch)
return 0;
if (!server->probe.said_rebooted) {
pr_notice("kAFS: FS rebooted %pU\n", &server->uuid);
server->probe.said_rebooted = true;
}
}
spin_lock(&server->probe_lock);
if (!test_bit(AFS_SERVER_FL_HAVE_EPOCH, &server->flags)) {
server->cm_epoch = call->epoch;
server->probe.cm_epoch = call->epoch;
goto out;
}
if (server->probe.cm_probed &&
call->epoch != server->probe.cm_epoch &&
!server->probe.said_inconsistent) {
pr_notice("kAFS: FS endpoints inconsistent %pU\n",
&server->uuid);
server->probe.said_inconsistent = true;
}
if (!server->probe.cm_probed || call->epoch == server->cm_epoch)
server->probe.cm_epoch = server->cm_epoch;
out:
server->probe.cm_probed = true;
spin_unlock(&server->probe_lock);
return 0;
}
/*
* Find the server record by peer address and record a probe to the cache
* manager from a server.
*/
static int afs_find_cm_server_by_peer(struct afs_call *call)
{
struct sockaddr_rxrpc srx;
struct afs_server *server;
rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
server = afs_find_server(call->net, &srx);
if (!server) {
trace_afs_cm_no_server(call, &srx);
return 0;
}
call->cm_server = server;
return afs_record_cm_probe(call, server);
}
/*
* Find the server record by server UUID and record a probe to the cache
* manager from a server.
*/
static int afs_find_cm_server_by_uuid(struct afs_call *call,
struct afs_uuid *uuid)
{
struct afs_server *server;
rcu_read_lock();
server = afs_find_server_by_uuid(call->net, call->request);
rcu_read_unlock();
if (!server) {
trace_afs_cm_no_server_u(call, call->request);
return 0;
}
call->cm_server = server;
return afs_record_cm_probe(call, server);
}
/* /*
* Clean up a cache manager call. * Clean up a cache manager call.
*/ */
@ -168,7 +274,6 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
static int afs_deliver_cb_callback(struct afs_call *call) static int afs_deliver_cb_callback(struct afs_call *call)
{ {
struct afs_callback_break *cb; struct afs_callback_break *cb;
struct sockaddr_rxrpc srx;
__be32 *bp; __be32 *bp;
int ret, loop; int ret, loop;
@ -176,32 +281,32 @@ static int afs_deliver_cb_callback(struct afs_call *call)
switch (call->unmarshall) { switch (call->unmarshall) {
case 0: case 0:
call->offset = 0; afs_extract_to_tmp(call);
call->unmarshall++; call->unmarshall++;
/* extract the FID array and its count in two steps */ /* extract the FID array and its count in two steps */
case 1: case 1:
_debug("extract FID count"); _debug("extract FID count");
ret = afs_extract_data(call, &call->tmp, 4, true); ret = afs_extract_data(call, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
call->count = ntohl(call->tmp); call->count = ntohl(call->tmp);
_debug("FID count: %u", call->count); _debug("FID count: %u", call->count);
if (call->count > AFSCBMAX) if (call->count > AFSCBMAX)
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_cb_fid_count);
call->buffer = kmalloc(array3_size(call->count, 3, 4), call->buffer = kmalloc(array3_size(call->count, 3, 4),
GFP_KERNEL); GFP_KERNEL);
if (!call->buffer) if (!call->buffer)
return -ENOMEM; return -ENOMEM;
call->offset = 0; afs_extract_to_buf(call, call->count * 3 * 4);
call->unmarshall++; call->unmarshall++;
case 2: case 2:
_debug("extract FID array"); _debug("extract FID array");
ret = afs_extract_data(call, call->buffer, ret = afs_extract_data(call, true);
call->count * 3 * 4, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -218,59 +323,46 @@ static int afs_deliver_cb_callback(struct afs_call *call)
cb->fid.vid = ntohl(*bp++); cb->fid.vid = ntohl(*bp++);
cb->fid.vnode = ntohl(*bp++); cb->fid.vnode = ntohl(*bp++);
cb->fid.unique = ntohl(*bp++); cb->fid.unique = ntohl(*bp++);
cb->cb.type = AFSCM_CB_UNTYPED;
} }
call->offset = 0; afs_extract_to_tmp(call);
call->unmarshall++; call->unmarshall++;
/* extract the callback array and its count in two steps */ /* extract the callback array and its count in two steps */
case 3: case 3:
_debug("extract CB count"); _debug("extract CB count");
ret = afs_extract_data(call, &call->tmp, 4, true); ret = afs_extract_data(call, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
call->count2 = ntohl(call->tmp); call->count2 = ntohl(call->tmp);
_debug("CB count: %u", call->count2); _debug("CB count: %u", call->count2);
if (call->count2 != call->count && call->count2 != 0) if (call->count2 != call->count && call->count2 != 0)
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
call->offset = 0; afs_eproto_cb_count);
call->_iter = &call->iter;
iov_iter_discard(&call->iter, READ, call->count2 * 3 * 4);
call->unmarshall++; call->unmarshall++;
case 4: case 4:
_debug("extract CB array"); _debug("extract discard %zu/%u",
ret = afs_extract_data(call, call->buffer, iov_iter_count(&call->iter), call->count2 * 3 * 4);
call->count2 * 3 * 4, false);
ret = afs_extract_data(call, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
_debug("unmarshall CB array");
cb = call->request;
bp = call->buffer;
for (loop = call->count2; loop > 0; loop--, cb++) {
cb->cb.version = ntohl(*bp++);
cb->cb.expiry = ntohl(*bp++);
cb->cb.type = ntohl(*bp++);
}
call->offset = 0;
call->unmarshall++; call->unmarshall++;
case 5: case 5:
break; break;
} }
if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
return -EIO; return afs_io_error(call, afs_io_error_cm_reply);
/* we'll need the file server record as that tells us which set of /* we'll need the file server record as that tells us which set of
* vnodes to operate upon */ * vnodes to operate upon */
rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); return afs_find_cm_server_by_peer(call);
call->cm_server = afs_find_server(call->net, &srx);
if (!call->cm_server)
trace_afs_cm_no_server(call, &srx);
return afs_queue_call_work(call);
} }
/* /*
@ -294,24 +386,18 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work)
*/ */
static int afs_deliver_cb_init_call_back_state(struct afs_call *call) static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
{ {
struct sockaddr_rxrpc srx;
int ret; int ret;
_enter(""); _enter("");
rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); afs_extract_discard(call, 0);
ret = afs_extract_data(call, false);
ret = afs_extract_data(call, NULL, 0, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* we'll need the file server record as that tells us which set of /* we'll need the file server record as that tells us which set of
* vnodes to operate upon */ * vnodes to operate upon */
call->cm_server = afs_find_server(call->net, &srx); return afs_find_cm_server_by_peer(call);
if (!call->cm_server)
trace_afs_cm_no_server(call, &srx);
return afs_queue_call_work(call);
} }
/* /*
@ -330,16 +416,15 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
switch (call->unmarshall) { switch (call->unmarshall) {
case 0: case 0:
call->offset = 0;
call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL); call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL);
if (!call->buffer) if (!call->buffer)
return -ENOMEM; return -ENOMEM;
afs_extract_to_buf(call, 11 * sizeof(__be32));
call->unmarshall++; call->unmarshall++;
case 1: case 1:
_debug("extract UUID"); _debug("extract UUID");
ret = afs_extract_data(call, call->buffer, ret = afs_extract_data(call, false);
11 * sizeof(__be32), false);
switch (ret) { switch (ret) {
case 0: break; case 0: break;
case -EAGAIN: return 0; case -EAGAIN: return 0;
@ -362,7 +447,6 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
for (loop = 0; loop < 6; loop++) for (loop = 0; loop < 6; loop++)
r->node[loop] = ntohl(b[loop + 5]); r->node[loop] = ntohl(b[loop + 5]);
call->offset = 0;
call->unmarshall++; call->unmarshall++;
case 2: case 2:
@ -370,17 +454,11 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
} }
if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
return -EIO; return afs_io_error(call, afs_io_error_cm_reply);
/* we'll need the file server record as that tells us which set of /* we'll need the file server record as that tells us which set of
* vnodes to operate upon */ * vnodes to operate upon */
rcu_read_lock(); return afs_find_cm_server_by_uuid(call, call->request);
call->cm_server = afs_find_server_by_uuid(call->net, call->request);
rcu_read_unlock();
if (!call->cm_server)
trace_afs_cm_no_server_u(call, call->request);
return afs_queue_call_work(call);
} }
/* /*
@ -405,14 +483,14 @@ static int afs_deliver_cb_probe(struct afs_call *call)
_enter(""); _enter("");
ret = afs_extract_data(call, NULL, 0, false); afs_extract_discard(call, 0);
ret = afs_extract_data(call, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
return -EIO; return afs_io_error(call, afs_io_error_cm_reply);
return afs_find_cm_server_by_peer(call);
return afs_queue_call_work(call);
} }
/* /*
@ -453,16 +531,15 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
switch (call->unmarshall) { switch (call->unmarshall) {
case 0: case 0:
call->offset = 0;
call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL); call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL);
if (!call->buffer) if (!call->buffer)
return -ENOMEM; return -ENOMEM;
afs_extract_to_buf(call, 11 * sizeof(__be32));
call->unmarshall++; call->unmarshall++;
case 1: case 1:
_debug("extract UUID"); _debug("extract UUID");
ret = afs_extract_data(call, call->buffer, ret = afs_extract_data(call, false);
11 * sizeof(__be32), false);
switch (ret) { switch (ret) {
case 0: break; case 0: break;
case -EAGAIN: return 0; case -EAGAIN: return 0;
@ -485,7 +562,6 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
for (loop = 0; loop < 6; loop++) for (loop = 0; loop < 6; loop++)
r->node[loop] = ntohl(b[loop + 5]); r->node[loop] = ntohl(b[loop + 5]);
call->offset = 0;
call->unmarshall++; call->unmarshall++;
case 2: case 2:
@ -493,9 +569,8 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
} }
if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
return -EIO; return afs_io_error(call, afs_io_error_cm_reply);
return afs_find_cm_server_by_uuid(call, call->request);
return afs_queue_call_work(call);
} }
/* /*
@ -570,12 +645,88 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call)
_enter(""); _enter("");
ret = afs_extract_data(call, NULL, 0, false); afs_extract_discard(call, 0);
ret = afs_extract_data(call, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
return -EIO; return afs_io_error(call, afs_io_error_cm_reply);
return afs_find_cm_server_by_peer(call);
return afs_queue_call_work(call); }
/*
* deliver request data to a YFS CB.CallBack call
*/
static int afs_deliver_yfs_cb_callback(struct afs_call *call)
{
struct afs_callback_break *cb;
struct yfs_xdr_YFSFid *bp;
size_t size;
int ret, loop;
_enter("{%u}", call->unmarshall);
switch (call->unmarshall) {
case 0:
afs_extract_to_tmp(call);
call->unmarshall++;
/* extract the FID array and its count in two steps */
case 1:
_debug("extract FID count");
ret = afs_extract_data(call, true);
if (ret < 0)
return ret;
call->count = ntohl(call->tmp);
_debug("FID count: %u", call->count);
if (call->count > YFSCBMAX)
return afs_protocol_error(call, -EBADMSG,
afs_eproto_cb_fid_count);
size = array_size(call->count, sizeof(struct yfs_xdr_YFSFid));
call->buffer = kmalloc(size, GFP_KERNEL);
if (!call->buffer)
return -ENOMEM;
afs_extract_to_buf(call, size);
call->unmarshall++;
case 2:
_debug("extract FID array");
ret = afs_extract_data(call, false);
if (ret < 0)
return ret;
_debug("unmarshall FID array");
call->request = kcalloc(call->count,
sizeof(struct afs_callback_break),
GFP_KERNEL);
if (!call->request)
return -ENOMEM;
cb = call->request;
bp = call->buffer;
for (loop = call->count; loop > 0; loop--, cb++) {
cb->fid.vid = xdr_to_u64(bp->volume);
cb->fid.vnode = xdr_to_u64(bp->vnode.lo);
cb->fid.vnode_hi = ntohl(bp->vnode.hi);
cb->fid.unique = ntohl(bp->vnode.unique);
bp++;
}
afs_extract_to_tmp(call);
call->unmarshall++;
case 3:
break;
}
if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
return afs_io_error(call, afs_io_error_cm_reply);
/* We'll need the file server record as that tells us which set of
* vnodes to operate upon.
*/
return afs_find_cm_server_by_peer(call);
} }

View File

@ -138,6 +138,7 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page,
ntohs(dbuf->blocks[tmp].hdr.magic)); ntohs(dbuf->blocks[tmp].hdr.magic));
trace_afs_dir_check_failed(dvnode, off, i_size); trace_afs_dir_check_failed(dvnode, off, i_size);
kunmap(page); kunmap(page);
trace_afs_file_error(dvnode, -EIO, afs_file_error_dir_bad_magic);
goto error; goto error;
} }
@ -190,9 +191,11 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
retry: retry:
i_size = i_size_read(&dvnode->vfs_inode); i_size = i_size_read(&dvnode->vfs_inode);
if (i_size < 2048) if (i_size < 2048)
return ERR_PTR(-EIO); return ERR_PTR(afs_bad(dvnode, afs_file_error_dir_small));
if (i_size > 2048 * 1024) if (i_size > 2048 * 1024) {
trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big);
return ERR_PTR(-EFBIG); return ERR_PTR(-EFBIG);
}
_enter("%llu", i_size); _enter("%llu", i_size);
@ -315,7 +318,8 @@ content_has_grown:
/* /*
* deal with one block in an AFS directory * deal with one block in an AFS directory
*/ */
static int afs_dir_iterate_block(struct dir_context *ctx, static int afs_dir_iterate_block(struct afs_vnode *dvnode,
struct dir_context *ctx,
union afs_xdr_dir_block *block, union afs_xdr_dir_block *block,
unsigned blkoff) unsigned blkoff)
{ {
@ -365,7 +369,7 @@ static int afs_dir_iterate_block(struct dir_context *ctx,
" (len %u/%zu)", " (len %u/%zu)",
blkoff / sizeof(union afs_xdr_dir_block), blkoff / sizeof(union afs_xdr_dir_block),
offset, next, tmp, nlen); offset, next, tmp, nlen);
return -EIO; return afs_bad(dvnode, afs_file_error_dir_over_end);
} }
if (!(block->hdr.bitmap[next / 8] & if (!(block->hdr.bitmap[next / 8] &
(1 << (next % 8)))) { (1 << (next % 8)))) {
@ -373,7 +377,7 @@ static int afs_dir_iterate_block(struct dir_context *ctx,
" %u unmarked extension (len %u/%zu)", " %u unmarked extension (len %u/%zu)",
blkoff / sizeof(union afs_xdr_dir_block), blkoff / sizeof(union afs_xdr_dir_block),
offset, next, tmp, nlen); offset, next, tmp, nlen);
return -EIO; return afs_bad(dvnode, afs_file_error_dir_unmarked_ext);
} }
_debug("ENT[%zu.%u]: ext %u/%zu", _debug("ENT[%zu.%u]: ext %u/%zu",
@ -442,7 +446,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
*/ */
page = req->pages[blkoff / PAGE_SIZE]; page = req->pages[blkoff / PAGE_SIZE];
if (!page) { if (!page) {
ret = -EIO; ret = afs_bad(dvnode, afs_file_error_dir_missing_page);
break; break;
} }
mark_page_accessed(page); mark_page_accessed(page);
@ -455,7 +459,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
do { do {
dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) / dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
sizeof(union afs_xdr_dir_block)]; sizeof(union afs_xdr_dir_block)];
ret = afs_dir_iterate_block(ctx, dblock, blkoff); ret = afs_dir_iterate_block(dvnode, ctx, dblock, blkoff);
if (ret != 1) { if (ret != 1) {
kunmap(page); kunmap(page);
goto out; goto out;
@ -548,7 +552,7 @@ static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry,
} }
*fid = cookie.fid; *fid = cookie.fid;
_leave(" = 0 { vn=%u u=%u }", fid->vnode, fid->unique); _leave(" = 0 { vn=%llu u=%u }", fid->vnode, fid->unique);
return 0; return 0;
} }
@ -826,7 +830,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
struct key *key; struct key *key;
int ret; int ret;
_enter("{%x:%u},%p{%pd},", _enter("{%llx:%llu},%p{%pd},",
dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry); dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry);
ASSERTCMP(d_inode(dentry), ==, NULL); ASSERTCMP(d_inode(dentry), ==, NULL);
@ -896,7 +900,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
if (d_really_is_positive(dentry)) { if (d_really_is_positive(dentry)) {
vnode = AFS_FS_I(d_inode(dentry)); vnode = AFS_FS_I(d_inode(dentry));
_enter("{v={%x:%u} n=%pd fl=%lx},", _enter("{v={%llx:%llu} n=%pd fl=%lx},",
vnode->fid.vid, vnode->fid.vnode, dentry, vnode->fid.vid, vnode->fid.vnode, dentry,
vnode->flags); vnode->flags);
} else { } else {
@ -965,7 +969,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
/* if the vnode ID has changed, then the dirent points to a /* if the vnode ID has changed, then the dirent points to a
* different file */ * different file */
if (fid.vnode != vnode->fid.vnode) { if (fid.vnode != vnode->fid.vnode) {
_debug("%pd: dirent changed [%u != %u]", _debug("%pd: dirent changed [%llu != %llu]",
dentry, fid.vnode, dentry, fid.vnode,
vnode->fid.vnode); vnode->fid.vnode);
goto not_found; goto not_found;
@ -1085,6 +1089,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
vnode = AFS_FS_I(inode); vnode = AFS_FS_I(inode);
set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
afs_vnode_commit_status(fc, vnode, 0);
d_add(new_dentry, inode); d_add(new_dentry, inode);
} }
@ -1104,7 +1109,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
mode |= S_IFDIR; mode |= S_IFDIR;
_enter("{%x:%u},{%pd},%ho", _enter("{%llx:%llu},{%pd},%ho",
dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
key = afs_request_key(dvnode->volume->cell); key = afs_request_key(dvnode->volume->cell);
@ -1169,12 +1174,12 @@ static void afs_dir_remove_subdir(struct dentry *dentry)
static int afs_rmdir(struct inode *dir, struct dentry *dentry) static int afs_rmdir(struct inode *dir, struct dentry *dentry)
{ {
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
struct key *key; struct key *key;
u64 data_version = dvnode->status.data_version; u64 data_version = dvnode->status.data_version;
int ret; int ret;
_enter("{%x:%u},{%pd}", _enter("{%llx:%llu},{%pd}",
dvnode->fid.vid, dvnode->fid.vnode, dentry); dvnode->fid.vid, dvnode->fid.vnode, dentry);
key = afs_request_key(dvnode->volume->cell); key = afs_request_key(dvnode->volume->cell);
@ -1183,11 +1188,19 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
goto error; goto error;
} }
/* Try to make sure we have a callback promise on the victim. */
if (d_really_is_positive(dentry)) {
vnode = AFS_FS_I(d_inode(dentry));
ret = afs_validate(vnode, key);
if (ret < 0)
goto error_key;
}
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_remove(&fc, dentry->d_name.name, true, afs_fs_remove(&fc, vnode, dentry->d_name.name, true,
data_version); data_version);
} }
@ -1201,6 +1214,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
} }
} }
error_key:
key_put(key); key_put(key);
error: error:
return ret; return ret;
@ -1231,7 +1245,9 @@ static int afs_dir_remove_link(struct dentry *dentry, struct key *key,
if (d_really_is_positive(dentry)) { if (d_really_is_positive(dentry)) {
struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
if (dir_valid) { if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
/* Already done */
} else if (dir_valid) {
drop_nlink(&vnode->vfs_inode); drop_nlink(&vnode->vfs_inode);
if (vnode->vfs_inode.i_nlink == 0) { if (vnode->vfs_inode.i_nlink == 0) {
set_bit(AFS_VNODE_DELETED, &vnode->flags); set_bit(AFS_VNODE_DELETED, &vnode->flags);
@ -1260,13 +1276,13 @@ static int afs_dir_remove_link(struct dentry *dentry, struct key *key,
static int afs_unlink(struct inode *dir, struct dentry *dentry) static int afs_unlink(struct inode *dir, struct dentry *dentry)
{ {
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
struct key *key; struct key *key;
unsigned long d_version = (unsigned long)dentry->d_fsdata; unsigned long d_version = (unsigned long)dentry->d_fsdata;
u64 data_version = dvnode->status.data_version; u64 data_version = dvnode->status.data_version;
int ret; int ret;
_enter("{%x:%u},{%pd}", _enter("{%llx:%llu},{%pd}",
dvnode->fid.vid, dvnode->fid.vnode, dentry); dvnode->fid.vid, dvnode->fid.vnode, dentry);
if (dentry->d_name.len >= AFSNAMEMAX) if (dentry->d_name.len >= AFSNAMEMAX)
@ -1290,7 +1306,18 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_remove(&fc, dentry->d_name.name, false,
if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) &&
!test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) {
yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name,
data_version);
if (fc.ac.error != -ECONNABORTED ||
fc.ac.abort_code != RXGEN_OPCODE)
continue;
set_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags);
}
afs_fs_remove(&fc, vnode, dentry->d_name.name, false,
data_version); data_version);
} }
@ -1330,7 +1357,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
mode |= S_IFREG; mode |= S_IFREG;
_enter("{%x:%u},{%pd},%ho,", _enter("{%llx:%llu},{%pd},%ho,",
dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
ret = -ENAMETOOLONG; ret = -ENAMETOOLONG;
@ -1393,7 +1420,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
dvnode = AFS_FS_I(dir); dvnode = AFS_FS_I(dir);
data_version = dvnode->status.data_version; data_version = dvnode->status.data_version;
_enter("{%x:%u},{%x:%u},{%pd}", _enter("{%llx:%llu},{%llx:%llu},{%pd}",
vnode->fid.vid, vnode->fid.vnode, vnode->fid.vid, vnode->fid.vnode,
dvnode->fid.vid, dvnode->fid.vnode, dvnode->fid.vid, dvnode->fid.vnode,
dentry); dentry);
@ -1464,7 +1491,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
u64 data_version = dvnode->status.data_version; u64 data_version = dvnode->status.data_version;
int ret; int ret;
_enter("{%x:%u},{%pd},%s", _enter("{%llx:%llu},{%pd},%s",
dvnode->fid.vid, dvnode->fid.vnode, dentry, dvnode->fid.vid, dvnode->fid.vnode, dentry,
content); content);
@ -1540,7 +1567,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
orig_data_version = orig_dvnode->status.data_version; orig_data_version = orig_dvnode->status.data_version;
new_data_version = new_dvnode->status.data_version; new_data_version = new_dvnode->status.data_version;
_enter("{%x:%u},{%x:%u},{%x:%u},{%pd}", _enter("{%llx:%llu},{%llx:%llu},{%llx:%llu},{%pd}",
orig_dvnode->fid.vid, orig_dvnode->fid.vnode, orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
vnode->fid.vid, vnode->fid.vnode, vnode->fid.vid, vnode->fid.vnode,
new_dvnode->fid.vid, new_dvnode->fid.vnode, new_dvnode->fid.vid, new_dvnode->fid.vnode,
@ -1607,7 +1634,7 @@ static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags)
{ {
struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host); struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host);
_enter("{{%x:%u}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index); _enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index);
set_page_private(page, 0); set_page_private(page, 0);
ClearPagePrivate(page); ClearPagePrivate(page);

View File

@ -46,7 +46,7 @@ static int afs_probe_cell_name(struct dentry *dentry)
return 0; return 0;
} }
ret = dns_query("afsdb", name, len, "", NULL, NULL); ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL);
if (ret == -ENODATA) if (ret == -ENODATA)
ret = -EDESTADDRREQ; ret = -EDESTADDRREQ;
return ret; return ret;
@ -62,7 +62,7 @@ struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
struct inode *inode; struct inode *inode;
int ret = -ENOENT; int ret = -ENOENT;
_enter("%p{%pd}, {%x:%u}", _enter("%p{%pd}, {%llx:%llu}",
dentry, dentry, vnode->fid.vid, vnode->fid.vnode); dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))

View File

@ -121,7 +121,7 @@ int afs_open(struct inode *inode, struct file *file)
struct key *key; struct key *key;
int ret; int ret;
_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode);
key = afs_request_key(vnode->volume->cell); key = afs_request_key(vnode->volume->cell);
if (IS_ERR(key)) { if (IS_ERR(key)) {
@ -170,7 +170,7 @@ int afs_release(struct inode *inode, struct file *file)
struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_vnode *vnode = AFS_FS_I(inode);
struct afs_file *af = file->private_data; struct afs_file *af = file->private_data;
_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode);
if ((file->f_mode & FMODE_WRITE)) if ((file->f_mode & FMODE_WRITE))
return vfs_fsync(file, 0); return vfs_fsync(file, 0);
@ -228,7 +228,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
int ret; int ret;
_enter("%s{%x:%u.%u},%x,,,", _enter("%s{%llx:%llu.%u},%x,,,",
vnode->volume->name, vnode->volume->name,
vnode->fid.vid, vnode->fid.vid,
vnode->fid.vnode, vnode->fid.vnode,
@ -634,7 +634,7 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
unsigned long priv; unsigned long priv;
_enter("{{%x:%u}[%lu],%lx},%x", _enter("{{%llx:%llu}[%lu],%lx},%x",
vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
gfp_flags); gfp_flags);

View File

@ -29,7 +29,7 @@ static const struct file_lock_operations afs_lock_ops = {
*/ */
void afs_lock_may_be_available(struct afs_vnode *vnode) void afs_lock_may_be_available(struct afs_vnode *vnode)
{ {
_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0); queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0);
} }
@ -76,7 +76,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
int ret; int ret;
_enter("%s{%x:%u.%u},%x,%u", _enter("%s{%llx:%llu.%u},%x,%u",
vnode->volume->name, vnode->volume->name,
vnode->fid.vid, vnode->fid.vid,
vnode->fid.vnode, vnode->fid.vnode,
@ -107,7 +107,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key)
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
int ret; int ret;
_enter("%s{%x:%u.%u},%x", _enter("%s{%llx:%llu.%u},%x",
vnode->volume->name, vnode->volume->name,
vnode->fid.vid, vnode->fid.vid,
vnode->fid.vnode, vnode->fid.vnode,
@ -138,7 +138,7 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key)
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
int ret; int ret;
_enter("%s{%x:%u.%u},%x", _enter("%s{%llx:%llu.%u},%x",
vnode->volume->name, vnode->volume->name,
vnode->fid.vid, vnode->fid.vid,
vnode->fid.vnode, vnode->fid.vnode,
@ -175,7 +175,7 @@ void afs_lock_work(struct work_struct *work)
struct key *key; struct key *key;
int ret; int ret;
_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
spin_lock(&vnode->lock); spin_lock(&vnode->lock);
@ -192,7 +192,7 @@ again:
ret = afs_release_lock(vnode, vnode->lock_key); ret = afs_release_lock(vnode, vnode->lock_key);
if (ret < 0) if (ret < 0)
printk(KERN_WARNING "AFS:" printk(KERN_WARNING "AFS:"
" Failed to release lock on {%x:%x} error %d\n", " Failed to release lock on {%llx:%llx} error %d\n",
vnode->fid.vid, vnode->fid.vnode, ret); vnode->fid.vid, vnode->fid.vnode, ret);
spin_lock(&vnode->lock); spin_lock(&vnode->lock);
@ -229,7 +229,7 @@ again:
key_put(key); key_put(key);
if (ret < 0) if (ret < 0)
pr_warning("AFS: Failed to extend lock on {%x:%x} error %d\n", pr_warning("AFS: Failed to extend lock on {%llx:%llx} error %d\n",
vnode->fid.vid, vnode->fid.vnode, ret); vnode->fid.vid, vnode->fid.vnode, ret);
spin_lock(&vnode->lock); spin_lock(&vnode->lock);
@ -430,7 +430,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
struct key *key = afs_file_key(file); struct key *key = afs_file_key(file);
int ret; int ret;
_enter("{%x:%u},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type); _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
/* only whole-file locks are supported */ /* only whole-file locks are supported */
if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX) if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
@ -582,7 +582,7 @@ static int afs_do_unlk(struct file *file, struct file_lock *fl)
struct afs_vnode *vnode = AFS_FS_I(locks_inode(file)); struct afs_vnode *vnode = AFS_FS_I(locks_inode(file));
int ret; int ret;
_enter("{%x:%u},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type); _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
/* Flush all pending writes before doing anything with locks. */ /* Flush all pending writes before doing anything with locks. */
vfs_fsync(file, 0); vfs_fsync(file, 0);
@ -639,7 +639,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl)
{ {
struct afs_vnode *vnode = AFS_FS_I(locks_inode(file)); struct afs_vnode *vnode = AFS_FS_I(locks_inode(file));
_enter("{%x:%u},%d,{t=%x,fl=%x,r=%Ld:%Ld}", _enter("{%llx:%llu},%d,{t=%x,fl=%x,r=%Ld:%Ld}",
vnode->fid.vid, vnode->fid.vnode, cmd, vnode->fid.vid, vnode->fid.vnode, cmd,
fl->fl_type, fl->fl_flags, fl->fl_type, fl->fl_flags,
(long long) fl->fl_start, (long long) fl->fl_end); (long long) fl->fl_start, (long long) fl->fl_end);
@ -662,7 +662,7 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl)
{ {
struct afs_vnode *vnode = AFS_FS_I(locks_inode(file)); struct afs_vnode *vnode = AFS_FS_I(locks_inode(file));
_enter("{%x:%u},%d,{t=%x,fl=%x}", _enter("{%llx:%llu},%d,{t=%x,fl=%x}",
vnode->fid.vid, vnode->fid.vnode, cmd, vnode->fid.vid, vnode->fid.vnode, cmd,
fl->fl_type, fl->fl_flags); fl->fl_type, fl->fl_flags);

270
fs/afs/fs_probe.c Normal file
View File

@ -0,0 +1,270 @@
/* AFS fileserver probing
*
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/sched.h>
#include <linux/slab.h>
#include "afs_fs.h"
#include "internal.h"
#include "protocol_yfs.h"
static bool afs_fs_probe_done(struct afs_server *server)
{
if (!atomic_dec_and_test(&server->probe_outstanding))
return false;
wake_up_var(&server->probe_outstanding);
clear_bit_unlock(AFS_SERVER_FL_PROBING, &server->flags);
wake_up_bit(&server->flags, AFS_SERVER_FL_PROBING);
return true;
}
/*
* Process the result of probing a fileserver. This is called after successful
* or failed delivery of an FS.GetCapabilities operation.
*/
void afs_fileserver_probe_result(struct afs_call *call)
{
struct afs_addr_list *alist = call->alist;
struct afs_server *server = call->reply[0];
unsigned int server_index = (long)call->reply[1];
unsigned int index = call->addr_ix;
unsigned int rtt = UINT_MAX;
bool have_result = false;
u64 _rtt;
int ret = call->error;
_enter("%pU,%u", &server->uuid, index);
spin_lock(&server->probe_lock);
switch (ret) {
case 0:
server->probe.error = 0;
goto responded;
case -ECONNABORTED:
if (!server->probe.responded) {
server->probe.abort_code = call->abort_code;
server->probe.error = ret;
}
goto responded;
case -ENOMEM:
case -ENONET:
server->probe.local_failure = true;
afs_io_error(call, afs_io_error_fs_probe_fail);
goto out;
case -ECONNRESET: /* Responded, but call expired. */
case -ENETUNREACH:
case -EHOSTUNREACH:
case -ECONNREFUSED:
case -ETIMEDOUT:
case -ETIME:
default:
clear_bit(index, &alist->responded);
set_bit(index, &alist->failed);
if (!server->probe.responded &&
(server->probe.error == 0 ||
server->probe.error == -ETIMEDOUT ||
server->probe.error == -ETIME))
server->probe.error = ret;
afs_io_error(call, afs_io_error_fs_probe_fail);
goto out;
}
responded:
set_bit(index, &alist->responded);
clear_bit(index, &alist->failed);
if (call->service_id == YFS_FS_SERVICE) {
server->probe.is_yfs = true;
set_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
alist->addrs[index].srx_service = call->service_id;
} else {
server->probe.not_yfs = true;
if (!server->probe.is_yfs) {
clear_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
alist->addrs[index].srx_service = call->service_id;
}
}
/* Get the RTT and scale it to fit into a 32-bit value that represents
* over a minute of time so that we can access it with one instruction
* on a 32-bit system.
*/
_rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall);
_rtt /= 64;
rtt = (_rtt > UINT_MAX) ? UINT_MAX : _rtt;
if (rtt < server->probe.rtt) {
server->probe.rtt = rtt;
alist->preferred = index;
have_result = true;
}
smp_wmb(); /* Set rtt before responded. */
server->probe.responded = true;
set_bit(AFS_SERVER_FL_PROBED, &server->flags);
out:
spin_unlock(&server->probe_lock);
_debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
server_index, index, &alist->addrs[index].transport,
(unsigned int)rtt, ret);
have_result |= afs_fs_probe_done(server);
if (have_result) {
server->probe.have_result = true;
wake_up_var(&server->probe.have_result);
wake_up_all(&server->probe_wq);
}
}
/*
* Probe all of a fileserver's addresses to find out the best route and to
* query its capabilities.
*/
static int afs_do_probe_fileserver(struct afs_net *net,
struct afs_server *server,
struct key *key,
unsigned int server_index)
{
struct afs_addr_cursor ac = {
.index = 0,
};
int ret;
_enter("%pU", &server->uuid);
read_lock(&server->fs_lock);
ac.alist = rcu_dereference_protected(server->addresses,
lockdep_is_held(&server->fs_lock));
read_unlock(&server->fs_lock);
atomic_set(&server->probe_outstanding, ac.alist->nr_addrs);
memset(&server->probe, 0, sizeof(server->probe));
server->probe.rtt = UINT_MAX;
for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) {
ret = afs_fs_get_capabilities(net, server, &ac, key, server_index,
true);
if (ret != -EINPROGRESS) {
afs_fs_probe_done(server);
return ret;
}
}
return 0;
}
/*
* Send off probes to all unprobed servers.
*/
int afs_probe_fileservers(struct afs_net *net, struct key *key,
struct afs_server_list *list)
{
struct afs_server *server;
int i, ret;
for (i = 0; i < list->nr_servers; i++) {
server = list->servers[i].server;
if (test_bit(AFS_SERVER_FL_PROBED, &server->flags))
continue;
if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &server->flags)) {
ret = afs_do_probe_fileserver(net, server, key, i);
if (ret)
return ret;
}
}
return 0;
}
/*
* Wait for the first as-yet untried fileserver to respond.
*/
int afs_wait_for_fs_probes(struct afs_server_list *slist, unsigned long untried)
{
struct wait_queue_entry *waits;
struct afs_server *server;
unsigned int rtt = UINT_MAX;
bool have_responders = false;
int pref = -1, i;
_enter("%u,%lx", slist->nr_servers, untried);
/* Only wait for servers that have a probe outstanding. */
for (i = 0; i < slist->nr_servers; i++) {
if (test_bit(i, &untried)) {
server = slist->servers[i].server;
if (!test_bit(AFS_SERVER_FL_PROBING, &server->flags))
__clear_bit(i, &untried);
if (server->probe.responded)
have_responders = true;
}
}
if (have_responders || !untried)
return 0;
waits = kmalloc(array_size(slist->nr_servers, sizeof(*waits)), GFP_KERNEL);
if (!waits)
return -ENOMEM;
for (i = 0; i < slist->nr_servers; i++) {
if (test_bit(i, &untried)) {
server = slist->servers[i].server;
init_waitqueue_entry(&waits[i], current);
add_wait_queue(&server->probe_wq, &waits[i]);
}
}
for (;;) {
bool still_probing = false;
set_current_state(TASK_INTERRUPTIBLE);
for (i = 0; i < slist->nr_servers; i++) {
if (test_bit(i, &untried)) {
server = slist->servers[i].server;
if (server->probe.responded)
goto stop;
if (test_bit(AFS_SERVER_FL_PROBING, &server->flags))
still_probing = true;
}
}
if (!still_probing || unlikely(signal_pending(current)))
goto stop;
schedule();
}
stop:
set_current_state(TASK_RUNNING);
for (i = 0; i < slist->nr_servers; i++) {
if (test_bit(i, &untried)) {
server = slist->servers[i].server;
if (server->probe.responded &&
server->probe.rtt < rtt) {
pref = i;
rtt = server->probe.rtt;
}
remove_wait_queue(&server->probe_wq, &waits[i]);
}
}
kfree(waits);
if (pref == -1 && signal_pending(current))
return -ERESTARTSYS;
if (pref >= 0)
slist->preferred = pref;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -82,7 +82,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key)
default: default:
printk("kAFS: AFS vnode with undefined type\n"); printk("kAFS: AFS vnode with undefined type\n");
read_sequnlock_excl(&vnode->cb_lock); read_sequnlock_excl(&vnode->cb_lock);
return afs_protocol_error(NULL, -EBADMSG); return afs_protocol_error(NULL, -EBADMSG, afs_eproto_file_type);
} }
inode->i_blocks = 0; inode->i_blocks = 0;
@ -100,7 +100,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
int ret; int ret;
_enter("%s,{%x:%u.%u,S=%lx}", _enter("%s,{%llx:%llu.%u,S=%lx}",
vnode->volume->name, vnode->volume->name,
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique,
vnode->flags); vnode->flags);
@ -127,9 +127,9 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
int afs_iget5_test(struct inode *inode, void *opaque) int afs_iget5_test(struct inode *inode, void *opaque)
{ {
struct afs_iget_data *data = opaque; struct afs_iget_data *data = opaque;
struct afs_vnode *vnode = AFS_FS_I(inode);
return inode->i_ino == data->fid.vnode && return memcmp(&vnode->fid, &data->fid, sizeof(data->fid)) == 0;
inode->i_generation == data->fid.unique;
} }
/* /*
@ -150,11 +150,14 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
struct afs_iget_data *data = opaque; struct afs_iget_data *data = opaque;
struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_vnode *vnode = AFS_FS_I(inode);
inode->i_ino = data->fid.vnode;
inode->i_generation = data->fid.unique;
vnode->fid = data->fid; vnode->fid = data->fid;
vnode->volume = data->volume; vnode->volume = data->volume;
/* YFS supports 96-bit vnode IDs, but Linux only supports
* 64-bit inode numbers.
*/
inode->i_ino = data->fid.vnode;
inode->i_generation = data->fid.unique;
return 0; return 0;
} }
@ -193,7 +196,7 @@ struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
_debug("GOT INODE %p { ino=%lu, vl=%x, vn=%x, u=%x }", _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }",
inode, inode->i_ino, data.fid.vid, data.fid.vnode, inode, inode->i_ino, data.fid.vid, data.fid.vnode,
data.fid.unique); data.fid.unique);
@ -252,8 +255,8 @@ static void afs_get_inode_cache(struct afs_vnode *vnode)
key.vnode_id = vnode->fid.vnode; key.vnode_id = vnode->fid.vnode;
key.unique = vnode->fid.unique; key.unique = vnode->fid.unique;
key.vnode_id_ext[0] = 0; key.vnode_id_ext[0] = vnode->fid.vnode >> 32;
key.vnode_id_ext[1] = 0; key.vnode_id_ext[1] = vnode->fid.vnode_hi;
aux.data_version = vnode->status.data_version; aux.data_version = vnode->status.data_version;
vnode->cache = fscache_acquire_cookie(vnode->volume->cache, vnode->cache = fscache_acquire_cookie(vnode->volume->cache,
@ -277,7 +280,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
struct inode *inode; struct inode *inode;
int ret; int ret;
_enter(",{%x:%u.%u},,", fid->vid, fid->vnode, fid->unique); _enter(",{%llx:%llu.%u},,", fid->vid, fid->vnode, fid->unique);
as = sb->s_fs_info; as = sb->s_fs_info;
data.volume = as->volume; data.volume = as->volume;
@ -289,7 +292,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
_debug("GOT INODE %p { vl=%x vn=%x, u=%x }", _debug("GOT INODE %p { vl=%llx vn=%llx, u=%x }",
inode, fid->vid, fid->vnode, fid->unique); inode, fid->vid, fid->vnode, fid->unique);
vnode = AFS_FS_I(inode); vnode = AFS_FS_I(inode);
@ -314,11 +317,11 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
* didn't give us a callback) */ * didn't give us a callback) */
vnode->cb_version = 0; vnode->cb_version = 0;
vnode->cb_type = 0; vnode->cb_type = 0;
vnode->cb_expires_at = 0; vnode->cb_expires_at = ktime_get();
} else { } else {
vnode->cb_version = cb->version; vnode->cb_version = cb->version;
vnode->cb_type = cb->type; vnode->cb_type = cb->type;
vnode->cb_expires_at = cb->expiry; vnode->cb_expires_at = cb->expires_at;
vnode->cb_interest = afs_get_cb_interest(cbi); vnode->cb_interest = afs_get_cb_interest(cbi);
set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
} }
@ -352,7 +355,7 @@ bad_inode:
*/ */
void afs_zap_data(struct afs_vnode *vnode) void afs_zap_data(struct afs_vnode *vnode)
{ {
_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
#ifdef CONFIG_AFS_FSCACHE #ifdef CONFIG_AFS_FSCACHE
fscache_invalidate(vnode->cache); fscache_invalidate(vnode->cache);
@ -382,7 +385,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
bool valid = false; bool valid = false;
int ret; int ret;
_enter("{v={%x:%u} fl=%lx},%x", _enter("{v={%llx:%llu} fl=%lx},%x",
vnode->fid.vid, vnode->fid.vnode, vnode->flags, vnode->fid.vid, vnode->fid.vnode, vnode->flags,
key_serial(key)); key_serial(key));
@ -501,7 +504,7 @@ void afs_evict_inode(struct inode *inode)
vnode = AFS_FS_I(inode); vnode = AFS_FS_I(inode);
_enter("{%x:%u.%d}", _enter("{%llx:%llu.%d}",
vnode->fid.vid, vnode->fid.vid,
vnode->fid.vnode, vnode->fid.vnode,
vnode->fid.unique); vnode->fid.unique);
@ -550,7 +553,7 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
struct key *key; struct key *key;
int ret; int ret;
_enter("{%x:%u},{n=%pd},%x", _enter("{%llx:%llu},{n=%pd},%x",
vnode->fid.vid, vnode->fid.vnode, dentry, vnode->fid.vid, vnode->fid.vnode, dentry,
attr->ia_valid); attr->ia_valid);

View File

@ -22,6 +22,7 @@
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/uuid.h> #include <linux/uuid.h>
#include <linux/mm_types.h> #include <linux/mm_types.h>
#include <linux/dns_resolver.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
#include <net/sock.h> #include <net/sock.h>
@ -75,10 +76,13 @@ struct afs_addr_list {
u32 version; /* Version */ u32 version; /* Version */
unsigned char max_addrs; unsigned char max_addrs;
unsigned char nr_addrs; unsigned char nr_addrs;
unsigned char index; /* Address currently in use */ unsigned char preferred; /* Preferred address */
unsigned char nr_ipv4; /* Number of IPv4 addresses */ unsigned char nr_ipv4; /* Number of IPv4 addresses */
enum dns_record_source source:8;
enum dns_lookup_status status:8;
unsigned long probed; /* Mask of servers that have been probed */ unsigned long probed; /* Mask of servers that have been probed */
unsigned long yfs; /* Mask of servers that are YFS */ unsigned long failed; /* Mask of addrs that failed locally/ICMP */
unsigned long responded; /* Mask of addrs that responded */
struct sockaddr_rxrpc addrs[]; struct sockaddr_rxrpc addrs[];
#define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8)) #define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8))
}; };
@ -88,6 +92,7 @@ struct afs_addr_list {
*/ */
struct afs_call { struct afs_call {
const struct afs_call_type *type; /* type of call */ const struct afs_call_type *type; /* type of call */
struct afs_addr_list *alist; /* Address is alist[addr_ix] */
wait_queue_head_t waitq; /* processes awaiting completion */ wait_queue_head_t waitq; /* processes awaiting completion */
struct work_struct async_work; /* async I/O processor */ struct work_struct async_work; /* async I/O processor */
struct work_struct work; /* actual work processor */ struct work_struct work; /* actual work processor */
@ -98,16 +103,22 @@ struct afs_call {
struct afs_cb_interest *cbi; /* Callback interest for server used */ struct afs_cb_interest *cbi; /* Callback interest for server used */
void *request; /* request data (first part) */ void *request; /* request data (first part) */
struct address_space *mapping; /* Pages being written from */ struct address_space *mapping; /* Pages being written from */
struct iov_iter iter; /* Buffer iterator */
struct iov_iter *_iter; /* Iterator currently in use */
union { /* Convenience for ->iter */
struct kvec kvec[1];
struct bio_vec bvec[1];
};
void *buffer; /* reply receive buffer */ void *buffer; /* reply receive buffer */
void *reply[4]; /* Where to put the reply */ void *reply[4]; /* Where to put the reply */
pgoff_t first; /* first page in mapping to deal with */ pgoff_t first; /* first page in mapping to deal with */
pgoff_t last; /* last page in mapping to deal with */ pgoff_t last; /* last page in mapping to deal with */
size_t offset; /* offset into received data store */
atomic_t usage; atomic_t usage;
enum afs_call_state state; enum afs_call_state state;
spinlock_t state_lock; spinlock_t state_lock;
int error; /* error code */ int error; /* error code */
u32 abort_code; /* Remote abort ID or 0 */ u32 abort_code; /* Remote abort ID or 0 */
u32 epoch;
unsigned request_size; /* size of request data */ unsigned request_size; /* size of request data */
unsigned reply_max; /* maximum size of reply */ unsigned reply_max; /* maximum size of reply */
unsigned first_offset; /* offset into mapping[first] */ unsigned first_offset; /* offset into mapping[first] */
@ -117,19 +128,28 @@ struct afs_call {
unsigned count2; /* count used in unmarshalling */ unsigned count2; /* count used in unmarshalling */
}; };
unsigned char unmarshall; /* unmarshalling phase */ unsigned char unmarshall; /* unmarshalling phase */
unsigned char addr_ix; /* Address in ->alist */
bool incoming; /* T if incoming call */ bool incoming; /* T if incoming call */
bool send_pages; /* T if data from mapping should be sent */ bool send_pages; /* T if data from mapping should be sent */
bool need_attention; /* T if RxRPC poked us */ bool need_attention; /* T if RxRPC poked us */
bool async; /* T if asynchronous */ bool async; /* T if asynchronous */
bool ret_reply0; /* T if should return reply[0] on success */ bool ret_reply0; /* T if should return reply[0] on success */
bool upgrade; /* T to request service upgrade */ bool upgrade; /* T to request service upgrade */
bool want_reply_time; /* T if want reply_time */
u16 service_id; /* Actual service ID (after upgrade) */ u16 service_id; /* Actual service ID (after upgrade) */
unsigned int debug_id; /* Trace ID */ unsigned int debug_id; /* Trace ID */
u32 operation_ID; /* operation ID for an incoming call */ u32 operation_ID; /* operation ID for an incoming call */
u32 count; /* count for use in unmarshalling */ u32 count; /* count for use in unmarshalling */
__be32 tmp; /* place to extract temporary data */ union { /* place to extract temporary data */
struct {
__be32 tmp_u;
__be32 tmp;
} __attribute__((packed));
__be64 tmp64;
};
afs_dataversion_t expected_version; /* Updated version expected from store */ afs_dataversion_t expected_version; /* Updated version expected from store */
afs_dataversion_t expected_version_2; /* 2nd updated version expected from store */ afs_dataversion_t expected_version_2; /* 2nd updated version expected from store */
ktime_t reply_time; /* Time of first reply packet */
}; };
struct afs_call_type { struct afs_call_type {
@ -146,6 +166,9 @@ struct afs_call_type {
/* Work function */ /* Work function */
void (*work)(struct work_struct *work); void (*work)(struct work_struct *work);
/* Call done function (gets called immediately on success or failure) */
void (*done)(struct afs_call *call);
}; };
/* /*
@ -185,6 +208,7 @@ struct afs_read {
refcount_t usage; refcount_t usage;
unsigned int index; /* Which page we're reading into */ unsigned int index; /* Which page we're reading into */
unsigned int nr_pages; unsigned int nr_pages;
unsigned int offset; /* offset into current page */
void (*page_done)(struct afs_call *, struct afs_read *); void (*page_done)(struct afs_call *, struct afs_read *);
struct page **pages; struct page **pages;
struct page *array[]; struct page *array[];
@ -343,12 +367,69 @@ struct afs_cell {
rwlock_t proc_lock; rwlock_t proc_lock;
/* VL server list. */ /* VL server list. */
rwlock_t vl_addrs_lock; /* Lock on vl_addrs */ rwlock_t vl_servers_lock; /* Lock on vl_servers */
struct afs_addr_list __rcu *vl_addrs; /* List of VL servers */ struct afs_vlserver_list __rcu *vl_servers;
u8 name_len; /* Length of name */ u8 name_len; /* Length of name */
char name[64 + 1]; /* Cell name, case-flattened and NUL-padded */ char name[64 + 1]; /* Cell name, case-flattened and NUL-padded */
}; };
/*
* Volume Location server record.
*/
struct afs_vlserver {
struct rcu_head rcu;
struct afs_addr_list __rcu *addresses; /* List of addresses for this VL server */
unsigned long flags;
#define AFS_VLSERVER_FL_PROBED 0 /* The VL server has been probed */
#define AFS_VLSERVER_FL_PROBING 1 /* VL server is being probed */
#define AFS_VLSERVER_FL_IS_YFS 2 /* Server is YFS not AFS */
rwlock_t lock; /* Lock on addresses */
atomic_t usage;
/* Probe state */
wait_queue_head_t probe_wq;
atomic_t probe_outstanding;
spinlock_t probe_lock;
struct {
unsigned int rtt; /* RTT as ktime/64 */
u32 abort_code;
short error;
bool have_result;
bool responded:1;
bool is_yfs:1;
bool not_yfs:1;
bool local_failure:1;
} probe;
u16 port;
u16 name_len; /* Length of name */
char name[]; /* Server name, case-flattened */
};
/*
* Weighted list of Volume Location servers.
*/
struct afs_vlserver_entry {
u16 priority; /* Preference (as SRV) */
u16 weight; /* Weight (as SRV) */
enum dns_record_source source:8;
enum dns_lookup_status status:8;
struct afs_vlserver *server;
};
struct afs_vlserver_list {
struct rcu_head rcu;
atomic_t usage;
u8 nr_servers;
u8 index; /* Server currently in use */
u8 preferred; /* Preferred server */
enum dns_record_source source:8;
enum dns_lookup_status status:8;
rwlock_t lock;
struct afs_vlserver_entry servers[];
};
/* /*
* Cached VLDB entry. * Cached VLDB entry.
* *
@ -403,8 +484,12 @@ struct afs_server {
#define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */ #define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */
#define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */ #define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */
#define AFS_SERVER_FL_MAY_HAVE_CB 8 /* May have callbacks on this fileserver */ #define AFS_SERVER_FL_MAY_HAVE_CB 8 /* May have callbacks on this fileserver */
#define AFS_SERVER_FL_IS_YFS 9 /* Server is YFS not AFS */
#define AFS_SERVER_FL_NO_RM2 10 /* Fileserver doesn't support YFS.RemoveFile2 */
#define AFS_SERVER_FL_HAVE_EPOCH 11 /* ->epoch is valid */
atomic_t usage; atomic_t usage;
u32 addr_version; /* Address list version */ u32 addr_version; /* Address list version */
u32 cm_epoch; /* Server RxRPC epoch */
/* file service access */ /* file service access */
rwlock_t fs_lock; /* access lock */ rwlock_t fs_lock; /* access lock */
@ -413,6 +498,26 @@ struct afs_server {
struct hlist_head cb_volumes; /* List of volume interests on this server */ struct hlist_head cb_volumes; /* List of volume interests on this server */
unsigned cb_s_break; /* Break-everything counter. */ unsigned cb_s_break; /* Break-everything counter. */
rwlock_t cb_break_lock; /* Volume finding lock */ rwlock_t cb_break_lock; /* Volume finding lock */
/* Probe state */
wait_queue_head_t probe_wq;
atomic_t probe_outstanding;
spinlock_t probe_lock;
struct {
unsigned int rtt; /* RTT as ktime/64 */
u32 abort_code;
u32 cm_epoch;
short error;
bool have_result;
bool responded:1;
bool is_yfs:1;
bool not_yfs:1;
bool local_failure:1;
bool no_epoch:1;
bool cm_probed:1;
bool said_rebooted:1;
bool said_inconsistent:1;
} probe;
}; };
/* /*
@ -447,8 +552,8 @@ struct afs_server_entry {
struct afs_server_list { struct afs_server_list {
refcount_t usage; refcount_t usage;
unsigned short nr_servers; unsigned char nr_servers;
unsigned short index; /* Server currently in use */ unsigned char preferred; /* Preferred server */
unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */ unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */
unsigned int seq; /* Set to ->servers_seq when installed */ unsigned int seq; /* Set to ->servers_seq when installed */
rwlock_t lock; rwlock_t lock;
@ -550,6 +655,15 @@ struct afs_vnode {
afs_callback_type_t cb_type; /* type of callback */ afs_callback_type_t cb_type; /* type of callback */
}; };
static inline struct fscache_cookie *afs_vnode_cache(struct afs_vnode *vnode)
{
#ifdef CONFIG_AFS_FSCACHE
return vnode->cache;
#else
return NULL;
#endif
}
/* /*
* cached security record for one user's attempt to access a vnode * cached security record for one user's attempt to access a vnode
*/ */
@ -586,13 +700,31 @@ struct afs_interface {
*/ */
struct afs_addr_cursor { struct afs_addr_cursor {
struct afs_addr_list *alist; /* Current address list (pins ref) */ struct afs_addr_list *alist; /* Current address list (pins ref) */
struct sockaddr_rxrpc *addr; unsigned long tried; /* Tried addresses */
u32 abort_code; signed char index; /* Current address */
unsigned short start; /* Starting point in alist->addrs[] */
unsigned short index; /* Wrapping offset from start to current addr */
short error;
bool begun; /* T if we've begun iteration */
bool responded; /* T if the current address responded */ bool responded; /* T if the current address responded */
unsigned short nr_iterations; /* Number of address iterations */
short error;
u32 abort_code;
};
/*
* Cursor for iterating over a set of volume location servers.
*/
struct afs_vl_cursor {
struct afs_addr_cursor ac;
struct afs_cell *cell; /* The cell we're querying */
struct afs_vlserver_list *server_list; /* Current server list (pins ref) */
struct afs_vlserver *server; /* Server on which this resides */
struct key *key; /* Key for the server */
unsigned long untried; /* Bitmask of untried servers */
short index; /* Current server */
short error;
unsigned short flags;
#define AFS_VL_CURSOR_STOP 0x0001 /* Set to cease iteration */
#define AFS_VL_CURSOR_RETRY 0x0002 /* Set to do a retry */
#define AFS_VL_CURSOR_RETRIED 0x0004 /* Set if started a retry */
unsigned short nr_iterations; /* Number of server iterations */
}; };
/* /*
@ -604,10 +736,11 @@ struct afs_fs_cursor {
struct afs_server_list *server_list; /* Current server list (pins ref) */ struct afs_server_list *server_list; /* Current server list (pins ref) */
struct afs_cb_interest *cbi; /* Server on which this resides (pins ref) */ struct afs_cb_interest *cbi; /* Server on which this resides (pins ref) */
struct key *key; /* Key for the server */ struct key *key; /* Key for the server */
unsigned long untried; /* Bitmask of untried servers */
unsigned int cb_break; /* cb_break + cb_s_break before the call */ unsigned int cb_break; /* cb_break + cb_s_break before the call */
unsigned int cb_break_2; /* cb_break + cb_s_break (2nd vnode) */ unsigned int cb_break_2; /* cb_break + cb_s_break (2nd vnode) */
unsigned char start; /* Initial index in server list */ short index; /* Current server */
unsigned char index; /* Number of servers tried beyond start */ short error;
unsigned short flags; unsigned short flags;
#define AFS_FS_CURSOR_STOP 0x0001 /* Set to cease iteration */ #define AFS_FS_CURSOR_STOP 0x0001 /* Set to cease iteration */
#define AFS_FS_CURSOR_VBUSY 0x0002 /* Set if seen VBUSY */ #define AFS_FS_CURSOR_VBUSY 0x0002 /* Set if seen VBUSY */
@ -615,6 +748,7 @@ struct afs_fs_cursor {
#define AFS_FS_CURSOR_VNOVOL 0x0008 /* Set if seen VNOVOL */ #define AFS_FS_CURSOR_VNOVOL 0x0008 /* Set if seen VNOVOL */
#define AFS_FS_CURSOR_CUR_ONLY 0x0010 /* Set if current server only (file lock held) */ #define AFS_FS_CURSOR_CUR_ONLY 0x0010 /* Set if current server only (file lock held) */
#define AFS_FS_CURSOR_NO_VSLEEP 0x0020 /* Set to prevent sleep on VBUSY, VOFFLINE, ... */ #define AFS_FS_CURSOR_NO_VSLEEP 0x0020 /* Set to prevent sleep on VBUSY, VOFFLINE, ... */
unsigned short nr_iterations; /* Number of server iterations */
}; };
/* /*
@ -640,12 +774,12 @@ extern struct afs_addr_list *afs_alloc_addrlist(unsigned int,
unsigned short, unsigned short,
unsigned short); unsigned short);
extern void afs_put_addrlist(struct afs_addr_list *); extern void afs_put_addrlist(struct afs_addr_list *);
extern struct afs_addr_list *afs_parse_text_addrs(const char *, size_t, char, extern struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *,
const char *, size_t, char,
unsigned short, unsigned short); unsigned short, unsigned short);
extern struct afs_addr_list *afs_dns_query(struct afs_cell *, time64_t *); extern struct afs_vlserver_list *afs_dns_query(struct afs_cell *, time64_t *);
extern bool afs_iterate_addresses(struct afs_addr_cursor *); extern bool afs_iterate_addresses(struct afs_addr_cursor *);
extern int afs_end_cursor(struct afs_addr_cursor *); extern int afs_end_cursor(struct afs_addr_cursor *);
extern int afs_set_vl_cursor(struct afs_addr_cursor *, struct afs_cell *);
extern void afs_merge_fs_addr4(struct afs_addr_list *, __be32, u16); extern void afs_merge_fs_addr4(struct afs_addr_list *, __be32, u16);
extern void afs_merge_fs_addr6(struct afs_addr_list *, __be32 *, u16); extern void afs_merge_fs_addr6(struct afs_addr_list *, __be32 *, u16);
@ -668,6 +802,7 @@ extern struct fscache_cookie_def afs_vnode_cache_index_def;
* callback.c * callback.c
*/ */
extern void afs_init_callback_state(struct afs_server *); extern void afs_init_callback_state(struct afs_server *);
extern void __afs_break_callback(struct afs_vnode *);
extern void afs_break_callback(struct afs_vnode *); extern void afs_break_callback(struct afs_vnode *);
extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*); extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*);
@ -688,10 +823,13 @@ static inline unsigned int afs_calc_vnode_cb_break(struct afs_vnode *vnode)
return vnode->cb_break + vnode->cb_s_break + vnode->cb_v_break; return vnode->cb_break + vnode->cb_s_break + vnode->cb_v_break;
} }
static inline unsigned int afs_cb_break_sum(struct afs_vnode *vnode, static inline bool afs_cb_is_broken(unsigned int cb_break,
struct afs_cb_interest *cbi) const struct afs_vnode *vnode,
const struct afs_cb_interest *cbi)
{ {
return vnode->cb_break + cbi->server->cb_s_break + vnode->volume->cb_v_break; return !cbi || cb_break != (vnode->cb_break +
cbi->server->cb_s_break +
vnode->volume->cb_v_break);
} }
/* /*
@ -781,7 +919,7 @@ extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *);
extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *); extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *);
extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, u64, extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, u64,
struct afs_fid *, struct afs_file_status *, struct afs_callback *); struct afs_fid *, struct afs_file_status *, struct afs_callback *);
extern int afs_fs_remove(struct afs_fs_cursor *, const char *, bool, u64); extern int afs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool, u64);
extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64); extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64);
extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64, extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64,
struct afs_fid *, struct afs_file_status *); struct afs_fid *, struct afs_file_status *);
@ -797,7 +935,7 @@ extern int afs_fs_release_lock(struct afs_fs_cursor *);
extern int afs_fs_give_up_all_callbacks(struct afs_net *, struct afs_server *, extern int afs_fs_give_up_all_callbacks(struct afs_net *, struct afs_server *,
struct afs_addr_cursor *, struct key *); struct afs_addr_cursor *, struct key *);
extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *, extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *,
struct afs_addr_cursor *, struct key *); struct afs_addr_cursor *, struct key *, unsigned int, bool);
extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *, struct afs_fid *, struct afs_file_status *,
struct afs_callback *, unsigned int, struct afs_callback *, unsigned int,
@ -806,6 +944,13 @@ extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *, struct afs_fid *, struct afs_file_status *,
struct afs_callback *, struct afs_volsync *); struct afs_callback *, struct afs_volsync *);
/*
* fs_probe.c
*/
extern void afs_fileserver_probe_result(struct afs_call *);
extern int afs_probe_fileservers(struct afs_net *, struct key *, struct afs_server_list *);
extern int afs_wait_for_fs_probes(struct afs_server_list *, unsigned long);
/* /*
* inode.c * inode.c
*/ */
@ -922,7 +1067,6 @@ extern int __net_init afs_open_socket(struct afs_net *);
extern void __net_exit afs_close_socket(struct afs_net *); extern void __net_exit afs_close_socket(struct afs_net *);
extern void afs_charge_preallocation(struct work_struct *); extern void afs_charge_preallocation(struct work_struct *);
extern void afs_put_call(struct afs_call *); extern void afs_put_call(struct afs_call *);
extern int afs_queue_call_work(struct afs_call *);
extern long afs_make_call(struct afs_addr_cursor *, struct afs_call *, gfp_t, bool); extern long afs_make_call(struct afs_addr_cursor *, struct afs_call *, gfp_t, bool);
extern struct afs_call *afs_alloc_flat_call(struct afs_net *, extern struct afs_call *afs_alloc_flat_call(struct afs_net *,
const struct afs_call_type *, const struct afs_call_type *,
@ -930,12 +1074,39 @@ extern struct afs_call *afs_alloc_flat_call(struct afs_net *,
extern void afs_flat_call_destructor(struct afs_call *); extern void afs_flat_call_destructor(struct afs_call *);
extern void afs_send_empty_reply(struct afs_call *); extern void afs_send_empty_reply(struct afs_call *);
extern void afs_send_simple_reply(struct afs_call *, const void *, size_t); extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);
extern int afs_extract_data(struct afs_call *, void *, size_t, bool); extern int afs_extract_data(struct afs_call *, bool);
extern int afs_protocol_error(struct afs_call *, int); extern int afs_protocol_error(struct afs_call *, int, enum afs_eproto_cause);
static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
{
call->kvec[0].iov_base = buf;
call->kvec[0].iov_len = size;
iov_iter_kvec(&call->iter, READ, call->kvec, 1, size);
}
static inline void afs_extract_to_tmp(struct afs_call *call)
{
afs_extract_begin(call, &call->tmp, sizeof(call->tmp));
}
static inline void afs_extract_to_tmp64(struct afs_call *call)
{
afs_extract_begin(call, &call->tmp64, sizeof(call->tmp64));
}
static inline void afs_extract_discard(struct afs_call *call, size_t size)
{
iov_iter_discard(&call->iter, READ, size);
}
static inline void afs_extract_to_buf(struct afs_call *call, size_t size)
{
afs_extract_begin(call, call->buffer, size);
}
static inline int afs_transfer_reply(struct afs_call *call) static inline int afs_transfer_reply(struct afs_call *call)
{ {
return afs_extract_data(call, call->buffer, call->reply_max, false); return afs_extract_data(call, false);
} }
static inline bool afs_check_call_state(struct afs_call *call, static inline bool afs_check_call_state(struct afs_call *call,
@ -1012,7 +1183,6 @@ extern void afs_put_server(struct afs_net *, struct afs_server *);
extern void afs_manage_servers(struct work_struct *); extern void afs_manage_servers(struct work_struct *);
extern void afs_servers_timer(struct timer_list *); extern void afs_servers_timer(struct timer_list *);
extern void __net_exit afs_purge_servers(struct afs_net *); extern void __net_exit afs_purge_servers(struct afs_net *);
extern bool afs_probe_fileserver(struct afs_fs_cursor *);
extern bool afs_check_server_record(struct afs_fs_cursor *, struct afs_server *); extern bool afs_check_server_record(struct afs_fs_cursor *, struct afs_server *);
/* /*
@ -1039,14 +1209,51 @@ extern void afs_fs_exit(void);
/* /*
* vlclient.c * vlclient.c
*/ */
extern struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *, extern struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *,
struct afs_addr_cursor *, const char *, int);
struct key *, const char *, int); extern struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *, const uuid_t *);
extern struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *, struct afs_addr_cursor *, extern int afs_vl_get_capabilities(struct afs_net *, struct afs_addr_cursor *, struct key *,
struct key *, const uuid_t *); struct afs_vlserver *, unsigned int, bool);
extern int afs_vl_get_capabilities(struct afs_net *, struct afs_addr_cursor *, struct key *); extern struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *, const uuid_t *);
extern struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *, struct afs_addr_cursor *,
struct key *, const uuid_t *); /*
* vl_probe.c
*/
extern void afs_vlserver_probe_result(struct afs_call *);
extern int afs_send_vl_probes(struct afs_net *, struct key *, struct afs_vlserver_list *);
extern int afs_wait_for_vl_probes(struct afs_vlserver_list *, unsigned long);
/*
* vl_rotate.c
*/
extern bool afs_begin_vlserver_operation(struct afs_vl_cursor *,
struct afs_cell *, struct key *);
extern bool afs_select_vlserver(struct afs_vl_cursor *);
extern bool afs_select_current_vlserver(struct afs_vl_cursor *);
extern int afs_end_vlserver_operation(struct afs_vl_cursor *);
/*
* vlserver_list.c
*/
static inline struct afs_vlserver *afs_get_vlserver(struct afs_vlserver *vlserver)
{
atomic_inc(&vlserver->usage);
return vlserver;
}
static inline struct afs_vlserver_list *afs_get_vlserverlist(struct afs_vlserver_list *vllist)
{
if (vllist)
atomic_inc(&vllist->usage);
return vllist;
}
extern struct afs_vlserver *afs_alloc_vlserver(const char *, size_t, unsigned short);
extern void afs_put_vlserver(struct afs_net *, struct afs_vlserver *);
extern struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int);
extern void afs_put_vlserverlist(struct afs_net *, struct afs_vlserver_list *);
extern struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *,
const void *, size_t);
/* /*
* volume.c * volume.c
@ -1089,6 +1296,36 @@ extern int afs_launder_page(struct page *);
extern const struct xattr_handler *afs_xattr_handlers[]; extern const struct xattr_handler *afs_xattr_handlers[];
extern ssize_t afs_listxattr(struct dentry *, char *, size_t); extern ssize_t afs_listxattr(struct dentry *, char *, size_t);
/*
* yfsclient.c
*/
extern int yfs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool);
extern int yfs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *);
extern int yfs_fs_create_file(struct afs_fs_cursor *, const char *, umode_t, u64,
struct afs_fid *, struct afs_file_status *, struct afs_callback *);
extern int yfs_fs_make_dir(struct afs_fs_cursor *, const char *, umode_t, u64,
struct afs_fid *, struct afs_file_status *, struct afs_callback *);
extern int yfs_fs_remove_file2(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64);
extern int yfs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool, u64);
extern int yfs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64);
extern int yfs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64,
struct afs_fid *, struct afs_file_status *);
extern int yfs_fs_rename(struct afs_fs_cursor *, const char *,
struct afs_vnode *, const char *, u64, u64);
extern int yfs_fs_store_data(struct afs_fs_cursor *, struct address_space *,
pgoff_t, pgoff_t, unsigned, unsigned);
extern int yfs_fs_setattr(struct afs_fs_cursor *, struct iattr *);
extern int yfs_fs_get_volume_status(struct afs_fs_cursor *, struct afs_volume_status *);
extern int yfs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t);
extern int yfs_fs_extend_lock(struct afs_fs_cursor *);
extern int yfs_fs_release_lock(struct afs_fs_cursor *);
extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *,
struct afs_callback *, struct afs_volsync *);
extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *,
struct afs_callback *, unsigned int,
struct afs_volsync *);
/* /*
* Miscellaneous inline functions. * Miscellaneous inline functions.
@ -1120,6 +1357,17 @@ static inline void afs_check_for_remote_deletion(struct afs_fs_cursor *fc,
} }
} }
static inline int afs_io_error(struct afs_call *call, enum afs_io_error where)
{
trace_afs_io_error(call->debug_id, -EIO, where);
return -EIO;
}
static inline int afs_bad(struct afs_vnode *vnode, enum afs_file_error where)
{
trace_afs_file_error(vnode, -EIO, where);
return -EIO;
}
/*****************************************************************************/ /*****************************************************************************/
/* /*

View File

@ -130,9 +130,10 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
goto error_no_page; goto error_no_page;
} }
ret = -EIO; if (PageError(page)) {
if (PageError(page)) ret = afs_bad(AFS_FS_I(d_inode(mntpt)), afs_file_error_mntpt);
goto error; goto error;
}
buf = kmap_atomic(page); buf = kmap_atomic(page);
memcpy(devname, buf, size); memcpy(devname, buf, size);

View File

@ -17,6 +17,11 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include "internal.h" #include "internal.h"
struct afs_vl_seq_net_private {
struct seq_net_private seq; /* Must be first */
struct afs_vlserver_list *vllist;
};
static inline struct afs_net *afs_seq2net(struct seq_file *m) static inline struct afs_net *afs_seq2net(struct seq_file *m)
{ {
return afs_net(seq_file_net(m)); return afs_net(seq_file_net(m));
@ -32,16 +37,24 @@ static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
*/ */
static int afs_proc_cells_show(struct seq_file *m, void *v) static int afs_proc_cells_show(struct seq_file *m, void *v)
{ {
struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); struct afs_vlserver_list *vllist;
struct afs_cell *cell;
if (v == SEQ_START_TOKEN) { if (v == SEQ_START_TOKEN) {
/* display header on line 1 */ /* display header on line 1 */
seq_puts(m, "USE NAME\n"); seq_puts(m, "USE TTL SV NAME\n");
return 0; return 0;
} }
cell = list_entry(v, struct afs_cell, proc_link);
vllist = rcu_dereference(cell->vl_servers);
/* display one cell per line on subsequent lines */ /* display one cell per line on subsequent lines */
seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name); seq_printf(m, "%3u %6lld %2u %s\n",
atomic_read(&cell->usage),
cell->dns_expiry - ktime_get_real_seconds(),
vllist ? vllist->nr_servers : 0,
cell->name);
return 0; return 0;
} }
@ -208,7 +221,7 @@ static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
return 0; return 0;
} }
seq_printf(m, "%3d %08x %s\n", seq_printf(m, "%3d %08llx %s\n",
atomic_read(&vol->usage), vol->vid, atomic_read(&vol->usage), vol->vid,
afs_vol_types[vol->type]); afs_vol_types[vol->type]);
@ -247,61 +260,102 @@ static const struct seq_operations afs_proc_cell_volumes_ops = {
.show = afs_proc_cell_volumes_show, .show = afs_proc_cell_volumes_show,
}; };
static const char *const dns_record_sources[NR__dns_record_source + 1] = {
[DNS_RECORD_UNAVAILABLE] = "unav",
[DNS_RECORD_FROM_CONFIG] = "cfg",
[DNS_RECORD_FROM_DNS_A] = "A",
[DNS_RECORD_FROM_DNS_AFSDB] = "AFSDB",
[DNS_RECORD_FROM_DNS_SRV] = "SRV",
[DNS_RECORD_FROM_NSS] = "nss",
[NR__dns_record_source] = "[weird]"
};
static const char *const dns_lookup_statuses[NR__dns_lookup_status + 1] = {
[DNS_LOOKUP_NOT_DONE] = "no-lookup",
[DNS_LOOKUP_GOOD] = "good",
[DNS_LOOKUP_GOOD_WITH_BAD] = "good/bad",
[DNS_LOOKUP_BAD] = "bad",
[DNS_LOOKUP_GOT_NOT_FOUND] = "not-found",
[DNS_LOOKUP_GOT_LOCAL_FAILURE] = "local-failure",
[DNS_LOOKUP_GOT_TEMP_FAILURE] = "temp-failure",
[DNS_LOOKUP_GOT_NS_FAILURE] = "ns-failure",
[NR__dns_lookup_status] = "[weird]"
};
/* /*
* Display the list of Volume Location servers we're using for a cell. * Display the list of Volume Location servers we're using for a cell.
*/ */
static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
{ {
struct sockaddr_rxrpc *addr = v; const struct afs_vl_seq_net_private *priv = m->private;
const struct afs_vlserver_list *vllist = priv->vllist;
const struct afs_vlserver_entry *entry;
const struct afs_vlserver *vlserver;
const struct afs_addr_list *alist;
int i;
/* display header on line 1 */ if (v == SEQ_START_TOKEN) {
if (v == (void *)1) { seq_printf(m, "# source %s, status %s\n",
seq_puts(m, "ADDRESS\n"); dns_record_sources[vllist->source],
dns_lookup_statuses[vllist->status]);
return 0; return 0;
} }
/* display one cell per line on subsequent lines */ entry = v;
seq_printf(m, "%pISp\n", &addr->transport); vlserver = entry->server;
alist = rcu_dereference(vlserver->addresses);
seq_printf(m, "%s [p=%hu w=%hu s=%s,%s]:\n",
vlserver->name, entry->priority, entry->weight,
dns_record_sources[alist ? alist->source : entry->source],
dns_lookup_statuses[alist ? alist->status : entry->status]);
if (alist) {
for (i = 0; i < alist->nr_addrs; i++)
seq_printf(m, " %c %pISpc\n",
alist->preferred == i ? '>' : '-',
&alist->addrs[i].transport);
}
return 0; return 0;
} }
static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
__acquires(rcu) __acquires(rcu)
{ {
struct afs_addr_list *alist; struct afs_vl_seq_net_private *priv = m->private;
struct afs_vlserver_list *vllist;
struct afs_cell *cell = PDE_DATA(file_inode(m->file)); struct afs_cell *cell = PDE_DATA(file_inode(m->file));
loff_t pos = *_pos; loff_t pos = *_pos;
rcu_read_lock(); rcu_read_lock();
alist = rcu_dereference(cell->vl_addrs); vllist = rcu_dereference(cell->vl_servers);
priv->vllist = vllist;
/* allow for the header line */ if (pos < 0)
if (!pos) *_pos = pos = 0;
return (void *) 1; if (pos == 0)
pos--; return SEQ_START_TOKEN;
if (!alist || pos >= alist->nr_addrs) if (!vllist || pos - 1 >= vllist->nr_servers)
return NULL; return NULL;
return alist->addrs + pos; return &vllist->servers[pos - 1];
} }
static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v, static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v,
loff_t *_pos) loff_t *_pos)
{ {
struct afs_addr_list *alist; struct afs_vl_seq_net_private *priv = m->private;
struct afs_cell *cell = PDE_DATA(file_inode(m->file)); struct afs_vlserver_list *vllist = priv->vllist;
loff_t pos; loff_t pos;
alist = rcu_dereference(cell->vl_addrs);
pos = *_pos; pos = *_pos;
(*_pos)++; pos++;
if (!alist || pos >= alist->nr_addrs) *_pos = pos;
if (!vllist || pos - 1 >= vllist->nr_servers)
return NULL; return NULL;
return alist->addrs + pos; return &vllist->servers[pos - 1];
} }
static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v) static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v)
@ -337,11 +391,11 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
&server->uuid, &server->uuid,
atomic_read(&server->usage), atomic_read(&server->usage),
&alist->addrs[0].transport, &alist->addrs[0].transport,
alist->index == 0 ? "*" : ""); alist->preferred == 0 ? "*" : "");
for (i = 1; i < alist->nr_addrs; i++) for (i = 1; i < alist->nr_addrs; i++)
seq_printf(m, " %pISpc%s\n", seq_printf(m, " %pISpc%s\n",
&alist->addrs[i].transport, &alist->addrs[i].transport,
alist->index == i ? "*" : ""); alist->preferred == i ? "*" : "");
return 0; return 0;
} }
@ -562,7 +616,7 @@ int afs_proc_cell_setup(struct afs_cell *cell)
if (!proc_create_net_data("vlservers", 0444, dir, if (!proc_create_net_data("vlservers", 0444, dir,
&afs_proc_cell_vlservers_ops, &afs_proc_cell_vlservers_ops,
sizeof(struct seq_net_private), sizeof(struct afs_vl_seq_net_private),
cell) || cell) ||
!proc_create_net_data("volumes", 0444, dir, !proc_create_net_data("volumes", 0444, dir,
&afs_proc_cell_volumes_ops, &afs_proc_cell_volumes_ops,

163
fs/afs/protocol_yfs.h Normal file
View File

@ -0,0 +1,163 @@
/* YFS protocol bits
*
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define YFS_FS_SERVICE 2500
#define YFS_CM_SERVICE 2501
#define YFSCBMAX 1024
enum YFS_CM_Operations {
YFSCBProbe = 206, /* probe client */
YFSCBGetLock = 207, /* get contents of CM lock table */
YFSCBXStatsVersion = 209, /* get version of extended statistics */
YFSCBGetXStats = 210, /* get contents of extended statistics data */
YFSCBInitCallBackState3 = 213, /* initialise callback state, version 3 */
YFSCBProbeUuid = 214, /* check the client hasn't rebooted */
YFSCBGetServerPrefs = 215,
YFSCBGetCellServDV = 216,
YFSCBGetLocalCell = 217,
YFSCBGetCacheConfig = 218,
YFSCBGetCellByNum = 65537,
YFSCBTellMeAboutYourself = 65538, /* get client capabilities */
YFSCBCallBack = 64204,
};
enum YFS_FS_Operations {
YFSFETCHACL = 64131, /* YFS Fetch file ACL */
YFSFETCHSTATUS = 64132, /* YFS Fetch file status */
YFSSTOREACL = 64134, /* YFS Store file ACL */
YFSSTORESTATUS = 64135, /* YFS Store file status */
YFSREMOVEFILE = 64136, /* YFS Remove a file */
YFSCREATEFILE = 64137, /* YFS Create a file */
YFSRENAME = 64138, /* YFS Rename or move a file or directory */
YFSSYMLINK = 64139, /* YFS Create a symbolic link */
YFSLINK = 64140, /* YFS Create a hard link */
YFSMAKEDIR = 64141, /* YFS Create a directory */
YFSREMOVEDIR = 64142, /* YFS Remove a directory */
YFSGETVOLUMESTATUS = 64149, /* YFS Get volume status information */
YFSSETVOLUMESTATUS = 64150, /* YFS Set volume status information */
YFSSETLOCK = 64156, /* YFS Request a file lock */
YFSEXTENDLOCK = 64157, /* YFS Extend a file lock */
YFSRELEASELOCK = 64158, /* YFS Release a file lock */
YFSLOOKUP = 64161, /* YFS lookup file in directory */
YFSFLUSHCPS = 64165,
YFSFETCHOPAQUEACL = 64168,
YFSWHOAMI = 64170,
YFSREMOVEACL = 64171,
YFSREMOVEFILE2 = 64173,
YFSSTOREOPAQUEACL2 = 64174,
YFSINLINEBULKSTATUS = 64536, /* YFS Fetch multiple file statuses with errors */
YFSFETCHDATA64 = 64537, /* YFS Fetch file data */
YFSSTOREDATA64 = 64538, /* YFS Store file data */
YFSUPDATESYMLINK = 64540,
};
struct yfs_xdr_u64 {
__be32 msw;
__be32 lsw;
} __packed;
static inline u64 xdr_to_u64(const struct yfs_xdr_u64 x)
{
return ((u64)ntohl(x.msw) << 32) | ntohl(x.lsw);
}
static inline struct yfs_xdr_u64 u64_to_xdr(const u64 x)
{
return (struct yfs_xdr_u64){ .msw = htonl(x >> 32), .lsw = htonl(x) };
}
struct yfs_xdr_vnode {
struct yfs_xdr_u64 lo;
__be32 hi;
__be32 unique;
} __packed;
struct yfs_xdr_YFSFid {
struct yfs_xdr_u64 volume;
struct yfs_xdr_vnode vnode;
} __packed;
struct yfs_xdr_YFSFetchStatus {
__be32 type;
__be32 nlink;
struct yfs_xdr_u64 size;
struct yfs_xdr_u64 data_version;
struct yfs_xdr_u64 author;
struct yfs_xdr_u64 owner;
struct yfs_xdr_u64 group;
__be32 mode;
__be32 caller_access;
__be32 anon_access;
struct yfs_xdr_vnode parent;
__be32 data_access_protocol;
struct yfs_xdr_u64 mtime_client;
struct yfs_xdr_u64 mtime_server;
__be32 lock_count;
__be32 abort_code;
} __packed;
struct yfs_xdr_YFSCallBack {
__be32 version;
struct yfs_xdr_u64 expiration_time;
__be32 type;
} __packed;
struct yfs_xdr_YFSStoreStatus {
__be32 mask;
__be32 mode;
struct yfs_xdr_u64 mtime_client;
struct yfs_xdr_u64 owner;
struct yfs_xdr_u64 group;
} __packed;
struct yfs_xdr_RPCFlags {
__be32 rpc_flags;
} __packed;
struct yfs_xdr_YFSVolSync {
struct yfs_xdr_u64 vol_creation_date;
struct yfs_xdr_u64 vol_update_date;
struct yfs_xdr_u64 max_quota;
struct yfs_xdr_u64 blocks_in_use;
struct yfs_xdr_u64 blocks_avail;
} __packed;
enum yfs_volume_type {
yfs_volume_type_ro = 0,
yfs_volume_type_rw = 1,
};
#define yfs_FVSOnline 0x1
#define yfs_FVSInservice 0x2
#define yfs_FVSBlessed 0x4
#define yfs_FVSNeedsSalvage 0x8
struct yfs_xdr_YFSFetchVolumeStatus {
struct yfs_xdr_u64 vid;
struct yfs_xdr_u64 parent_id;
__be32 flags;
__be32 type;
struct yfs_xdr_u64 max_quota;
struct yfs_xdr_u64 blocks_in_use;
struct yfs_xdr_u64 part_blocks_avail;
struct yfs_xdr_u64 part_max_blocks;
struct yfs_xdr_u64 vol_copy_date;
struct yfs_xdr_u64 vol_backup_date;
} __packed;
struct yfs_xdr_YFSStoreVolumeStatus {
__be32 mask;
struct yfs_xdr_u64 min_quota;
struct yfs_xdr_u64 max_quota;
struct yfs_xdr_u64 file_quota;
} __packed;

View File

@ -18,14 +18,6 @@
#include "internal.h" #include "internal.h"
#include "afs_fs.h" #include "afs_fs.h"
/*
* Initialise a filesystem server cursor for iterating over FS servers.
*/
static void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
{
memset(fc, 0, sizeof(*fc));
}
/* /*
* Begin an operation on the fileserver. * Begin an operation on the fileserver.
* *
@ -35,13 +27,14 @@ static void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode
bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode, bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
struct key *key) struct key *key)
{ {
afs_init_fs_cursor(fc, vnode); memset(fc, 0, sizeof(*fc));
fc->vnode = vnode; fc->vnode = vnode;
fc->key = key; fc->key = key;
fc->ac.error = SHRT_MAX; fc->ac.error = SHRT_MAX;
fc->error = -EDESTADDRREQ;
if (mutex_lock_interruptible(&vnode->io_lock) < 0) { if (mutex_lock_interruptible(&vnode->io_lock) < 0) {
fc->ac.error = -EINTR; fc->error = -EINTR;
fc->flags |= AFS_FS_CURSOR_STOP; fc->flags |= AFS_FS_CURSOR_STOP;
return false; return false;
} }
@ -65,12 +58,15 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc,
fc->server_list = afs_get_serverlist(vnode->volume->servers); fc->server_list = afs_get_serverlist(vnode->volume->servers);
read_unlock(&vnode->volume->servers_lock); read_unlock(&vnode->volume->servers_lock);
fc->untried = (1UL << fc->server_list->nr_servers) - 1;
fc->index = READ_ONCE(fc->server_list->preferred);
cbi = vnode->cb_interest; cbi = vnode->cb_interest;
if (cbi) { if (cbi) {
/* See if the vnode's preferred record is still available */ /* See if the vnode's preferred record is still available */
for (i = 0; i < fc->server_list->nr_servers; i++) { for (i = 0; i < fc->server_list->nr_servers; i++) {
if (fc->server_list->servers[i].cb_interest == cbi) { if (fc->server_list->servers[i].cb_interest == cbi) {
fc->start = i; fc->index = i;
goto found_interest; goto found_interest;
} }
} }
@ -80,7 +76,7 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc,
* and have to return an error. * and have to return an error.
*/ */
if (fc->flags & AFS_FS_CURSOR_CUR_ONLY) { if (fc->flags & AFS_FS_CURSOR_CUR_ONLY) {
fc->ac.error = -ESTALE; fc->error = -ESTALE;
return false; return false;
} }
@ -94,12 +90,9 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc,
afs_put_cb_interest(afs_v2net(vnode), cbi); afs_put_cb_interest(afs_v2net(vnode), cbi);
cbi = NULL; cbi = NULL;
} else {
fc->start = READ_ONCE(fc->server_list->index);
} }
found_interest: found_interest:
fc->index = fc->start;
return true; return true;
} }
@ -117,7 +110,7 @@ static void afs_busy(struct afs_volume *volume, u32 abort_code)
default: m = "busy"; break; default: m = "busy"; break;
} }
pr_notice("kAFS: Volume %u '%s' is %s\n", volume->vid, volume->name, m); pr_notice("kAFS: Volume %llu '%s' is %s\n", volume->vid, volume->name, m);
} }
/* /*
@ -127,7 +120,7 @@ static bool afs_sleep_and_retry(struct afs_fs_cursor *fc)
{ {
msleep_interruptible(1000); msleep_interruptible(1000);
if (signal_pending(current)) { if (signal_pending(current)) {
fc->ac.error = -ERESTARTSYS; fc->error = -ERESTARTSYS;
return false; return false;
} }
@ -143,27 +136,32 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
struct afs_addr_list *alist; struct afs_addr_list *alist;
struct afs_server *server; struct afs_server *server;
struct afs_vnode *vnode = fc->vnode; struct afs_vnode *vnode = fc->vnode;
u32 rtt, abort_code;
int error = fc->ac.error, i;
_enter("%u/%u,%u/%u,%d,%d", _enter("%lx[%d],%lx[%d],%d,%d",
fc->index, fc->start, fc->untried, fc->index,
fc->ac.index, fc->ac.start, fc->ac.tried, fc->ac.index,
fc->ac.error, fc->ac.abort_code); error, fc->ac.abort_code);
if (fc->flags & AFS_FS_CURSOR_STOP) { if (fc->flags & AFS_FS_CURSOR_STOP) {
_leave(" = f [stopped]"); _leave(" = f [stopped]");
return false; return false;
} }
fc->nr_iterations++;
/* Evaluate the result of the previous operation, if there was one. */ /* Evaluate the result of the previous operation, if there was one. */
switch (fc->ac.error) { switch (error) {
case SHRT_MAX: case SHRT_MAX:
goto start; goto start;
case 0: case 0:
default: default:
/* Success or local failure. Stop. */ /* Success or local failure. Stop. */
fc->error = error;
fc->flags |= AFS_FS_CURSOR_STOP; fc->flags |= AFS_FS_CURSOR_STOP;
_leave(" = f [okay/local %d]", fc->ac.error); _leave(" = f [okay/local %d]", error);
return false; return false;
case -ECONNABORTED: case -ECONNABORTED:
@ -178,7 +176,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
* - May indicate that the fileserver couldn't attach to the vol. * - May indicate that the fileserver couldn't attach to the vol.
*/ */
if (fc->flags & AFS_FS_CURSOR_VNOVOL) { if (fc->flags & AFS_FS_CURSOR_VNOVOL) {
fc->ac.error = -EREMOTEIO; fc->error = -EREMOTEIO;
goto next_server; goto next_server;
} }
@ -187,12 +185,12 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
write_unlock(&vnode->volume->servers_lock); write_unlock(&vnode->volume->servers_lock);
set_bit(AFS_VOLUME_NEEDS_UPDATE, &vnode->volume->flags); set_bit(AFS_VOLUME_NEEDS_UPDATE, &vnode->volume->flags);
fc->ac.error = afs_check_volume_status(vnode->volume, fc->key); error = afs_check_volume_status(vnode->volume, fc->key);
if (fc->ac.error < 0) if (error < 0)
goto failed; goto failed_set_error;
if (test_bit(AFS_VOLUME_DELETED, &vnode->volume->flags)) { if (test_bit(AFS_VOLUME_DELETED, &vnode->volume->flags)) {
fc->ac.error = -ENOMEDIUM; fc->error = -ENOMEDIUM;
goto failed; goto failed;
} }
@ -200,7 +198,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
* it's the fileserver having trouble. * it's the fileserver having trouble.
*/ */
if (vnode->volume->servers == fc->server_list) { if (vnode->volume->servers == fc->server_list) {
fc->ac.error = -EREMOTEIO; fc->error = -EREMOTEIO;
goto next_server; goto next_server;
} }
@ -215,7 +213,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
case VONLINE: case VONLINE:
case VDISKFULL: case VDISKFULL:
case VOVERQUOTA: case VOVERQUOTA:
fc->ac.error = afs_abort_to_error(fc->ac.abort_code); fc->error = afs_abort_to_error(fc->ac.abort_code);
goto next_server; goto next_server;
case VOFFLINE: case VOFFLINE:
@ -224,11 +222,11 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
clear_bit(AFS_VOLUME_BUSY, &vnode->volume->flags); clear_bit(AFS_VOLUME_BUSY, &vnode->volume->flags);
} }
if (fc->flags & AFS_FS_CURSOR_NO_VSLEEP) { if (fc->flags & AFS_FS_CURSOR_NO_VSLEEP) {
fc->ac.error = -EADV; fc->error = -EADV;
goto failed; goto failed;
} }
if (fc->flags & AFS_FS_CURSOR_CUR_ONLY) { if (fc->flags & AFS_FS_CURSOR_CUR_ONLY) {
fc->ac.error = -ESTALE; fc->error = -ESTALE;
goto failed; goto failed;
} }
goto busy; goto busy;
@ -240,7 +238,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
* have a file lock we need to maintain. * have a file lock we need to maintain.
*/ */
if (fc->flags & AFS_FS_CURSOR_NO_VSLEEP) { if (fc->flags & AFS_FS_CURSOR_NO_VSLEEP) {
fc->ac.error = -EBUSY; fc->error = -EBUSY;
goto failed; goto failed;
} }
if (!test_and_set_bit(AFS_VOLUME_BUSY, &vnode->volume->flags)) { if (!test_and_set_bit(AFS_VOLUME_BUSY, &vnode->volume->flags)) {
@ -269,16 +267,16 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
* honour, just in case someone sets up a loop. * honour, just in case someone sets up a loop.
*/ */
if (fc->flags & AFS_FS_CURSOR_VMOVED) { if (fc->flags & AFS_FS_CURSOR_VMOVED) {
fc->ac.error = -EREMOTEIO; fc->error = -EREMOTEIO;
goto failed; goto failed;
} }
fc->flags |= AFS_FS_CURSOR_VMOVED; fc->flags |= AFS_FS_CURSOR_VMOVED;
set_bit(AFS_VOLUME_WAIT, &vnode->volume->flags); set_bit(AFS_VOLUME_WAIT, &vnode->volume->flags);
set_bit(AFS_VOLUME_NEEDS_UPDATE, &vnode->volume->flags); set_bit(AFS_VOLUME_NEEDS_UPDATE, &vnode->volume->flags);
fc->ac.error = afs_check_volume_status(vnode->volume, fc->key); error = afs_check_volume_status(vnode->volume, fc->key);
if (fc->ac.error < 0) if (error < 0)
goto failed; goto failed_set_error;
/* If the server list didn't change, then the VLDB is /* If the server list didn't change, then the VLDB is
* out of sync with the fileservers. This is hopefully * out of sync with the fileservers. This is hopefully
@ -290,7 +288,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
* TODO: Retry a few times with sleeps. * TODO: Retry a few times with sleeps.
*/ */
if (vnode->volume->servers == fc->server_list) { if (vnode->volume->servers == fc->server_list) {
fc->ac.error = -ENOMEDIUM; fc->error = -ENOMEDIUM;
goto failed; goto failed;
} }
@ -299,20 +297,25 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
default: default:
clear_bit(AFS_VOLUME_OFFLINE, &vnode->volume->flags); clear_bit(AFS_VOLUME_OFFLINE, &vnode->volume->flags);
clear_bit(AFS_VOLUME_BUSY, &vnode->volume->flags); clear_bit(AFS_VOLUME_BUSY, &vnode->volume->flags);
fc->ac.error = afs_abort_to_error(fc->ac.abort_code); fc->error = afs_abort_to_error(fc->ac.abort_code);
goto failed; goto failed;
} }
case -ETIMEDOUT:
case -ETIME:
if (fc->error != -EDESTADDRREQ)
goto iterate_address;
/* Fall through */
case -ENETUNREACH: case -ENETUNREACH:
case -EHOSTUNREACH: case -EHOSTUNREACH:
case -ECONNREFUSED: case -ECONNREFUSED:
case -ETIMEDOUT:
case -ETIME:
_debug("no conn"); _debug("no conn");
fc->error = error;
goto iterate_address; goto iterate_address;
case -ECONNRESET: case -ECONNRESET:
_debug("call reset"); _debug("call reset");
fc->error = error;
goto failed; goto failed;
} }
@ -328,15 +331,57 @@ start:
/* See if we need to do an update of the volume record. Note that the /* See if we need to do an update of the volume record. Note that the
* volume may have moved or even have been deleted. * volume may have moved or even have been deleted.
*/ */
fc->ac.error = afs_check_volume_status(vnode->volume, fc->key); error = afs_check_volume_status(vnode->volume, fc->key);
if (fc->ac.error < 0) if (error < 0)
goto failed; goto failed_set_error;
if (!afs_start_fs_iteration(fc, vnode)) if (!afs_start_fs_iteration(fc, vnode))
goto failed; goto failed;
use_server: _debug("__ VOL %llx __", vnode->volume->vid);
_debug("use"); error = afs_probe_fileservers(afs_v2net(vnode), fc->key, fc->server_list);
if (error < 0)
goto failed_set_error;
pick_server:
_debug("pick [%lx]", fc->untried);
error = afs_wait_for_fs_probes(fc->server_list, fc->untried);
if (error < 0)
goto failed_set_error;
/* Pick the untried server with the lowest RTT. If we have outstanding
* callbacks, we stick with the server we're already using if we can.
*/
if (fc->cbi) {
_debug("cbi %u", fc->index);
if (test_bit(fc->index, &fc->untried))
goto selected_server;
afs_put_cb_interest(afs_v2net(vnode), fc->cbi);
fc->cbi = NULL;
_debug("nocbi");
}
fc->index = -1;
rtt = U32_MAX;
for (i = 0; i < fc->server_list->nr_servers; i++) {
struct afs_server *s = fc->server_list->servers[i].server;
if (!test_bit(i, &fc->untried) || !s->probe.responded)
continue;
if (s->probe.rtt < rtt) {
fc->index = i;
rtt = s->probe.rtt;
}
}
if (fc->index == -1)
goto no_more_servers;
selected_server:
_debug("use %d", fc->index);
__clear_bit(fc->index, &fc->untried);
/* We're starting on a different fileserver from the list. We need to /* We're starting on a different fileserver from the list. We need to
* check it, create a callback intercept, find its address list and * check it, create a callback intercept, find its address list and
* probe its capabilities before we use it. * probe its capabilities before we use it.
@ -354,10 +399,10 @@ use_server:
* break request before we've finished decoding the reply and * break request before we've finished decoding the reply and
* installing the vnode. * installing the vnode.
*/ */
fc->ac.error = afs_register_server_cb_interest(vnode, fc->server_list, error = afs_register_server_cb_interest(vnode, fc->server_list,
fc->index); fc->index);
if (fc->ac.error < 0) if (error < 0)
goto failed; goto failed_set_error;
fc->cbi = afs_get_cb_interest(vnode->cb_interest); fc->cbi = afs_get_cb_interest(vnode->cb_interest);
@ -369,66 +414,88 @@ use_server:
memset(&fc->ac, 0, sizeof(fc->ac)); memset(&fc->ac, 0, sizeof(fc->ac));
/* Probe the current fileserver if we haven't done so yet. */
if (!test_bit(AFS_SERVER_FL_PROBED, &server->flags)) {
fc->ac.alist = afs_get_addrlist(alist);
if (!afs_probe_fileserver(fc)) {
switch (fc->ac.error) {
case -ENOMEM:
case -ERESTARTSYS:
case -EINTR:
goto failed;
default:
goto next_server;
}
}
}
if (!fc->ac.alist) if (!fc->ac.alist)
fc->ac.alist = alist; fc->ac.alist = alist;
else else
afs_put_addrlist(alist); afs_put_addrlist(alist);
fc->ac.start = READ_ONCE(alist->index); fc->ac.index = -1;
fc->ac.index = fc->ac.start;
iterate_address: iterate_address:
ASSERT(fc->ac.alist); ASSERT(fc->ac.alist);
_debug("iterate %d/%d", fc->ac.index, fc->ac.alist->nr_addrs);
/* Iterate over the current server's address list to try and find an /* Iterate over the current server's address list to try and find an
* address on which it will respond to us. * address on which it will respond to us.
*/ */
if (!afs_iterate_addresses(&fc->ac)) if (!afs_iterate_addresses(&fc->ac))
goto next_server; goto next_server;
_debug("address [%u] %u/%u", fc->index, fc->ac.index, fc->ac.alist->nr_addrs);
_leave(" = t"); _leave(" = t");
return true; return true;
next_server: next_server:
_debug("next"); _debug("next");
afs_end_cursor(&fc->ac); afs_end_cursor(&fc->ac);
afs_put_cb_interest(afs_v2net(vnode), fc->cbi); goto pick_server;
fc->cbi = NULL;
fc->index++;
if (fc->index >= fc->server_list->nr_servers)
fc->index = 0;
if (fc->index != fc->start)
goto use_server;
no_more_servers:
/* That's all the servers poked to no good effect. Try again if some /* That's all the servers poked to no good effect. Try again if some
* of them were busy. * of them were busy.
*/ */
if (fc->flags & AFS_FS_CURSOR_VBUSY) if (fc->flags & AFS_FS_CURSOR_VBUSY)
goto restart_from_beginning; goto restart_from_beginning;
fc->ac.error = -EDESTADDRREQ; abort_code = 0;
goto failed; error = -EDESTADDRREQ;
for (i = 0; i < fc->server_list->nr_servers; i++) {
struct afs_server *s = fc->server_list->servers[i].server;
int probe_error = READ_ONCE(s->probe.error);
switch (probe_error) {
case 0:
continue;
default:
if (error == -ETIMEDOUT ||
error == -ETIME)
continue;
case -ETIMEDOUT:
case -ETIME:
if (error == -ENOMEM ||
error == -ENONET)
continue;
case -ENOMEM:
case -ENONET:
if (error == -ENETUNREACH)
continue;
case -ENETUNREACH:
if (error == -EHOSTUNREACH)
continue;
case -EHOSTUNREACH:
if (error == -ECONNREFUSED)
continue;
case -ECONNREFUSED:
if (error == -ECONNRESET)
continue;
case -ECONNRESET: /* Responded, but call expired. */
if (error == -ECONNABORTED)
continue;
case -ECONNABORTED:
abort_code = s->probe.abort_code;
error = probe_error;
continue;
}
}
if (error == -ECONNABORTED)
error = afs_abort_to_error(abort_code);
failed_set_error:
fc->error = error;
failed: failed:
fc->flags |= AFS_FS_CURSOR_STOP; fc->flags |= AFS_FS_CURSOR_STOP;
afs_end_cursor(&fc->ac); afs_end_cursor(&fc->ac);
_leave(" = f [failed %d]", fc->ac.error); _leave(" = f [failed %d]", fc->error);
return false; return false;
} }
@ -442,13 +509,14 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
struct afs_vnode *vnode = fc->vnode; struct afs_vnode *vnode = fc->vnode;
struct afs_cb_interest *cbi = vnode->cb_interest; struct afs_cb_interest *cbi = vnode->cb_interest;
struct afs_addr_list *alist; struct afs_addr_list *alist;
int error = fc->ac.error;
_enter(""); _enter("");
switch (fc->ac.error) { switch (error) {
case SHRT_MAX: case SHRT_MAX:
if (!cbi) { if (!cbi) {
fc->ac.error = -ESTALE; fc->error = -ESTALE;
fc->flags |= AFS_FS_CURSOR_STOP; fc->flags |= AFS_FS_CURSOR_STOP;
return false; return false;
} }
@ -461,25 +529,26 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
afs_get_addrlist(alist); afs_get_addrlist(alist);
read_unlock(&cbi->server->fs_lock); read_unlock(&cbi->server->fs_lock);
if (!alist) { if (!alist) {
fc->ac.error = -ESTALE; fc->error = -ESTALE;
fc->flags |= AFS_FS_CURSOR_STOP; fc->flags |= AFS_FS_CURSOR_STOP;
return false; return false;
} }
memset(&fc->ac, 0, sizeof(fc->ac)); memset(&fc->ac, 0, sizeof(fc->ac));
fc->ac.alist = alist; fc->ac.alist = alist;
fc->ac.start = READ_ONCE(alist->index); fc->ac.index = -1;
fc->ac.index = fc->ac.start;
goto iterate_address; goto iterate_address;
case 0: case 0:
default: default:
/* Success or local failure. Stop. */ /* Success or local failure. Stop. */
fc->error = error;
fc->flags |= AFS_FS_CURSOR_STOP; fc->flags |= AFS_FS_CURSOR_STOP;
_leave(" = f [okay/local %d]", fc->ac.error); _leave(" = f [okay/local %d]", error);
return false; return false;
case -ECONNABORTED: case -ECONNABORTED:
fc->error = afs_abort_to_error(fc->ac.abort_code);
fc->flags |= AFS_FS_CURSOR_STOP; fc->flags |= AFS_FS_CURSOR_STOP;
_leave(" = f [abort]"); _leave(" = f [abort]");
return false; return false;
@ -490,6 +559,7 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
case -ETIMEDOUT: case -ETIMEDOUT:
case -ETIME: case -ETIME:
_debug("no conn"); _debug("no conn");
fc->error = error;
goto iterate_address; goto iterate_address;
} }
@ -506,13 +576,66 @@ iterate_address:
return false; return false;
} }
/*
* Dump cursor state in the case of the error being EDESTADDRREQ.
*/
static void afs_dump_edestaddrreq(const struct afs_fs_cursor *fc)
{
static int count;
int i;
if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3)
return;
count++;
rcu_read_lock();
pr_notice("EDESTADDR occurred\n");
pr_notice("FC: cbb=%x cbb2=%x fl=%hx err=%hd\n",
fc->cb_break, fc->cb_break_2, fc->flags, fc->error);
pr_notice("FC: ut=%lx ix=%d ni=%u\n",
fc->untried, fc->index, fc->nr_iterations);
if (fc->server_list) {
const struct afs_server_list *sl = fc->server_list;
pr_notice("FC: SL nr=%u pr=%u vnov=%hx\n",
sl->nr_servers, sl->preferred, sl->vnovol_mask);
for (i = 0; i < sl->nr_servers; i++) {
const struct afs_server *s = sl->servers[i].server;
pr_notice("FC: server fl=%lx av=%u %pU\n",
s->flags, s->addr_version, &s->uuid);
if (s->addresses) {
const struct afs_addr_list *a =
rcu_dereference(s->addresses);
pr_notice("FC: - av=%u nr=%u/%u/%u pr=%u\n",
a->version,
a->nr_ipv4, a->nr_addrs, a->max_addrs,
a->preferred);
pr_notice("FC: - pr=%lx R=%lx F=%lx\n",
a->probed, a->responded, a->failed);
if (a == fc->ac.alist)
pr_notice("FC: - current\n");
}
}
}
pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
fc->ac.tried, fc->ac.index, fc->ac.abort_code, fc->ac.error,
fc->ac.responded, fc->ac.nr_iterations);
rcu_read_unlock();
}
/* /*
* Tidy up a filesystem cursor and unlock the vnode. * Tidy up a filesystem cursor and unlock the vnode.
*/ */
int afs_end_vnode_operation(struct afs_fs_cursor *fc) int afs_end_vnode_operation(struct afs_fs_cursor *fc)
{ {
struct afs_net *net = afs_v2net(fc->vnode); struct afs_net *net = afs_v2net(fc->vnode);
int ret;
if (fc->error == -EDESTADDRREQ ||
fc->error == -ENETUNREACH ||
fc->error == -EHOSTUNREACH)
afs_dump_edestaddrreq(fc);
mutex_unlock(&fc->vnode->io_lock); mutex_unlock(&fc->vnode->io_lock);
@ -520,9 +643,8 @@ int afs_end_vnode_operation(struct afs_fs_cursor *fc)
afs_put_cb_interest(net, fc->cbi); afs_put_cb_interest(net, fc->cbi);
afs_put_serverlist(net, fc->server_list); afs_put_serverlist(net, fc->server_list);
ret = fc->ac.error; if (fc->error == -ECONNABORTED)
if (ret == -ECONNABORTED) fc->error = afs_abort_to_error(fc->ac.abort_code);
afs_abort_to_error(fc->ac.abort_code);
return fc->ac.error; return fc->error;
} }

View File

@ -16,6 +16,7 @@
#include <net/af_rxrpc.h> #include <net/af_rxrpc.h>
#include "internal.h" #include "internal.h"
#include "afs_cm.h" #include "afs_cm.h"
#include "protocol_yfs.h"
struct workqueue_struct *afs_async_calls; struct workqueue_struct *afs_async_calls;
@ -75,6 +76,18 @@ int afs_open_socket(struct afs_net *net)
if (ret < 0) if (ret < 0)
goto error_2; goto error_2;
srx.srx_service = YFS_CM_SERVICE;
ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
if (ret < 0)
goto error_2;
/* Ideally, we'd turn on service upgrade here, but we can't because
* OpenAFS is buggy and leaks the userStatus field from packet to
* packet and between FS packets and CB packets - so if we try to do an
* upgrade on an FS packet, OpenAFS will leak that into the CB packet
* it sends back to us.
*/
rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, rxrpc_kernel_new_call_notification(socket, afs_rx_new_call,
afs_rx_discard_new_call); afs_rx_discard_new_call);
@ -143,6 +156,7 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
INIT_WORK(&call->async_work, afs_process_async_call); INIT_WORK(&call->async_work, afs_process_async_call);
init_waitqueue_head(&call->waitq); init_waitqueue_head(&call->waitq);
spin_lock_init(&call->state_lock); spin_lock_init(&call->state_lock);
call->_iter = &call->iter;
o = atomic_inc_return(&net->nr_outstanding_calls); o = atomic_inc_return(&net->nr_outstanding_calls);
trace_afs_call(call, afs_call_trace_alloc, 1, o, trace_afs_call(call, afs_call_trace_alloc, 1, o,
@ -176,6 +190,7 @@ void afs_put_call(struct afs_call *call)
afs_put_server(call->net, call->cm_server); afs_put_server(call->net, call->cm_server);
afs_put_cb_interest(call->net, call->cbi); afs_put_cb_interest(call->net, call->cbi);
afs_put_addrlist(call->alist);
kfree(call->request); kfree(call->request);
trace_afs_call(call, afs_call_trace_free, 0, o, trace_afs_call(call, afs_call_trace_free, 0, o,
@ -189,10 +204,11 @@ void afs_put_call(struct afs_call *call)
} }
/* /*
* Queue the call for actual work. Returns 0 unconditionally for convenience. * Queue the call for actual work.
*/ */
int afs_queue_call_work(struct afs_call *call) static void afs_queue_call_work(struct afs_call *call)
{ {
if (call->type->work) {
int u = atomic_inc_return(&call->usage); int u = atomic_inc_return(&call->usage);
trace_afs_call(call, afs_call_trace_work, u, trace_afs_call(call, afs_call_trace_work, u,
@ -203,7 +219,7 @@ int afs_queue_call_work(struct afs_call *call)
if (!queue_work(afs_wq, &call->work)) if (!queue_work(afs_wq, &call->work))
afs_put_call(call); afs_put_call(call);
return 0; }
} }
/* /*
@ -233,6 +249,7 @@ struct afs_call *afs_alloc_flat_call(struct afs_net *net,
goto nomem_free; goto nomem_free;
} }
afs_extract_to_buf(call, call->reply_max);
call->operation_ID = type->op; call->operation_ID = type->op;
init_waitqueue_head(&call->waitq); init_waitqueue_head(&call->waitq);
return call; return call;
@ -286,7 +303,7 @@ static void afs_load_bvec(struct afs_call *call, struct msghdr *msg,
offset = 0; offset = 0;
} }
iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC, bv, nr, bytes); iov_iter_bvec(&msg->msg_iter, WRITE, bv, nr, bytes);
} }
/* /*
@ -342,7 +359,7 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg)
long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
gfp_t gfp, bool async) gfp_t gfp, bool async)
{ {
struct sockaddr_rxrpc *srx = ac->addr; struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index];
struct rxrpc_call *rxcall; struct rxrpc_call *rxcall;
struct msghdr msg; struct msghdr msg;
struct kvec iov[1]; struct kvec iov[1];
@ -359,6 +376,8 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
atomic_read(&call->net->nr_outstanding_calls)); atomic_read(&call->net->nr_outstanding_calls));
call->async = async; call->async = async;
call->addr_ix = ac->index;
call->alist = afs_get_addrlist(ac->alist);
/* Work out the length we're going to transmit. This is awkward for /* Work out the length we're going to transmit. This is awkward for
* calls such as FS.StoreData where there's an extra injection of data * calls such as FS.StoreData where there's an extra injection of data
@ -390,6 +409,7 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
call->debug_id); call->debug_id);
if (IS_ERR(rxcall)) { if (IS_ERR(rxcall)) {
ret = PTR_ERR(rxcall); ret = PTR_ERR(rxcall);
call->error = ret;
goto error_kill_call; goto error_kill_call;
} }
@ -401,8 +421,7 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
msg.msg_name = NULL; msg.msg_name = NULL;
msg.msg_namelen = 0; msg.msg_namelen = 0;
iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size);
call->request_size);
msg.msg_control = NULL; msg.msg_control = NULL;
msg.msg_controllen = 0; msg.msg_controllen = 0;
msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0); msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0);
@ -432,7 +451,7 @@ error_do_abort:
rxrpc_kernel_abort_call(call->net->socket, rxcall, rxrpc_kernel_abort_call(call->net->socket, rxcall,
RX_USER_ABORT, ret, "KSD"); RX_USER_ABORT, ret, "KSD");
} else { } else {
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, NULL, 0, 0); iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0);
rxrpc_kernel_recv_data(call->net->socket, rxcall, rxrpc_kernel_recv_data(call->net->socket, rxcall,
&msg.msg_iter, false, &msg.msg_iter, false,
&call->abort_code, &call->service_id); &call->abort_code, &call->service_id);
@ -442,6 +461,8 @@ error_do_abort:
call->error = ret; call->error = ret;
trace_afs_call_done(call); trace_afs_call_done(call);
error_kill_call: error_kill_call:
if (call->type->done)
call->type->done(call);
afs_put_call(call); afs_put_call(call);
ac->error = ret; ac->error = ret;
_leave(" = %d", ret); _leave(" = %d", ret);
@ -466,14 +487,12 @@ static void afs_deliver_to_call(struct afs_call *call)
state == AFS_CALL_SV_AWAIT_ACK state == AFS_CALL_SV_AWAIT_ACK
) { ) {
if (state == AFS_CALL_SV_AWAIT_ACK) { if (state == AFS_CALL_SV_AWAIT_ACK) {
struct iov_iter iter; iov_iter_kvec(&call->iter, READ, NULL, 0, 0);
iov_iter_kvec(&iter, READ | ITER_KVEC, NULL, 0, 0);
ret = rxrpc_kernel_recv_data(call->net->socket, ret = rxrpc_kernel_recv_data(call->net->socket,
call->rxcall, &iter, false, call->rxcall, &call->iter,
&remote_abort, false, &remote_abort,
&call->service_id); &call->service_id);
trace_afs_recv_data(call, 0, 0, false, ret); trace_afs_receive_data(call, &call->iter, false, ret);
if (ret == -EINPROGRESS || ret == -EAGAIN) if (ret == -EINPROGRESS || ret == -EAGAIN)
return; return;
@ -485,10 +504,17 @@ static void afs_deliver_to_call(struct afs_call *call)
return; return;
} }
if (call->want_reply_time &&
rxrpc_kernel_get_reply_time(call->net->socket,
call->rxcall,
&call->reply_time))
call->want_reply_time = false;
ret = call->type->deliver(call); ret = call->type->deliver(call);
state = READ_ONCE(call->state); state = READ_ONCE(call->state);
switch (ret) { switch (ret) {
case 0: case 0:
afs_queue_call_work(call);
if (state == AFS_CALL_CL_PROC_REPLY) { if (state == AFS_CALL_CL_PROC_REPLY) {
if (call->cbi) if (call->cbi)
set_bit(AFS_SERVER_FL_MAY_HAVE_CB, set_bit(AFS_SERVER_FL_MAY_HAVE_CB,
@ -500,7 +526,6 @@ static void afs_deliver_to_call(struct afs_call *call)
case -EINPROGRESS: case -EINPROGRESS:
case -EAGAIN: case -EAGAIN:
goto out; goto out;
case -EIO:
case -ECONNABORTED: case -ECONNABORTED:
ASSERTCMP(state, ==, AFS_CALL_COMPLETE); ASSERTCMP(state, ==, AFS_CALL_COMPLETE);
goto done; goto done;
@ -509,6 +534,10 @@ static void afs_deliver_to_call(struct afs_call *call)
rxrpc_kernel_abort_call(call->net->socket, call->rxcall, rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, ret, "KIV"); abort_code, ret, "KIV");
goto local_abort; goto local_abort;
case -EIO:
pr_err("kAFS: Call %u in bad state %u\n",
call->debug_id, state);
/* Fall through */
case -ENODATA: case -ENODATA:
case -EBADMSG: case -EBADMSG:
case -EMSGSIZE: case -EMSGSIZE:
@ -517,12 +546,14 @@ static void afs_deliver_to_call(struct afs_call *call)
if (state != AFS_CALL_CL_AWAIT_REPLY) if (state != AFS_CALL_CL_AWAIT_REPLY)
abort_code = RXGEN_SS_UNMARSHAL; abort_code = RXGEN_SS_UNMARSHAL;
rxrpc_kernel_abort_call(call->net->socket, call->rxcall, rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, -EBADMSG, "KUM"); abort_code, ret, "KUM");
goto local_abort; goto local_abort;
} }
} }
done: done:
if (call->type->done)
call->type->done(call);
if (state == AFS_CALL_COMPLETE && call->incoming) if (state == AFS_CALL_COMPLETE && call->incoming)
afs_put_call(call); afs_put_call(call);
out: out:
@ -728,6 +759,7 @@ void afs_charge_preallocation(struct work_struct *work)
call->async = true; call->async = true;
call->state = AFS_CALL_SV_AWAIT_OP_ID; call->state = AFS_CALL_SV_AWAIT_OP_ID;
init_waitqueue_head(&call->waitq); init_waitqueue_head(&call->waitq);
afs_extract_to_tmp(call);
} }
if (rxrpc_kernel_charge_accept(net->socket, if (rxrpc_kernel_charge_accept(net->socket,
@ -773,18 +805,15 @@ static int afs_deliver_cm_op_id(struct afs_call *call)
{ {
int ret; int ret;
_enter("{%zu}", call->offset); _enter("{%zu}", iov_iter_count(call->_iter));
ASSERTCMP(call->offset, <, 4);
/* the operation ID forms the first four bytes of the request data */ /* the operation ID forms the first four bytes of the request data */
ret = afs_extract_data(call, &call->tmp, 4, true); ret = afs_extract_data(call, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
call->operation_ID = ntohl(call->tmp); call->operation_ID = ntohl(call->tmp);
afs_set_call_state(call, AFS_CALL_SV_AWAIT_OP_ID, AFS_CALL_SV_AWAIT_REQUEST); afs_set_call_state(call, AFS_CALL_SV_AWAIT_OP_ID, AFS_CALL_SV_AWAIT_REQUEST);
call->offset = 0;
/* ask the cache manager to route the call (it'll change the call type /* ask the cache manager to route the call (it'll change the call type
* if successful) */ * if successful) */
@ -825,7 +854,7 @@ void afs_send_empty_reply(struct afs_call *call)
msg.msg_name = NULL; msg.msg_name = NULL;
msg.msg_namelen = 0; msg.msg_namelen = 0;
iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, NULL, 0, 0); iov_iter_kvec(&msg.msg_iter, WRITE, NULL, 0, 0);
msg.msg_control = NULL; msg.msg_control = NULL;
msg.msg_controllen = 0; msg.msg_controllen = 0;
msg.msg_flags = 0; msg.msg_flags = 0;
@ -864,7 +893,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
iov[0].iov_len = len; iov[0].iov_len = len;
msg.msg_name = NULL; msg.msg_name = NULL;
msg.msg_namelen = 0; msg.msg_namelen = 0;
iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, len); iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
msg.msg_control = NULL; msg.msg_control = NULL;
msg.msg_controllen = 0; msg.msg_controllen = 0;
msg.msg_flags = 0; msg.msg_flags = 0;
@ -888,30 +917,19 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
/* /*
* Extract a piece of data from the received data socket buffers. * Extract a piece of data from the received data socket buffers.
*/ */
int afs_extract_data(struct afs_call *call, void *buf, size_t count, int afs_extract_data(struct afs_call *call, bool want_more)
bool want_more)
{ {
struct afs_net *net = call->net; struct afs_net *net = call->net;
struct iov_iter iter; struct iov_iter *iter = call->_iter;
struct kvec iov;
enum afs_call_state state; enum afs_call_state state;
u32 remote_abort = 0; u32 remote_abort = 0;
int ret; int ret;
_enter("{%s,%zu},,%zu,%d", _enter("{%s,%zu},%d", call->type->name, iov_iter_count(iter), want_more);
call->type->name, call->offset, count, want_more);
ASSERTCMP(call->offset, <=, count); ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter,
iov.iov_base = buf + call->offset;
iov.iov_len = count - call->offset;
iov_iter_kvec(&iter, ITER_KVEC | READ, &iov, 1, count - call->offset);
ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, &iter,
want_more, &remote_abort, want_more, &remote_abort,
&call->service_id); &call->service_id);
call->offset += (count - call->offset) - iov_iter_count(&iter);
trace_afs_recv_data(call, count, call->offset, want_more, ret);
if (ret == 0 || ret == -EAGAIN) if (ret == 0 || ret == -EAGAIN)
return ret; return ret;
@ -926,7 +944,7 @@ int afs_extract_data(struct afs_call *call, void *buf, size_t count,
break; break;
case AFS_CALL_COMPLETE: case AFS_CALL_COMPLETE:
kdebug("prem complete %d", call->error); kdebug("prem complete %d", call->error);
return -EIO; return afs_io_error(call, afs_io_error_extract);
default: default:
break; break;
} }
@ -940,8 +958,9 @@ int afs_extract_data(struct afs_call *call, void *buf, size_t count,
/* /*
* Log protocol error production. * Log protocol error production.
*/ */
noinline int afs_protocol_error(struct afs_call *call, int error) noinline int afs_protocol_error(struct afs_call *call, int error,
enum afs_eproto_cause cause)
{ {
trace_afs_protocol_error(call, error, __builtin_return_address(0)); trace_afs_protocol_error(call, error, cause);
return error; return error;
} }

View File

@ -126,7 +126,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
bool changed = false; bool changed = false;
int i, j; int i, j;
_enter("{%x:%u},%x,%x", _enter("{%llx:%llu},%x,%x",
vnode->fid.vid, vnode->fid.vnode, key_serial(key), caller_access); vnode->fid.vid, vnode->fid.vnode, key_serial(key), caller_access);
rcu_read_lock(); rcu_read_lock();
@ -147,7 +147,8 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
break; break;
} }
if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest)) { if (afs_cb_is_broken(cb_break, vnode,
vnode->cb_interest)) {
changed = true; changed = true;
break; break;
} }
@ -177,7 +178,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
} }
} }
if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest)) if (afs_cb_is_broken(cb_break, vnode, vnode->cb_interest))
goto someone_else_changed_it; goto someone_else_changed_it;
/* We need a ref on any permits list we want to copy as we'll have to /* We need a ref on any permits list we want to copy as we'll have to
@ -256,7 +257,7 @@ found:
spin_lock(&vnode->lock); spin_lock(&vnode->lock);
zap = rcu_access_pointer(vnode->permit_cache); zap = rcu_access_pointer(vnode->permit_cache);
if (cb_break == afs_cb_break_sum(vnode, vnode->cb_interest) && if (!afs_cb_is_broken(cb_break, vnode, vnode->cb_interest) &&
zap == permits) zap == permits)
rcu_assign_pointer(vnode->permit_cache, replacement); rcu_assign_pointer(vnode->permit_cache, replacement);
else else
@ -289,7 +290,7 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key,
bool valid = false; bool valid = false;
int i, ret; int i, ret;
_enter("{%x:%u},%x", _enter("{%llx:%llu},%x",
vnode->fid.vid, vnode->fid.vnode, key_serial(key)); vnode->fid.vid, vnode->fid.vnode, key_serial(key));
/* check the permits to see if we've got one yet */ /* check the permits to see if we've got one yet */
@ -349,7 +350,7 @@ int afs_permission(struct inode *inode, int mask)
if (mask & MAY_NOT_BLOCK) if (mask & MAY_NOT_BLOCK)
return -ECHILD; return -ECHILD;
_enter("{{%x:%u},%lx},%x,", _enter("{{%llx:%llu},%lx},%x,",
vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
key = afs_request_key(vnode->volume->cell); key = afs_request_key(vnode->volume->cell);

View File

@ -13,6 +13,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "afs_fs.h" #include "afs_fs.h"
#include "internal.h" #include "internal.h"
#include "protocol_yfs.h"
static unsigned afs_server_gc_delay = 10; /* Server record timeout in seconds */ static unsigned afs_server_gc_delay = 10; /* Server record timeout in seconds */
static unsigned afs_server_update_delay = 30; /* Time till VLDB recheck in secs */ static unsigned afs_server_update_delay = 30; /* Time till VLDB recheck in secs */
@ -230,6 +231,8 @@ static struct afs_server *afs_alloc_server(struct afs_net *net,
rwlock_init(&server->fs_lock); rwlock_init(&server->fs_lock);
INIT_HLIST_HEAD(&server->cb_volumes); INIT_HLIST_HEAD(&server->cb_volumes);
rwlock_init(&server->cb_break_lock); rwlock_init(&server->cb_break_lock);
init_waitqueue_head(&server->probe_wq);
spin_lock_init(&server->probe_lock);
afs_inc_servers_outstanding(net); afs_inc_servers_outstanding(net);
_leave(" = %p", server); _leave(" = %p", server);
@ -246,41 +249,23 @@ enomem:
static struct afs_addr_list *afs_vl_lookup_addrs(struct afs_cell *cell, static struct afs_addr_list *afs_vl_lookup_addrs(struct afs_cell *cell,
struct key *key, const uuid_t *uuid) struct key *key, const uuid_t *uuid)
{ {
struct afs_addr_cursor ac; struct afs_vl_cursor vc;
struct afs_addr_list *alist; struct afs_addr_list *alist = NULL;
int ret; int ret;
ret = afs_set_vl_cursor(&ac, cell); ret = -ERESTARTSYS;
if (ret < 0) if (afs_begin_vlserver_operation(&vc, cell, key)) {
return ERR_PTR(ret); while (afs_select_vlserver(&vc)) {
if (test_bit(AFS_VLSERVER_FL_IS_YFS, &vc.server->flags))
while (afs_iterate_addresses(&ac)) { alist = afs_yfsvl_get_endpoints(&vc, uuid);
if (test_bit(ac.index, &ac.alist->yfs))
alist = afs_yfsvl_get_endpoints(cell->net, &ac, key, uuid);
else else
alist = afs_vl_get_addrs_u(cell->net, &ac, key, uuid); alist = afs_vl_get_addrs_u(&vc, uuid);
switch (ac.error) {
case 0:
afs_end_cursor(&ac);
return alist;
case -ECONNABORTED:
ac.error = afs_abort_to_error(ac.abort_code);
goto error;
case -ENOMEM:
case -ENONET:
goto error;
case -ENETUNREACH:
case -EHOSTUNREACH:
case -ECONNREFUSED:
break;
default:
ac.error = -EIO;
goto error;
}
} }
error: ret = afs_end_vlserver_operation(&vc);
return ERR_PTR(afs_end_cursor(&ac)); }
return ret < 0 ? ERR_PTR(ret) : alist;
} }
/* /*
@ -382,9 +367,7 @@ static void afs_destroy_server(struct afs_net *net, struct afs_server *server)
struct afs_addr_list *alist = rcu_access_pointer(server->addresses); struct afs_addr_list *alist = rcu_access_pointer(server->addresses);
struct afs_addr_cursor ac = { struct afs_addr_cursor ac = {
.alist = alist, .alist = alist,
.start = alist->index, .index = alist->preferred,
.index = 0,
.addr = &alist->addrs[alist->index],
.error = 0, .error = 0,
}; };
_enter("%p", server); _enter("%p", server);
@ -392,6 +375,9 @@ static void afs_destroy_server(struct afs_net *net, struct afs_server *server)
if (test_bit(AFS_SERVER_FL_MAY_HAVE_CB, &server->flags)) if (test_bit(AFS_SERVER_FL_MAY_HAVE_CB, &server->flags))
afs_fs_give_up_all_callbacks(net, server, &ac, NULL); afs_fs_give_up_all_callbacks(net, server, &ac, NULL);
wait_var_event(&server->probe_outstanding,
atomic_read(&server->probe_outstanding) == 0);
call_rcu(&server->rcu, afs_server_rcu); call_rcu(&server->rcu, afs_server_rcu);
afs_dec_servers_outstanding(net); afs_dec_servers_outstanding(net);
} }
@ -524,99 +510,6 @@ void afs_purge_servers(struct afs_net *net)
_leave(""); _leave("");
} }
/*
* Probe a fileserver to find its capabilities.
*
* TODO: Try service upgrade.
*/
static bool afs_do_probe_fileserver(struct afs_fs_cursor *fc)
{
_enter("");
fc->ac.addr = NULL;
fc->ac.start = READ_ONCE(fc->ac.alist->index);
fc->ac.index = fc->ac.start;
fc->ac.error = 0;
fc->ac.begun = false;
while (afs_iterate_addresses(&fc->ac)) {
afs_fs_get_capabilities(afs_v2net(fc->vnode), fc->cbi->server,
&fc->ac, fc->key);
switch (fc->ac.error) {
case 0:
afs_end_cursor(&fc->ac);
set_bit(AFS_SERVER_FL_PROBED, &fc->cbi->server->flags);
return true;
case -ECONNABORTED:
fc->ac.error = afs_abort_to_error(fc->ac.abort_code);
goto error;
case -ENOMEM:
case -ENONET:
goto error;
case -ENETUNREACH:
case -EHOSTUNREACH:
case -ECONNREFUSED:
case -ETIMEDOUT:
case -ETIME:
break;
default:
fc->ac.error = -EIO;
goto error;
}
}
error:
afs_end_cursor(&fc->ac);
return false;
}
/*
* If we haven't already, try probing the fileserver to get its capabilities.
* We try not to instigate parallel probes, but it's possible that the parallel
* probes will fail due to authentication failure when ours would succeed.
*
* TODO: Try sending an anonymous probe if an authenticated probe fails.
*/
bool afs_probe_fileserver(struct afs_fs_cursor *fc)
{
bool success;
int ret, retries = 0;
_enter("");
retry:
if (test_bit(AFS_SERVER_FL_PROBED, &fc->cbi->server->flags)) {
_leave(" = t");
return true;
}
if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &fc->cbi->server->flags)) {
success = afs_do_probe_fileserver(fc);
clear_bit_unlock(AFS_SERVER_FL_PROBING, &fc->cbi->server->flags);
wake_up_bit(&fc->cbi->server->flags, AFS_SERVER_FL_PROBING);
_leave(" = t");
return success;
}
_debug("wait");
ret = wait_on_bit(&fc->cbi->server->flags, AFS_SERVER_FL_PROBING,
TASK_INTERRUPTIBLE);
if (ret == -ERESTARTSYS) {
fc->ac.error = ret;
_leave(" = f [%d]", ret);
return false;
}
retries++;
if (retries == 4) {
fc->ac.error = -ESTALE;
_leave(" = f [stale]");
return false;
}
_debug("retry");
goto retry;
}
/* /*
* Get an update for a server's address list. * Get an update for a server's address list.
*/ */

View File

@ -118,11 +118,11 @@ bool afs_annotate_server_list(struct afs_server_list *new,
return false; return false;
changed: changed:
/* Maintain the same current server as before if possible. */ /* Maintain the same preferred server as before if possible. */
cur = old->servers[old->index].server; cur = old->servers[old->preferred].server;
for (j = 0; j < new->nr_servers; j++) { for (j = 0; j < new->nr_servers; j++) {
if (new->servers[j].server == cur) { if (new->servers[j].server == cur) {
new->index = j; new->preferred = j;
break; break;
} }
} }

View File

@ -406,10 +406,11 @@ static int afs_fill_super(struct super_block *sb,
inode = afs_iget_pseudo_dir(sb, true); inode = afs_iget_pseudo_dir(sb, true);
sb->s_flags |= SB_RDONLY; sb->s_flags |= SB_RDONLY;
} else { } else {
sprintf(sb->s_id, "%u", as->volume->vid); sprintf(sb->s_id, "%llu", as->volume->vid);
afs_activate_volume(as->volume); afs_activate_volume(as->volume);
fid.vid = as->volume->vid; fid.vid = as->volume->vid;
fid.vnode = 1; fid.vnode = 1;
fid.vnode_hi = 0;
fid.unique = 1; fid.unique = 1;
inode = afs_iget(sb, params->key, &fid, NULL, NULL, NULL); inode = afs_iget(sb, params->key, &fid, NULL, NULL, NULL);
} }
@ -663,7 +664,7 @@ static void afs_destroy_inode(struct inode *inode)
{ {
struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_vnode *vnode = AFS_FS_I(inode);
_enter("%p{%x:%u}", inode, vnode->fid.vid, vnode->fid.vnode); _enter("%p{%llx:%llu}", inode, vnode->fid.vid, vnode->fid.vnode);
_debug("DESTROY INODE %p", inode); _debug("DESTROY INODE %p", inode);

340
fs/afs/vl_list.c Normal file
View File

@ -0,0 +1,340 @@
/* AFS vlserver list management.
*
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include "internal.h"
struct afs_vlserver *afs_alloc_vlserver(const char *name, size_t name_len,
unsigned short port)
{
struct afs_vlserver *vlserver;
vlserver = kzalloc(struct_size(vlserver, name, name_len + 1),
GFP_KERNEL);
if (vlserver) {
atomic_set(&vlserver->usage, 1);
rwlock_init(&vlserver->lock);
init_waitqueue_head(&vlserver->probe_wq);
spin_lock_init(&vlserver->probe_lock);
vlserver->name_len = name_len;
vlserver->port = port;
memcpy(vlserver->name, name, name_len);
}
return vlserver;
}
static void afs_vlserver_rcu(struct rcu_head *rcu)
{
struct afs_vlserver *vlserver = container_of(rcu, struct afs_vlserver, rcu);
afs_put_addrlist(rcu_access_pointer(vlserver->addresses));
kfree_rcu(vlserver, rcu);
}
void afs_put_vlserver(struct afs_net *net, struct afs_vlserver *vlserver)
{
if (vlserver) {
unsigned int u = atomic_dec_return(&vlserver->usage);
//_debug("VL PUT %p{%u}", vlserver, u);
if (u == 0)
call_rcu(&vlserver->rcu, afs_vlserver_rcu);
}
}
struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
{
struct afs_vlserver_list *vllist;
vllist = kzalloc(struct_size(vllist, servers, nr_servers), GFP_KERNEL);
if (vllist) {
atomic_set(&vllist->usage, 1);
rwlock_init(&vllist->lock);
}
return vllist;
}
void afs_put_vlserverlist(struct afs_net *net, struct afs_vlserver_list *vllist)
{
if (vllist) {
unsigned int u = atomic_dec_return(&vllist->usage);
//_debug("VLLS PUT %p{%u}", vllist, u);
if (u == 0) {
int i;
for (i = 0; i < vllist->nr_servers; i++) {
afs_put_vlserver(net, vllist->servers[i].server);
}
kfree_rcu(vllist, rcu);
}
}
}
static u16 afs_extract_le16(const u8 **_b)
{
u16 val;
val = (u16)*(*_b)++ << 0;
val |= (u16)*(*_b)++ << 8;
return val;
}
/*
* Build a VL server address list from a DNS queried server list.
*/
static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end,
u8 nr_addrs, u16 port)
{
struct afs_addr_list *alist;
const u8 *b = *_b;
int ret = -EINVAL;
alist = afs_alloc_addrlist(nr_addrs, VL_SERVICE, port);
if (!alist)
return ERR_PTR(-ENOMEM);
if (nr_addrs == 0)
return alist;
for (; nr_addrs > 0 && end - b >= nr_addrs; nr_addrs--) {
struct dns_server_list_v1_address hdr;
__be32 x[4];
hdr.address_type = *b++;
switch (hdr.address_type) {
case DNS_ADDRESS_IS_IPV4:
if (end - b < 4) {
_leave(" = -EINVAL [short inet]");
goto error;
}
memcpy(x, b, 4);
afs_merge_fs_addr4(alist, x[0], port);
b += 4;
break;
case DNS_ADDRESS_IS_IPV6:
if (end - b < 16) {
_leave(" = -EINVAL [short inet6]");
goto error;
}
memcpy(x, b, 16);
afs_merge_fs_addr6(alist, x, port);
b += 16;
break;
default:
_leave(" = -EADDRNOTAVAIL [unknown af %u]",
hdr.address_type);
ret = -EADDRNOTAVAIL;
goto error;
}
}
/* Start with IPv6 if available. */
if (alist->nr_ipv4 < alist->nr_addrs)
alist->preferred = alist->nr_ipv4;
*_b = b;
return alist;
error:
*_b = b;
afs_put_addrlist(alist);
return ERR_PTR(ret);
}
/*
* Build a VL server list from a DNS queried server list.
*/
struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
const void *buffer,
size_t buffer_size)
{
const struct dns_server_list_v1_header *hdr = buffer;
struct dns_server_list_v1_server bs;
struct afs_vlserver_list *vllist, *previous;
struct afs_addr_list *addrs;
struct afs_vlserver *server;
const u8 *b = buffer, *end = buffer + buffer_size;
int ret = -ENOMEM, nr_servers, i, j;
_enter("");
/* Check that it's a server list, v1 */
if (end - b < sizeof(*hdr) ||
hdr->hdr.content != DNS_PAYLOAD_IS_SERVER_LIST ||
hdr->hdr.version != 1) {
pr_notice("kAFS: Got DNS record [%u,%u] len %zu\n",
hdr->hdr.content, hdr->hdr.version, end - b);
ret = -EDESTADDRREQ;
goto dump;
}
nr_servers = hdr->nr_servers;
vllist = afs_alloc_vlserver_list(nr_servers);
if (!vllist)
return ERR_PTR(-ENOMEM);
vllist->source = (hdr->source < NR__dns_record_source) ?
hdr->source : NR__dns_record_source;
vllist->status = (hdr->status < NR__dns_lookup_status) ?
hdr->status : NR__dns_lookup_status;
read_lock(&cell->vl_servers_lock);
previous = afs_get_vlserverlist(
rcu_dereference_protected(cell->vl_servers,
lockdep_is_held(&cell->vl_servers_lock)));
read_unlock(&cell->vl_servers_lock);
b += sizeof(*hdr);
while (end - b >= sizeof(bs)) {
bs.name_len = afs_extract_le16(&b);
bs.priority = afs_extract_le16(&b);
bs.weight = afs_extract_le16(&b);
bs.port = afs_extract_le16(&b);
bs.source = *b++;
bs.status = *b++;
bs.protocol = *b++;
bs.nr_addrs = *b++;
_debug("extract %u %u %u %u %u %u %*.*s",
bs.name_len, bs.priority, bs.weight,
bs.port, bs.protocol, bs.nr_addrs,
bs.name_len, bs.name_len, b);
if (end - b < bs.name_len)
break;
ret = -EPROTONOSUPPORT;
if (bs.protocol == DNS_SERVER_PROTOCOL_UNSPECIFIED) {
bs.protocol = DNS_SERVER_PROTOCOL_UDP;
} else if (bs.protocol != DNS_SERVER_PROTOCOL_UDP) {
_leave(" = [proto %u]", bs.protocol);
goto error;
}
if (bs.port == 0)
bs.port = AFS_VL_PORT;
if (bs.source > NR__dns_record_source)
bs.source = NR__dns_record_source;
if (bs.status > NR__dns_lookup_status)
bs.status = NR__dns_lookup_status;
server = NULL;
if (previous) {
/* See if we can update an old server record */
for (i = 0; i < previous->nr_servers; i++) {
struct afs_vlserver *p = previous->servers[i].server;
if (p->name_len == bs.name_len &&
p->port == bs.port &&
strncasecmp(b, p->name, bs.name_len) == 0) {
server = afs_get_vlserver(p);
break;
}
}
}
if (!server) {
ret = -ENOMEM;
server = afs_alloc_vlserver(b, bs.name_len, bs.port);
if (!server)
goto error;
}
b += bs.name_len;
/* Extract the addresses - note that we can't skip this as we
* have to advance the payload pointer.
*/
addrs = afs_extract_vl_addrs(&b, end, bs.nr_addrs, bs.port);
if (IS_ERR(addrs)) {
ret = PTR_ERR(addrs);
goto error_2;
}
if (vllist->nr_servers >= nr_servers) {
_debug("skip %u >= %u", vllist->nr_servers, nr_servers);
afs_put_addrlist(addrs);
afs_put_vlserver(cell->net, server);
continue;
}
addrs->source = bs.source;
addrs->status = bs.status;
if (addrs->nr_addrs == 0) {
afs_put_addrlist(addrs);
if (!rcu_access_pointer(server->addresses)) {
afs_put_vlserver(cell->net, server);
continue;
}
} else {
struct afs_addr_list *old = addrs;
write_lock(&server->lock);
rcu_swap_protected(server->addresses, old,
lockdep_is_held(&server->lock));
write_unlock(&server->lock);
afs_put_addrlist(old);
}
/* TODO: Might want to check for duplicates */
/* Insertion-sort by priority and weight */
for (j = 0; j < vllist->nr_servers; j++) {
if (bs.priority < vllist->servers[j].priority)
break; /* Lower preferable */
if (bs.priority == vllist->servers[j].priority &&
bs.weight > vllist->servers[j].weight)
break; /* Higher preferable */
}
if (j < vllist->nr_servers) {
memmove(vllist->servers + j + 1,
vllist->servers + j,
(vllist->nr_servers - j) * sizeof(struct afs_vlserver_entry));
}
clear_bit(AFS_VLSERVER_FL_PROBED, &server->flags);
vllist->servers[j].priority = bs.priority;
vllist->servers[j].weight = bs.weight;
vllist->servers[j].server = server;
vllist->nr_servers++;
}
if (b != end) {
_debug("parse error %zd", b - end);
goto error;
}
afs_put_vlserverlist(cell->net, previous);
_leave(" = ok [%u]", vllist->nr_servers);
return vllist;
error_2:
afs_put_vlserver(cell->net, server);
error:
afs_put_vlserverlist(cell->net, vllist);
afs_put_vlserverlist(cell->net, previous);
dump:
if (ret != -ENOMEM) {
printk(KERN_DEBUG "DNS: at %zu\n", (const void *)b - buffer);
print_hex_dump_bytes("DNS: ", DUMP_PREFIX_NONE, buffer, buffer_size);
}
return ERR_PTR(ret);
}

273
fs/afs/vl_probe.c Normal file
View File

@ -0,0 +1,273 @@
/* AFS vlserver probing
*
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/sched.h>
#include <linux/slab.h>
#include "afs_fs.h"
#include "internal.h"
#include "protocol_yfs.h"
static bool afs_vl_probe_done(struct afs_vlserver *server)
{
if (!atomic_dec_and_test(&server->probe_outstanding))
return false;
wake_up_var(&server->probe_outstanding);
clear_bit_unlock(AFS_VLSERVER_FL_PROBING, &server->flags);
wake_up_bit(&server->flags, AFS_VLSERVER_FL_PROBING);
return true;
}
/*
* Process the result of probing a vlserver. This is called after successful
* or failed delivery of an VL.GetCapabilities operation.
*/
void afs_vlserver_probe_result(struct afs_call *call)
{
struct afs_addr_list *alist = call->alist;
struct afs_vlserver *server = call->reply[0];
unsigned int server_index = (long)call->reply[1];
unsigned int index = call->addr_ix;
unsigned int rtt = UINT_MAX;
bool have_result = false;
u64 _rtt;
int ret = call->error;
_enter("%s,%u,%u,%d,%d", server->name, server_index, index, ret, call->abort_code);
spin_lock(&server->probe_lock);
switch (ret) {
case 0:
server->probe.error = 0;
goto responded;
case -ECONNABORTED:
if (!server->probe.responded) {
server->probe.abort_code = call->abort_code;
server->probe.error = ret;
}
goto responded;
case -ENOMEM:
case -ENONET:
server->probe.local_failure = true;
afs_io_error(call, afs_io_error_vl_probe_fail);
goto out;
case -ECONNRESET: /* Responded, but call expired. */
case -ENETUNREACH:
case -EHOSTUNREACH:
case -ECONNREFUSED:
case -ETIMEDOUT:
case -ETIME:
default:
clear_bit(index, &alist->responded);
set_bit(index, &alist->failed);
if (!server->probe.responded &&
(server->probe.error == 0 ||
server->probe.error == -ETIMEDOUT ||
server->probe.error == -ETIME))
server->probe.error = ret;
afs_io_error(call, afs_io_error_vl_probe_fail);
goto out;
}
responded:
set_bit(index, &alist->responded);
clear_bit(index, &alist->failed);
if (call->service_id == YFS_VL_SERVICE) {
server->probe.is_yfs = true;
set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
alist->addrs[index].srx_service = call->service_id;
} else {
server->probe.not_yfs = true;
if (!server->probe.is_yfs) {
clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
alist->addrs[index].srx_service = call->service_id;
}
}
/* Get the RTT and scale it to fit into a 32-bit value that represents
* over a minute of time so that we can access it with one instruction
* on a 32-bit system.
*/
_rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall);
_rtt /= 64;
rtt = (_rtt > UINT_MAX) ? UINT_MAX : _rtt;
if (rtt < server->probe.rtt) {
server->probe.rtt = rtt;
alist->preferred = index;
have_result = true;
}
smp_wmb(); /* Set rtt before responded. */
server->probe.responded = true;
set_bit(AFS_VLSERVER_FL_PROBED, &server->flags);
out:
spin_unlock(&server->probe_lock);
_debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
server_index, index, &alist->addrs[index].transport,
(unsigned int)rtt, ret);
have_result |= afs_vl_probe_done(server);
if (have_result) {
server->probe.have_result = true;
wake_up_var(&server->probe.have_result);
wake_up_all(&server->probe_wq);
}
}
/*
* Probe all of a vlserver's addresses to find out the best route and to
* query its capabilities.
*/
static int afs_do_probe_vlserver(struct afs_net *net,
struct afs_vlserver *server,
struct key *key,
unsigned int server_index)
{
struct afs_addr_cursor ac = {
.index = 0,
};
int ret;
_enter("%s", server->name);
read_lock(&server->lock);
ac.alist = rcu_dereference_protected(server->addresses,
lockdep_is_held(&server->lock));
read_unlock(&server->lock);
atomic_set(&server->probe_outstanding, ac.alist->nr_addrs);
memset(&server->probe, 0, sizeof(server->probe));
server->probe.rtt = UINT_MAX;
for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) {
ret = afs_vl_get_capabilities(net, &ac, key, server,
server_index, true);
if (ret != -EINPROGRESS) {
afs_vl_probe_done(server);
return ret;
}
}
return 0;
}
/*
* Send off probes to all unprobed servers.
*/
int afs_send_vl_probes(struct afs_net *net, struct key *key,
struct afs_vlserver_list *vllist)
{
struct afs_vlserver *server;
int i, ret;
for (i = 0; i < vllist->nr_servers; i++) {
server = vllist->servers[i].server;
if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags))
continue;
if (!test_and_set_bit_lock(AFS_VLSERVER_FL_PROBING, &server->flags)) {
ret = afs_do_probe_vlserver(net, server, key, i);
if (ret)
return ret;
}
}
return 0;
}
/*
* Wait for the first as-yet untried server to respond.
*/
int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist,
unsigned long untried)
{
struct wait_queue_entry *waits;
struct afs_vlserver *server;
unsigned int rtt = UINT_MAX;
bool have_responders = false;
int pref = -1, i;
_enter("%u,%lx", vllist->nr_servers, untried);
/* Only wait for servers that have a probe outstanding. */
for (i = 0; i < vllist->nr_servers; i++) {
if (test_bit(i, &untried)) {
server = vllist->servers[i].server;
if (!test_bit(AFS_VLSERVER_FL_PROBING, &server->flags))
__clear_bit(i, &untried);
if (server->probe.responded)
have_responders = true;
}
}
if (have_responders || !untried)
return 0;
waits = kmalloc(array_size(vllist->nr_servers, sizeof(*waits)), GFP_KERNEL);
if (!waits)
return -ENOMEM;
for (i = 0; i < vllist->nr_servers; i++) {
if (test_bit(i, &untried)) {
server = vllist->servers[i].server;
init_waitqueue_entry(&waits[i], current);
add_wait_queue(&server->probe_wq, &waits[i]);
}
}
for (;;) {
bool still_probing = false;
set_current_state(TASK_INTERRUPTIBLE);
for (i = 0; i < vllist->nr_servers; i++) {
if (test_bit(i, &untried)) {
server = vllist->servers[i].server;
if (server->probe.responded)
goto stop;
if (test_bit(AFS_VLSERVER_FL_PROBING, &server->flags))
still_probing = true;
}
}
if (!still_probing || unlikely(signal_pending(current)))
goto stop;
schedule();
}
stop:
set_current_state(TASK_RUNNING);
for (i = 0; i < vllist->nr_servers; i++) {
if (test_bit(i, &untried)) {
server = vllist->servers[i].server;
if (server->probe.responded &&
server->probe.rtt < rtt) {
pref = i;
rtt = server->probe.rtt;
}
remove_wait_queue(&server->probe_wq, &waits[i]);
}
}
kfree(waits);
if (pref == -1 && signal_pending(current))
return -ERESTARTSYS;
if (pref >= 0)
vllist->preferred = pref;
_leave(" = 0 [%u]", pref);
return 0;
}

355
fs/afs/vl_rotate.c Normal file
View File

@ -0,0 +1,355 @@
/* Handle vlserver selection and rotation.
*
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include "internal.h"
#include "afs_vl.h"
/*
* Begin an operation on a volume location server.
*/
bool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cell,
struct key *key)
{
memset(vc, 0, sizeof(*vc));
vc->cell = cell;
vc->key = key;
vc->error = -EDESTADDRREQ;
vc->ac.error = SHRT_MAX;
if (signal_pending(current)) {
vc->error = -EINTR;
vc->flags |= AFS_VL_CURSOR_STOP;
return false;
}
return true;
}
/*
* Begin iteration through a server list, starting with the last used server if
* possible, or the last recorded good server if not.
*/
static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
{
struct afs_cell *cell = vc->cell;
if (wait_on_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET,
TASK_INTERRUPTIBLE)) {
vc->error = -ERESTARTSYS;
return false;
}
read_lock(&cell->vl_servers_lock);
vc->server_list = afs_get_vlserverlist(
rcu_dereference_protected(cell->vl_servers,
lockdep_is_held(&cell->vl_servers_lock)));
read_unlock(&cell->vl_servers_lock);
if (!vc->server_list || !vc->server_list->nr_servers)
return false;
vc->untried = (1UL << vc->server_list->nr_servers) - 1;
vc->index = -1;
return true;
}
/*
* Select the vlserver to use. May be called multiple times to rotate
* through the vlservers.
*/
bool afs_select_vlserver(struct afs_vl_cursor *vc)
{
struct afs_addr_list *alist;
struct afs_vlserver *vlserver;
u32 rtt;
int error = vc->ac.error, abort_code, i;
_enter("%lx[%d],%lx[%d],%d,%d",
vc->untried, vc->index,
vc->ac.tried, vc->ac.index,
error, vc->ac.abort_code);
if (vc->flags & AFS_VL_CURSOR_STOP) {
_leave(" = f [stopped]");
return false;
}
vc->nr_iterations++;
/* Evaluate the result of the previous operation, if there was one. */
switch (error) {
case SHRT_MAX:
goto start;
default:
case 0:
/* Success or local failure. Stop. */
vc->error = error;
vc->flags |= AFS_VL_CURSOR_STOP;
_leave(" = f [okay/local %d]", vc->ac.error);
return false;
case -ECONNABORTED:
/* The far side rejected the operation on some grounds. This
* might involve the server being busy or the volume having been moved.
*/
switch (vc->ac.abort_code) {
case AFSVL_IO:
case AFSVL_BADVOLOPER:
case AFSVL_NOMEM:
/* The server went weird. */
vc->error = -EREMOTEIO;
//write_lock(&vc->cell->vl_servers_lock);
//vc->server_list->weird_mask |= 1 << vc->index;
//write_unlock(&vc->cell->vl_servers_lock);
goto next_server;
default:
vc->error = afs_abort_to_error(vc->ac.abort_code);
goto failed;
}
case -ENETUNREACH:
case -EHOSTUNREACH:
case -ECONNREFUSED:
case -ETIMEDOUT:
case -ETIME:
_debug("no conn %d", error);
vc->error = error;
goto iterate_address;
case -ECONNRESET:
_debug("call reset");
vc->error = error;
vc->flags |= AFS_VL_CURSOR_RETRY;
goto next_server;
}
restart_from_beginning:
_debug("restart");
afs_end_cursor(&vc->ac);
afs_put_vlserverlist(vc->cell->net, vc->server_list);
vc->server_list = NULL;
if (vc->flags & AFS_VL_CURSOR_RETRIED)
goto failed;
vc->flags |= AFS_VL_CURSOR_RETRIED;
start:
_debug("start");
if (!afs_start_vl_iteration(vc))
goto failed;
error = afs_send_vl_probes(vc->cell->net, vc->key, vc->server_list);
if (error < 0)
goto failed_set_error;
pick_server:
_debug("pick [%lx]", vc->untried);
error = afs_wait_for_vl_probes(vc->server_list, vc->untried);
if (error < 0)
goto failed_set_error;
/* Pick the untried server with the lowest RTT. */
vc->index = vc->server_list->preferred;
if (test_bit(vc->index, &vc->untried))
goto selected_server;
vc->index = -1;
rtt = U32_MAX;
for (i = 0; i < vc->server_list->nr_servers; i++) {
struct afs_vlserver *s = vc->server_list->servers[i].server;
if (!test_bit(i, &vc->untried) || !s->probe.responded)
continue;
if (s->probe.rtt < rtt) {
vc->index = i;
rtt = s->probe.rtt;
}
}
if (vc->index == -1)
goto no_more_servers;
selected_server:
_debug("use %d", vc->index);
__clear_bit(vc->index, &vc->untried);
/* We're starting on a different vlserver from the list. We need to
* check it, find its address list and probe its capabilities before we
* use it.
*/
ASSERTCMP(vc->ac.alist, ==, NULL);
vlserver = vc->server_list->servers[vc->index].server;
vc->server = vlserver;
_debug("USING VLSERVER: %s", vlserver->name);
read_lock(&vlserver->lock);
alist = rcu_dereference_protected(vlserver->addresses,
lockdep_is_held(&vlserver->lock));
afs_get_addrlist(alist);
read_unlock(&vlserver->lock);
memset(&vc->ac, 0, sizeof(vc->ac));
if (!vc->ac.alist)
vc->ac.alist = alist;
else
afs_put_addrlist(alist);
vc->ac.index = -1;
iterate_address:
ASSERT(vc->ac.alist);
/* Iterate over the current server's address list to try and find an
* address on which it will respond to us.
*/
if (!afs_iterate_addresses(&vc->ac))
goto next_server;
_debug("VL address %d/%d", vc->ac.index, vc->ac.alist->nr_addrs);
_leave(" = t %pISpc", &vc->ac.alist->addrs[vc->ac.index].transport);
return true;
next_server:
_debug("next");
afs_end_cursor(&vc->ac);
goto pick_server;
no_more_servers:
/* That's all the servers poked to no good effect. Try again if some
* of them were busy.
*/
if (vc->flags & AFS_VL_CURSOR_RETRY)
goto restart_from_beginning;
abort_code = 0;
error = -EDESTADDRREQ;
for (i = 0; i < vc->server_list->nr_servers; i++) {
struct afs_vlserver *s = vc->server_list->servers[i].server;
int probe_error = READ_ONCE(s->probe.error);
switch (probe_error) {
case 0:
continue;
default:
if (error == -ETIMEDOUT ||
error == -ETIME)
continue;
case -ETIMEDOUT:
case -ETIME:
if (error == -ENOMEM ||
error == -ENONET)
continue;
case -ENOMEM:
case -ENONET:
if (error == -ENETUNREACH)
continue;
case -ENETUNREACH:
if (error == -EHOSTUNREACH)
continue;
case -EHOSTUNREACH:
if (error == -ECONNREFUSED)
continue;
case -ECONNREFUSED:
if (error == -ECONNRESET)
continue;
case -ECONNRESET: /* Responded, but call expired. */
if (error == -ECONNABORTED)
continue;
case -ECONNABORTED:
abort_code = s->probe.abort_code;
error = probe_error;
continue;
}
}
if (error == -ECONNABORTED)
error = afs_abort_to_error(abort_code);
failed_set_error:
vc->error = error;
failed:
vc->flags |= AFS_VL_CURSOR_STOP;
afs_end_cursor(&vc->ac);
_leave(" = f [failed %d]", vc->error);
return false;
}
/*
* Dump cursor state in the case of the error being EDESTADDRREQ.
*/
static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc)
{
static int count;
int i;
if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3)
return;
count++;
rcu_read_lock();
pr_notice("EDESTADDR occurred\n");
pr_notice("VC: ut=%lx ix=%u ni=%hu fl=%hx err=%hd\n",
vc->untried, vc->index, vc->nr_iterations, vc->flags, vc->error);
if (vc->server_list) {
const struct afs_vlserver_list *sl = vc->server_list;
pr_notice("VC: SL nr=%u ix=%u\n",
sl->nr_servers, sl->index);
for (i = 0; i < sl->nr_servers; i++) {
const struct afs_vlserver *s = sl->servers[i].server;
pr_notice("VC: server %s+%hu fl=%lx E=%hd\n",
s->name, s->port, s->flags, s->probe.error);
if (s->addresses) {
const struct afs_addr_list *a =
rcu_dereference(s->addresses);
pr_notice("VC: - nr=%u/%u/%u pf=%u\n",
a->nr_ipv4, a->nr_addrs, a->max_addrs,
a->preferred);
pr_notice("VC: - pr=%lx R=%lx F=%lx\n",
a->probed, a->responded, a->failed);
if (a == vc->ac.alist)
pr_notice("VC: - current\n");
}
}
}
pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
vc->ac.tried, vc->ac.index, vc->ac.abort_code, vc->ac.error,
vc->ac.responded, vc->ac.nr_iterations);
rcu_read_unlock();
}
/*
* Tidy up a volume location server cursor and unlock the vnode.
*/
int afs_end_vlserver_operation(struct afs_vl_cursor *vc)
{
struct afs_net *net = vc->cell->net;
if (vc->error == -EDESTADDRREQ ||
vc->error == -ENETUNREACH ||
vc->error == -EHOSTUNREACH)
afs_vl_dump_edestaddrreq(vc);
afs_end_cursor(&vc->ac);
afs_put_vlserverlist(net, vc->server_list);
if (vc->error == -ECONNABORTED)
vc->error = afs_abort_to_error(vc->ac.abort_code);
return vc->error;
}

View File

@ -128,14 +128,13 @@ static const struct afs_call_type afs_RXVLGetEntryByNameU = {
* Dispatch a get volume entry by name or ID operation (uuid variant). If the * Dispatch a get volume entry by name or ID operation (uuid variant). If the
* volname is a decimal number then it's a volume ID not a volume name. * volname is a decimal number then it's a volume ID not a volume name.
*/ */
struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net, struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
struct afs_addr_cursor *ac,
struct key *key,
const char *volname, const char *volname,
int volnamesz) int volnamesz)
{ {
struct afs_vldb_entry *entry; struct afs_vldb_entry *entry;
struct afs_call *call; struct afs_call *call;
struct afs_net *net = vc->cell->net;
size_t reqsz, padsz; size_t reqsz, padsz;
__be32 *bp; __be32 *bp;
@ -155,7 +154,7 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
call->key = key; call->key = vc->key;
call->reply[0] = entry; call->reply[0] = entry;
call->ret_reply0 = true; call->ret_reply0 = true;
@ -168,7 +167,7 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net,
memset((void *)bp + volnamesz, 0, padsz); memset((void *)bp + volnamesz, 0, padsz);
trace_afs_make_vl_call(call); trace_afs_make_vl_call(call);
return (struct afs_vldb_entry *)afs_make_call(ac, call, GFP_KERNEL, false); return (struct afs_vldb_entry *)afs_make_call(&vc->ac, call, GFP_KERNEL, false);
} }
/* /*
@ -187,19 +186,18 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
u32 uniquifier, nentries, count; u32 uniquifier, nentries, count;
int i, ret; int i, ret;
_enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count); _enter("{%u,%zu/%u}",
call->unmarshall, iov_iter_count(call->_iter), call->count);
again:
switch (call->unmarshall) { switch (call->unmarshall) {
case 0: case 0:
call->offset = 0; afs_extract_to_buf(call,
sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
call->unmarshall++; call->unmarshall++;
/* Extract the returned uuid, uniquifier, nentries and blkaddrs size */ /* Extract the returned uuid, uniquifier, nentries and blkaddrs size */
case 1: case 1:
ret = afs_extract_data(call, call->buffer, ret = afs_extract_data(call, true);
sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32),
true);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -216,28 +214,28 @@ again:
call->reply[0] = alist; call->reply[0] = alist;
call->count = count; call->count = count;
call->count2 = nentries; call->count2 = nentries;
call->offset = 0;
call->unmarshall++; call->unmarshall++;
more_entries:
count = min(call->count, 4U);
afs_extract_to_buf(call, count * sizeof(__be32));
/* Extract entries */ /* Extract entries */
case 2: case 2:
count = min(call->count, 4U); ret = afs_extract_data(call, call->count > 4);
ret = afs_extract_data(call, call->buffer,
count * sizeof(__be32),
call->count > 4);
if (ret < 0) if (ret < 0)
return ret; return ret;
alist = call->reply[0]; alist = call->reply[0];
bp = call->buffer; bp = call->buffer;
count = min(call->count, 4U);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
if (alist->nr_addrs < call->count2) if (alist->nr_addrs < call->count2)
afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT); afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT);
call->count -= count; call->count -= count;
if (call->count > 0) if (call->count > 0)
goto again; goto more_entries;
call->offset = 0;
call->unmarshall++; call->unmarshall++;
break; break;
} }
@ -267,14 +265,13 @@ static const struct afs_call_type afs_RXVLGetAddrsU = {
* Dispatch an operation to get the addresses for a server, where the server is * Dispatch an operation to get the addresses for a server, where the server is
* nominated by UUID. * nominated by UUID.
*/ */
struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net, struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
struct afs_addr_cursor *ac,
struct key *key,
const uuid_t *uuid) const uuid_t *uuid)
{ {
struct afs_ListAddrByAttributes__xdr *r; struct afs_ListAddrByAttributes__xdr *r;
const struct afs_uuid *u = (const struct afs_uuid *)uuid; const struct afs_uuid *u = (const struct afs_uuid *)uuid;
struct afs_call *call; struct afs_call *call;
struct afs_net *net = vc->cell->net;
__be32 *bp; __be32 *bp;
int i; int i;
@ -286,7 +283,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net,
if (!call) if (!call)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
call->key = key; call->key = vc->key;
call->reply[0] = NULL; call->reply[0] = NULL;
call->ret_reply0 = true; call->ret_reply0 = true;
@ -307,7 +304,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net,
r->uuid.node[i] = htonl(u->node[i]); r->uuid.node[i] = htonl(u->node[i]);
trace_afs_make_vl_call(call); trace_afs_make_vl_call(call);
return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false); return (struct afs_addr_list *)afs_make_call(&vc->ac, call, GFP_KERNEL, false);
} }
/* /*
@ -318,54 +315,51 @@ static int afs_deliver_vl_get_capabilities(struct afs_call *call)
u32 count; u32 count;
int ret; int ret;
_enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count); _enter("{%u,%zu/%u}",
call->unmarshall, iov_iter_count(call->_iter), call->count);
again:
switch (call->unmarshall) { switch (call->unmarshall) {
case 0: case 0:
call->offset = 0; afs_extract_to_tmp(call);
call->unmarshall++; call->unmarshall++;
/* Extract the capabilities word count */ /* Extract the capabilities word count */
case 1: case 1:
ret = afs_extract_data(call, &call->tmp, ret = afs_extract_data(call, true);
1 * sizeof(__be32),
true);
if (ret < 0) if (ret < 0)
return ret; return ret;
count = ntohl(call->tmp); count = ntohl(call->tmp);
call->count = count; call->count = count;
call->count2 = count; call->count2 = count;
call->offset = 0;
call->unmarshall++; call->unmarshall++;
afs_extract_discard(call, count * sizeof(__be32));
/* Extract capabilities words */ /* Extract capabilities words */
case 2: case 2:
count = min(call->count, 16U); ret = afs_extract_data(call, false);
ret = afs_extract_data(call, call->buffer,
count * sizeof(__be32),
call->count > 16);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* TODO: Examine capabilities */ /* TODO: Examine capabilities */
call->count -= count;
if (call->count > 0)
goto again;
call->offset = 0;
call->unmarshall++; call->unmarshall++;
break; break;
} }
call->reply[0] = (void *)(unsigned long)call->service_id;
_leave(" = 0 [done]"); _leave(" = 0 [done]");
return 0; return 0;
} }
static void afs_destroy_vl_get_capabilities(struct afs_call *call)
{
struct afs_vlserver *server = call->reply[0];
afs_put_vlserver(call->net, server);
afs_flat_call_destructor(call);
}
/* /*
* VL.GetCapabilities operation type * VL.GetCapabilities operation type
*/ */
@ -373,11 +367,12 @@ static const struct afs_call_type afs_RXVLGetCapabilities = {
.name = "VL.GetCapabilities", .name = "VL.GetCapabilities",
.op = afs_VL_GetCapabilities, .op = afs_VL_GetCapabilities,
.deliver = afs_deliver_vl_get_capabilities, .deliver = afs_deliver_vl_get_capabilities,
.destructor = afs_flat_call_destructor, .done = afs_vlserver_probe_result,
.destructor = afs_destroy_vl_get_capabilities,
}; };
/* /*
* Probe a fileserver for the capabilities that it supports. This can * Probe a volume server for the capabilities that it supports. This can
* return up to 196 words. * return up to 196 words.
* *
* We use this to probe for service upgrade to determine what the server at the * We use this to probe for service upgrade to determine what the server at the
@ -385,7 +380,10 @@ static const struct afs_call_type afs_RXVLGetCapabilities = {
*/ */
int afs_vl_get_capabilities(struct afs_net *net, int afs_vl_get_capabilities(struct afs_net *net,
struct afs_addr_cursor *ac, struct afs_addr_cursor *ac,
struct key *key) struct key *key,
struct afs_vlserver *server,
unsigned int server_index,
bool async)
{ {
struct afs_call *call; struct afs_call *call;
__be32 *bp; __be32 *bp;
@ -397,9 +395,10 @@ int afs_vl_get_capabilities(struct afs_net *net,
return -ENOMEM; return -ENOMEM;
call->key = key; call->key = key;
call->upgrade = true; /* Let's see if this is a YFS server */ call->reply[0] = afs_get_vlserver(server);
call->reply[0] = (void *)VLGETCAPABILITIES; call->reply[1] = (void *)(long)server_index;
call->ret_reply0 = true; call->upgrade = true;
call->want_reply_time = true;
/* marshall the parameters */ /* marshall the parameters */
bp = call->request; bp = call->request;
@ -407,7 +406,7 @@ int afs_vl_get_capabilities(struct afs_net *net,
/* Can't take a ref on server */ /* Can't take a ref on server */
trace_afs_make_vl_call(call); trace_afs_make_vl_call(call);
return afs_make_call(ac, call, GFP_KERNEL, false); return afs_make_call(ac, call, GFP_KERNEL, async);
} }
/* /*
@ -426,22 +425,19 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
u32 uniquifier, size; u32 uniquifier, size;
int ret; int ret;
_enter("{%u,%zu/%u,%u}", call->unmarshall, call->offset, call->count, call->count2); _enter("{%u,%zu,%u}",
call->unmarshall, iov_iter_count(call->_iter), call->count2);
again:
switch (call->unmarshall) { switch (call->unmarshall) {
case 0: case 0:
call->offset = 0; afs_extract_to_buf(call, sizeof(uuid_t) + 3 * sizeof(__be32));
call->unmarshall = 1; call->unmarshall = 1;
/* Extract the returned uuid, uniquifier, fsEndpoints count and /* Extract the returned uuid, uniquifier, fsEndpoints count and
* either the first fsEndpoint type or the volEndpoints * either the first fsEndpoint type or the volEndpoints
* count if there are no fsEndpoints. */ * count if there are no fsEndpoints. */
case 1: case 1:
ret = afs_extract_data(call, call->buffer, ret = afs_extract_data(call, true);
sizeof(uuid_t) +
3 * sizeof(__be32),
true);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -451,22 +447,19 @@ again:
call->count2 = ntohl(*bp); /* Type or next count */ call->count2 = ntohl(*bp); /* Type or next count */
if (call->count > YFS_MAXENDPOINTS) if (call->count > YFS_MAXENDPOINTS)
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_fsendpt_num);
alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT); alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
if (!alist) if (!alist)
return -ENOMEM; return -ENOMEM;
alist->version = uniquifier; alist->version = uniquifier;
call->reply[0] = alist; call->reply[0] = alist;
call->offset = 0;
if (call->count == 0) if (call->count == 0)
goto extract_volendpoints; goto extract_volendpoints;
call->unmarshall = 2; next_fsendpoint:
/* Extract fsEndpoints[] entries */
case 2:
switch (call->count2) { switch (call->count2) {
case YFS_ENDPOINT_IPV4: case YFS_ENDPOINT_IPV4:
size = sizeof(__be32) * (1 + 1 + 1); size = sizeof(__be32) * (1 + 1 + 1);
@ -475,11 +468,17 @@ again:
size = sizeof(__be32) * (1 + 4 + 1); size = sizeof(__be32) * (1 + 4 + 1);
break; break;
default: default:
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_fsendpt_type);
} }
size += sizeof(__be32); size += sizeof(__be32);
ret = afs_extract_data(call, call->buffer, size, true); afs_extract_to_buf(call, size);
call->unmarshall = 2;
/* Extract fsEndpoints[] entries */
case 2:
ret = afs_extract_data(call, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -488,18 +487,21 @@ again:
switch (call->count2) { switch (call->count2) {
case YFS_ENDPOINT_IPV4: case YFS_ENDPOINT_IPV4:
if (ntohl(bp[0]) != sizeof(__be32) * 2) if (ntohl(bp[0]) != sizeof(__be32) * 2)
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_fsendpt4_len);
afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2])); afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
bp += 3; bp += 3;
break; break;
case YFS_ENDPOINT_IPV6: case YFS_ENDPOINT_IPV6:
if (ntohl(bp[0]) != sizeof(__be32) * 5) if (ntohl(bp[0]) != sizeof(__be32) * 5)
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_fsendpt6_len);
afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5])); afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
bp += 6; bp += 6;
break; break;
default: default:
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_fsendpt_type);
} }
/* Got either the type of the next entry or the count of /* Got either the type of the next entry or the count of
@ -507,10 +509,9 @@ again:
*/ */
call->count2 = ntohl(*bp++); call->count2 = ntohl(*bp++);
call->offset = 0;
call->count--; call->count--;
if (call->count > 0) if (call->count > 0)
goto again; goto next_fsendpoint;
extract_volendpoints: extract_volendpoints:
/* Extract the list of volEndpoints. */ /* Extract the list of volEndpoints. */
@ -518,8 +519,10 @@ again:
if (!call->count) if (!call->count)
goto end; goto end;
if (call->count > YFS_MAXENDPOINTS) if (call->count > YFS_MAXENDPOINTS)
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_vlendpt_type);
afs_extract_to_buf(call, 1 * sizeof(__be32));
call->unmarshall = 3; call->unmarshall = 3;
/* Extract the type of volEndpoints[0]. Normally we would /* Extract the type of volEndpoints[0]. Normally we would
@ -527,17 +530,14 @@ again:
* data of the current one, but this is the first... * data of the current one, but this is the first...
*/ */
case 3: case 3:
ret = afs_extract_data(call, call->buffer, sizeof(__be32), true); ret = afs_extract_data(call, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
bp = call->buffer; bp = call->buffer;
call->count2 = ntohl(*bp++);
call->offset = 0;
call->unmarshall = 4;
/* Extract volEndpoints[] entries */ next_volendpoint:
case 4: call->count2 = ntohl(*bp++);
switch (call->count2) { switch (call->count2) {
case YFS_ENDPOINT_IPV4: case YFS_ENDPOINT_IPV4:
size = sizeof(__be32) * (1 + 1 + 1); size = sizeof(__be32) * (1 + 1 + 1);
@ -546,12 +546,18 @@ again:
size = sizeof(__be32) * (1 + 4 + 1); size = sizeof(__be32) * (1 + 4 + 1);
break; break;
default: default:
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_vlendpt_type);
} }
if (call->count > 1) if (call->count > 1)
size += sizeof(__be32); size += sizeof(__be32); /* Get next type too */
ret = afs_extract_data(call, call->buffer, size, true); afs_extract_to_buf(call, size);
call->unmarshall = 4;
/* Extract volEndpoints[] entries */
case 4:
ret = afs_extract_data(call, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -559,34 +565,35 @@ again:
switch (call->count2) { switch (call->count2) {
case YFS_ENDPOINT_IPV4: case YFS_ENDPOINT_IPV4:
if (ntohl(bp[0]) != sizeof(__be32) * 2) if (ntohl(bp[0]) != sizeof(__be32) * 2)
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_vlendpt4_len);
bp += 3; bp += 3;
break; break;
case YFS_ENDPOINT_IPV6: case YFS_ENDPOINT_IPV6:
if (ntohl(bp[0]) != sizeof(__be32) * 5) if (ntohl(bp[0]) != sizeof(__be32) * 5)
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_vlendpt6_len);
bp += 6; bp += 6;
break; break;
default: default:
return afs_protocol_error(call, -EBADMSG); return afs_protocol_error(call, -EBADMSG,
afs_eproto_yvl_vlendpt_type);
} }
/* Got either the type of the next entry or the count of /* Got either the type of the next entry or the count of
* volEndpoints if no more fsEndpoints. * volEndpoints if no more fsEndpoints.
*/ */
call->offset = 0;
call->count--; call->count--;
if (call->count > 0) { if (call->count > 0)
call->count2 = ntohl(*bp++); goto next_volendpoint;
goto again;
}
end: end:
afs_extract_discard(call, 0);
call->unmarshall = 5; call->unmarshall = 5;
/* Done */ /* Done */
case 5: case 5:
ret = afs_extract_data(call, call->buffer, 0, false); ret = afs_extract_data(call, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
call->unmarshall = 6; call->unmarshall = 6;
@ -596,11 +603,6 @@ again:
} }
alist = call->reply[0]; alist = call->reply[0];
/* Start with IPv6 if available. */
if (alist->nr_ipv4 < alist->nr_addrs)
alist->index = alist->nr_ipv4;
_leave(" = 0 [done]"); _leave(" = 0 [done]");
return 0; return 0;
} }
@ -619,12 +621,11 @@ static const struct afs_call_type afs_YFSVLGetEndpoints = {
* Dispatch an operation to get the addresses for a server, where the server is * Dispatch an operation to get the addresses for a server, where the server is
* nominated by UUID. * nominated by UUID.
*/ */
struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *net, struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
struct afs_addr_cursor *ac,
struct key *key,
const uuid_t *uuid) const uuid_t *uuid)
{ {
struct afs_call *call; struct afs_call *call;
struct afs_net *net = vc->cell->net;
__be32 *bp; __be32 *bp;
_enter(""); _enter("");
@ -635,7 +636,7 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *net,
if (!call) if (!call)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
call->key = key; call->key = vc->key;
call->reply[0] = NULL; call->reply[0] = NULL;
call->ret_reply0 = true; call->ret_reply0 = true;
@ -646,5 +647,5 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *net,
memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */ memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
trace_afs_make_vl_call(call); trace_afs_make_vl_call(call);
return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false); return (struct afs_addr_list *)afs_make_call(&vc->ac, call, GFP_KERNEL, false);
} }

View File

@ -74,55 +74,19 @@ static struct afs_vldb_entry *afs_vl_lookup_vldb(struct afs_cell *cell,
const char *volname, const char *volname,
size_t volnamesz) size_t volnamesz)
{ {
struct afs_addr_cursor ac; struct afs_vldb_entry *vldb = ERR_PTR(-EDESTADDRREQ);
struct afs_vldb_entry *vldb; struct afs_vl_cursor vc;
int ret; int ret;
ret = afs_set_vl_cursor(&ac, cell); if (!afs_begin_vlserver_operation(&vc, cell, key))
if (ret < 0) return ERR_PTR(-ERESTARTSYS);
return ERR_PTR(ret);
while (afs_iterate_addresses(&ac)) { while (afs_select_vlserver(&vc)) {
if (!test_bit(ac.index, &ac.alist->probed)) { vldb = afs_vl_get_entry_by_name_u(&vc, volname, volnamesz);
ret = afs_vl_get_capabilities(cell->net, &ac, key);
switch (ret) {
case VL_SERVICE:
clear_bit(ac.index, &ac.alist->yfs);
set_bit(ac.index, &ac.alist->probed);
ac.addr->srx_service = ret;
break;
case YFS_VL_SERVICE:
set_bit(ac.index, &ac.alist->yfs);
set_bit(ac.index, &ac.alist->probed);
ac.addr->srx_service = ret;
break;
}
} }
vldb = afs_vl_get_entry_by_name_u(cell->net, &ac, key, ret = afs_end_vlserver_operation(&vc);
volname, volnamesz); return ret < 0 ? ERR_PTR(ret) : vldb;
switch (ac.error) {
case 0:
afs_end_cursor(&ac);
return vldb;
case -ECONNABORTED:
ac.error = afs_abort_to_error(ac.abort_code);
goto error;
case -ENOMEM:
case -ENONET:
goto error;
case -ENETUNREACH:
case -EHOSTUNREACH:
case -ECONNREFUSED:
break;
default:
ac.error = -EIO;
goto error;
}
}
error:
return ERR_PTR(afs_end_cursor(&ac));
} }
/* /*
@ -270,7 +234,7 @@ static int afs_update_volume_status(struct afs_volume *volume, struct key *key)
/* We look up an ID by passing it as a decimal string in the /* We look up an ID by passing it as a decimal string in the
* operation's name parameter. * operation's name parameter.
*/ */
idsz = sprintf(idbuf, "%u", volume->vid); idsz = sprintf(idbuf, "%llu", volume->vid);
vldb = afs_vl_lookup_vldb(volume->cell, key, idbuf, idsz); vldb = afs_vl_lookup_vldb(volume->cell, key, idbuf, idsz);
if (IS_ERR(vldb)) { if (IS_ERR(vldb)) {

View File

@ -33,10 +33,21 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
loff_t pos, unsigned int len, struct page *page) loff_t pos, unsigned int len, struct page *page)
{ {
struct afs_read *req; struct afs_read *req;
size_t p;
void *data;
int ret; int ret;
_enter(",,%llu", (unsigned long long)pos); _enter(",,%llu", (unsigned long long)pos);
if (pos >= vnode->vfs_inode.i_size) {
p = pos & ~PAGE_MASK;
ASSERTCMP(p + len, <=, PAGE_SIZE);
data = kmap(page);
memset(data + p, 0, len);
kunmap(page);
return 0;
}
req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *), req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *),
GFP_KERNEL); GFP_KERNEL);
if (!req) if (!req)
@ -81,7 +92,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
pgoff_t index = pos >> PAGE_SHIFT; pgoff_t index = pos >> PAGE_SHIFT;
int ret; int ret;
_enter("{%x:%u},{%lx},%u,%u", _enter("{%llx:%llu},{%lx},%u,%u",
vnode->fid.vid, vnode->fid.vnode, index, from, to); vnode->fid.vid, vnode->fid.vnode, index, from, to);
/* We want to store information about how much of a page is altered in /* We want to store information about how much of a page is altered in
@ -181,7 +192,7 @@ int afs_write_end(struct file *file, struct address_space *mapping,
loff_t i_size, maybe_i_size; loff_t i_size, maybe_i_size;
int ret; int ret;
_enter("{%x:%u},{%lx}", _enter("{%llx:%llu},{%lx}",
vnode->fid.vid, vnode->fid.vnode, page->index); vnode->fid.vid, vnode->fid.vnode, page->index);
maybe_i_size = pos + copied; maybe_i_size = pos + copied;
@ -230,7 +241,7 @@ static void afs_kill_pages(struct address_space *mapping,
struct pagevec pv; struct pagevec pv;
unsigned count, loop; unsigned count, loop;
_enter("{%x:%u},%lx-%lx", _enter("{%llx:%llu},%lx-%lx",
vnode->fid.vid, vnode->fid.vnode, first, last); vnode->fid.vid, vnode->fid.vnode, first, last);
pagevec_init(&pv); pagevec_init(&pv);
@ -272,7 +283,7 @@ static void afs_redirty_pages(struct writeback_control *wbc,
struct pagevec pv; struct pagevec pv;
unsigned count, loop; unsigned count, loop;
_enter("{%x:%u},%lx-%lx", _enter("{%llx:%llu},%lx-%lx",
vnode->fid.vid, vnode->fid.vnode, first, last); vnode->fid.vid, vnode->fid.vnode, first, last);
pagevec_init(&pv); pagevec_init(&pv);
@ -314,7 +325,7 @@ static int afs_store_data(struct address_space *mapping,
struct list_head *p; struct list_head *p;
int ret = -ENOKEY, ret2; int ret = -ENOKEY, ret2;
_enter("%s{%x:%u.%u},%lx,%lx,%x,%x", _enter("%s{%llx:%llu.%u},%lx,%lx,%x,%x",
vnode->volume->name, vnode->volume->name,
vnode->fid.vid, vnode->fid.vid,
vnode->fid.vnode, vnode->fid.vnode,
@ -533,6 +544,7 @@ no_more:
case -ENOENT: case -ENOENT:
case -ENOMEDIUM: case -ENOMEDIUM:
case -ENXIO: case -ENXIO:
trace_afs_file_error(vnode, ret, afs_file_error_writeback_fail);
afs_kill_pages(mapping, first, last); afs_kill_pages(mapping, first, last);
mapping_set_error(mapping, ret); mapping_set_error(mapping, ret);
break; break;
@ -675,7 +687,7 @@ void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)
unsigned count, loop; unsigned count, loop;
pgoff_t first = call->first, last = call->last; pgoff_t first = call->first, last = call->last;
_enter("{%x:%u},{%lx-%lx}", _enter("{%llx:%llu},{%lx-%lx}",
vnode->fid.vid, vnode->fid.vnode, first, last); vnode->fid.vid, vnode->fid.vnode, first, last);
pagevec_init(&pv); pagevec_init(&pv);
@ -714,7 +726,7 @@ ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from)
ssize_t result; ssize_t result;
size_t count = iov_iter_count(from); size_t count = iov_iter_count(from);
_enter("{%x.%u},{%zu},", _enter("{%llx:%llu},{%zu},",
vnode->fid.vid, vnode->fid.vnode, count); vnode->fid.vid, vnode->fid.vnode, count);
if (IS_SWAPFILE(&vnode->vfs_inode)) { if (IS_SWAPFILE(&vnode->vfs_inode)) {
@ -742,7 +754,7 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_vnode *vnode = AFS_FS_I(inode);
_enter("{%x:%u},{n=%pD},%d", _enter("{%llx:%llu},{n=%pD},%d",
vnode->fid.vid, vnode->fid.vnode, file, vnode->fid.vid, vnode->fid.vnode, file,
datasync); datasync);
@ -760,7 +772,7 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_vnode *vnode = AFS_FS_I(inode);
unsigned long priv; unsigned long priv;
_enter("{{%x:%u}},{%lx}", _enter("{{%llx:%llu}},{%lx}",
vnode->fid.vid, vnode->fid.vnode, vmf->page->index); vnode->fid.vid, vnode->fid.vnode, vmf->page->index);
sb_start_pagefault(inode->i_sb); sb_start_pagefault(inode->i_sb);

View File

@ -72,7 +72,7 @@ static int afs_xattr_get_fid(const struct xattr_handler *handler,
char text[8 + 1 + 8 + 1 + 8 + 1]; char text[8 + 1 + 8 + 1 + 8 + 1];
size_t len; size_t len;
len = sprintf(text, "%x:%x:%x", len = sprintf(text, "%llx:%llx:%x",
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
if (size == 0) if (size == 0)
return len; return len;

2184
fs/afs/yfsclient.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -349,7 +349,7 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
dio->size = 0; dio->size = 0;
dio->multi_bio = false; dio->multi_bio = false;
dio->should_dirty = is_read && (iter->type == ITER_IOVEC); dio->should_dirty = is_read && iter_is_iovec(iter);
blk_start_plug(&plug); blk_start_plug(&plug);
for (;;) { for (;;) {

View File

@ -615,7 +615,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to,
more = len < iov_iter_count(to); more = len < iov_iter_count(to);
if (unlikely(to->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(to))) {
ret = iov_iter_get_pages_alloc(to, &pages, len, ret = iov_iter_get_pages_alloc(to, &pages, len,
&page_off); &page_off);
if (ret <= 0) { if (ret <= 0) {
@ -662,7 +662,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to,
ret += zlen; ret += zlen;
} }
if (unlikely(to->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(to))) {
if (ret > 0) { if (ret > 0) {
iov_iter_advance(to, ret); iov_iter_advance(to, ret);
off += ret; off += ret;
@ -815,7 +815,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req)
aio_req->total_len = rc + zlen; aio_req->total_len = rc + zlen;
} }
iov_iter_bvec(&i, ITER_BVEC, osd_data->bvec_pos.bvecs, iov_iter_bvec(&i, READ, osd_data->bvec_pos.bvecs,
osd_data->num_bvecs, osd_data->num_bvecs,
osd_data->bvec_pos.iter.bi_size); osd_data->bvec_pos.iter.bi_size);
iov_iter_advance(&i, rc); iov_iter_advance(&i, rc);
@ -1038,8 +1038,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
int zlen = min_t(size_t, len - ret, int zlen = min_t(size_t, len - ret,
size - pos - ret); size - pos - ret);
iov_iter_bvec(&i, ITER_BVEC, bvecs, num_pages, iov_iter_bvec(&i, READ, bvecs, num_pages, len);
len);
iov_iter_advance(&i, ret); iov_iter_advance(&i, ret);
iov_iter_zero(zlen, &i); iov_iter_zero(zlen, &i);
ret += zlen; ret += zlen;

View File

@ -589,7 +589,7 @@ cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
{ {
struct msghdr smb_msg; struct msghdr smb_msg;
struct kvec iov = {.iov_base = buf, .iov_len = to_read}; struct kvec iov = {.iov_base = buf, .iov_len = to_read};
iov_iter_kvec(&smb_msg.msg_iter, READ | ITER_KVEC, &iov, 1, to_read); iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
return cifs_readv_from_socket(server, &smb_msg); return cifs_readv_from_socket(server, &smb_msg);
} }
@ -601,7 +601,7 @@ cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
struct msghdr smb_msg; struct msghdr smb_msg;
struct bio_vec bv = { struct bio_vec bv = {
.bv_page = page, .bv_len = to_read, .bv_offset = page_offset}; .bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
iov_iter_bvec(&smb_msg.msg_iter, READ | ITER_BVEC, &bv, 1, to_read); iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
return cifs_readv_from_socket(server, &smb_msg); return cifs_readv_from_socket(server, &smb_msg);
} }

View File

@ -3004,7 +3004,7 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter)
size_t copy = min_t(size_t, remaining, PAGE_SIZE); size_t copy = min_t(size_t, remaining, PAGE_SIZE);
size_t written; size_t written;
if (unlikely(iter->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(iter))) {
void *addr = kmap_atomic(page); void *addr = kmap_atomic(page);
written = copy_to_iter(addr, copy, iter); written = copy_to_iter(addr, copy, iter);
@ -3316,7 +3316,7 @@ ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to)
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
ctx->iocb = iocb; ctx->iocb = iocb;
if (to->type == ITER_IOVEC) if (iter_is_iovec(to))
ctx->should_dirty = true; ctx->should_dirty = true;
rc = setup_aio_ctx_iter(ctx, to, READ); rc = setup_aio_ctx_iter(ctx, to, READ);

View File

@ -788,7 +788,7 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
struct page **pages = NULL; struct page **pages = NULL;
struct bio_vec *bv = NULL; struct bio_vec *bv = NULL;
if (iter->type & ITER_KVEC) { if (iov_iter_is_kvec(iter)) {
memcpy(&ctx->iter, iter, sizeof(struct iov_iter)); memcpy(&ctx->iter, iter, sizeof(struct iov_iter));
ctx->len = count; ctx->len = count;
iov_iter_advance(iter, count); iov_iter_advance(iter, count);
@ -859,7 +859,7 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
ctx->bv = bv; ctx->bv = bv;
ctx->len = saved_len - count; ctx->len = saved_len - count;
ctx->npages = npages; ctx->npages = npages;
iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len); iov_iter_bvec(&ctx->iter, rw, ctx->bv, npages, ctx->len);
return 0; return 0;
} }

View File

@ -3152,13 +3152,13 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
return 0; return 0;
} }
iov_iter_bvec(&iter, WRITE | ITER_BVEC, bvec, npages, data_len); iov_iter_bvec(&iter, WRITE, bvec, npages, data_len);
} else if (buf_len >= data_offset + data_len) { } else if (buf_len >= data_offset + data_len) {
/* read response payload is in buf */ /* read response payload is in buf */
WARN_ONCE(npages > 0, "read data can be either in buf or in pages"); WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
iov.iov_base = buf + data_offset; iov.iov_base = buf + data_offset;
iov.iov_len = data_len; iov.iov_len = data_len;
iov_iter_kvec(&iter, WRITE | ITER_KVEC, &iov, 1, data_len); iov_iter_kvec(&iter, WRITE, &iov, 1, data_len);
} else { } else {
/* read response payload cannot be in both buf and pages */ /* read response payload cannot be in both buf and pages */
WARN_ONCE(1, "buf can not contain only a part of read data"); WARN_ONCE(1, "buf can not contain only a part of read data");

View File

@ -2054,14 +2054,22 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg)
info->smbd_recv_pending++; info->smbd_recv_pending++;
switch (msg->msg_iter.type) { if (iov_iter_rw(&msg->msg_iter) == WRITE) {
case READ | ITER_KVEC: /* It's a bug in upper layer to get there */
cifs_dbg(VFS, "CIFS: invalid msg iter dir %u\n",
iov_iter_rw(&msg->msg_iter));
rc = -EINVAL;
goto out;
}
switch (iov_iter_type(&msg->msg_iter)) {
case ITER_KVEC:
buf = msg->msg_iter.kvec->iov_base; buf = msg->msg_iter.kvec->iov_base;
to_read = msg->msg_iter.kvec->iov_len; to_read = msg->msg_iter.kvec->iov_len;
rc = smbd_recv_buf(info, buf, to_read); rc = smbd_recv_buf(info, buf, to_read);
break; break;
case READ | ITER_BVEC: case ITER_BVEC:
page = msg->msg_iter.bvec->bv_page; page = msg->msg_iter.bvec->bv_page;
page_offset = msg->msg_iter.bvec->bv_offset; page_offset = msg->msg_iter.bvec->bv_offset;
to_read = msg->msg_iter.bvec->bv_len; to_read = msg->msg_iter.bvec->bv_len;
@ -2071,10 +2079,11 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg)
default: default:
/* It's a bug in upper layer to get there */ /* It's a bug in upper layer to get there */
cifs_dbg(VFS, "CIFS: invalid msg type %d\n", cifs_dbg(VFS, "CIFS: invalid msg type %d\n",
msg->msg_iter.type); iov_iter_type(&msg->msg_iter));
rc = -EINVAL; rc = -EINVAL;
} }
out:
info->smbd_recv_pending--; info->smbd_recv_pending--;
wake_up(&info->wait_smbd_recv_pending); wake_up(&info->wait_smbd_recv_pending);

View File

@ -316,8 +316,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
.iov_base = &rfc1002_marker, .iov_base = &rfc1002_marker,
.iov_len = 4 .iov_len = 4
}; };
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, &hiov, iov_iter_kvec(&smb_msg.msg_iter, WRITE, &hiov, 1, 4);
1, 4);
rc = smb_send_kvec(server, &smb_msg, &sent); rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0) if (rc < 0)
goto uncork; goto uncork;
@ -338,8 +337,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
size += iov[i].iov_len; size += iov[i].iov_len;
} }
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov_iter_kvec(&smb_msg.msg_iter, WRITE, iov, n_vec, size);
iov, n_vec, size);
rc = smb_send_kvec(server, &smb_msg, &sent); rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0) if (rc < 0)
@ -355,7 +353,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
rqst_page_get_length(&rqst[j], i, &bvec.bv_len, rqst_page_get_length(&rqst[j], i, &bvec.bv_len,
&bvec.bv_offset); &bvec.bv_offset);
iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, iov_iter_bvec(&smb_msg.msg_iter, WRITE,
&bvec, 1, bvec.bv_len); &bvec, 1, bvec.bv_len);
rc = smb_send_kvec(server, &smb_msg, &sent); rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0) if (rc < 0)

View File

@ -1313,7 +1313,7 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
spin_lock_init(&dio->bio_lock); spin_lock_init(&dio->bio_lock);
dio->refcount = 1; dio->refcount = 1;
dio->should_dirty = (iter->type == ITER_IOVEC); dio->should_dirty = iter_is_iovec(iter) && iov_iter_rw(iter) == READ;
sdio.iter = iter; sdio.iter = iter;
sdio.final_block_in_request = end >> blkbits; sdio.final_block_in_request = end >> blkbits;

View File

@ -674,7 +674,7 @@ static int receive_from_sock(struct connection *con)
nvec = 2; nvec = 2;
} }
len = iov[0].iov_len + iov[1].iov_len; len = iov[0].iov_len + iov[1].iov_len;
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, iov, nvec, len); iov_iter_kvec(&msg.msg_iter, READ, iov, nvec, len);
r = ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT | MSG_NOSIGNAL); r = ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT | MSG_NOSIGNAL);
if (ret <= 0) if (ret <= 0)

View File

@ -1275,7 +1275,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
ssize_t ret = 0; ssize_t ret = 0;
/* Special case for kernel I/O: can copy directly into the buffer */ /* Special case for kernel I/O: can copy directly into the buffer */
if (ii->type & ITER_KVEC) { if (iov_iter_is_kvec(ii)) {
unsigned long user_addr = fuse_get_user_addr(ii); unsigned long user_addr = fuse_get_user_addr(ii);
size_t frag_size = fuse_get_frag_size(ii, *nbytesp); size_t frag_size = fuse_get_frag_size(ii, *nbytesp);

View File

@ -1795,7 +1795,7 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
if (pos >= dio->i_size) if (pos >= dio->i_size)
goto out_free_dio; goto out_free_dio;
if (iter->type == ITER_IOVEC) if (iter_is_iovec(iter) && iov_iter_rw(iter) == READ)
dio->flags |= IOMAP_DIO_DIRTY; dio->flags |= IOMAP_DIO_DIRTY;
} else { } else {
flags |= IOMAP_WRITE; flags |= IOMAP_WRITE;

View File

@ -923,7 +923,7 @@ __be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp,
int host_err; int host_err;
trace_nfsd_read_vector(rqstp, fhp, offset, *count); trace_nfsd_read_vector(rqstp, fhp, offset, *count);
iov_iter_kvec(&iter, READ | ITER_KVEC, vec, vlen, *count); iov_iter_kvec(&iter, READ, vec, vlen, *count);
host_err = vfs_iter_read(file, &iter, &offset, 0); host_err = vfs_iter_read(file, &iter, &offset, 0);
return nfsd_finish_read(rqstp, fhp, file, offset, count, host_err); return nfsd_finish_read(rqstp, fhp, file, offset, count, host_err);
} }
@ -999,7 +999,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
if (stable && !use_wgather) if (stable && !use_wgather)
flags |= RWF_SYNC; flags |= RWF_SYNC;
iov_iter_kvec(&iter, WRITE | ITER_KVEC, vec, vlen, *cnt); iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
host_err = vfs_iter_write(file, &iter, &pos, flags); host_err = vfs_iter_write(file, &iter, &pos, flags);
if (host_err < 0) if (host_err < 0)
goto out_nfserr; goto out_nfserr;

View File

@ -916,7 +916,7 @@ static int o2net_recv_tcp_msg(struct socket *sock, void *data, size_t len)
{ {
struct kvec vec = { .iov_len = len, .iov_base = data, }; struct kvec vec = { .iov_len = len, .iov_base = data, };
struct msghdr msg = { .msg_flags = MSG_DONTWAIT, }; struct msghdr msg = { .msg_flags = MSG_DONTWAIT, };
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &vec, 1, len); iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, len);
return sock_recvmsg(sock, &msg, MSG_DONTWAIT); return sock_recvmsg(sock, &msg, MSG_DONTWAIT);
} }

View File

@ -25,7 +25,7 @@ static int read_one_page(struct page *page)
struct iov_iter to; struct iov_iter to;
struct bio_vec bv = {.bv_page = page, .bv_len = PAGE_SIZE}; struct bio_vec bv = {.bv_page = page, .bv_len = PAGE_SIZE};
iov_iter_bvec(&to, ITER_BVEC | READ, &bv, 1, PAGE_SIZE); iov_iter_bvec(&to, READ, &bv, 1, PAGE_SIZE);
gossip_debug(GOSSIP_INODE_DEBUG, gossip_debug(GOSSIP_INODE_DEBUG,
"orangefs_readpage called with page %p\n", "orangefs_readpage called with page %p\n",

View File

@ -301,7 +301,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
struct kiocb kiocb; struct kiocb kiocb;
int idx, ret; int idx, ret;
iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len); iov_iter_pipe(&to, READ, pipe, len);
idx = to.idx; idx = to.idx;
init_sync_kiocb(&kiocb, in); init_sync_kiocb(&kiocb, in);
kiocb.ki_pos = *ppos; kiocb.ki_pos = *ppos;
@ -386,7 +386,7 @@ static ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
*/ */
offset = *ppos & ~PAGE_MASK; offset = *ppos & ~PAGE_MASK;
iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len + offset); iov_iter_pipe(&to, READ, pipe, len + offset);
res = iov_iter_get_pages_alloc(&to, &pages, len + offset, &base); res = iov_iter_get_pages_alloc(&to, &pages, len + offset, &base);
if (res <= 0) if (res <= 0)
@ -745,8 +745,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
left -= this_len; left -= this_len;
} }
iov_iter_bvec(&from, ITER_BVEC | WRITE, array, n, iov_iter_bvec(&from, WRITE, array, n, sd.total_len - left);
sd.total_len - left);
ret = vfs_iter_write(out, &from, &sd.pos, 0); ret = vfs_iter_write(out, &from, &sd.pos, 0);
if (ret <= 0) if (ret <= 0)
break; break;

View File

@ -21,15 +21,16 @@ struct kvec {
size_t iov_len; size_t iov_len;
}; };
enum { enum iter_type {
ITER_IOVEC = 0, ITER_IOVEC = 0,
ITER_KVEC = 2, ITER_KVEC = 2,
ITER_BVEC = 4, ITER_BVEC = 4,
ITER_PIPE = 8, ITER_PIPE = 8,
ITER_DISCARD = 16,
}; };
struct iov_iter { struct iov_iter {
int type; unsigned int type;
size_t iov_offset; size_t iov_offset;
size_t count; size_t count;
union { union {
@ -47,6 +48,41 @@ struct iov_iter {
}; };
}; };
static inline enum iter_type iov_iter_type(const struct iov_iter *i)
{
return i->type & ~(READ | WRITE);
}
static inline bool iter_is_iovec(const struct iov_iter *i)
{
return iov_iter_type(i) == ITER_IOVEC;
}
static inline bool iov_iter_is_kvec(const struct iov_iter *i)
{
return iov_iter_type(i) == ITER_KVEC;
}
static inline bool iov_iter_is_bvec(const struct iov_iter *i)
{
return iov_iter_type(i) == ITER_BVEC;
}
static inline bool iov_iter_is_pipe(const struct iov_iter *i)
{
return iov_iter_type(i) == ITER_PIPE;
}
static inline bool iov_iter_is_discard(const struct iov_iter *i)
{
return iov_iter_type(i) == ITER_DISCARD;
}
static inline unsigned char iov_iter_rw(const struct iov_iter *i)
{
return i->type & (READ | WRITE);
}
/* /*
* Total number of bytes covered by an iovec. * Total number of bytes covered by an iovec.
* *
@ -74,7 +110,8 @@ static inline struct iovec iov_iter_iovec(const struct iov_iter *iter)
} }
#define iov_for_each(iov, iter, start) \ #define iov_for_each(iov, iter, start) \
if (!((start).type & (ITER_BVEC | ITER_PIPE))) \ if (iov_iter_type(start) == ITER_IOVEC || \
iov_iter_type(start) == ITER_KVEC) \
for (iter = (start); \ for (iter = (start); \
(iter).count && \ (iter).count && \
((iov = iov_iter_iovec(&(iter))), 1); \ ((iov = iov_iter_iovec(&(iter))), 1); \
@ -181,14 +218,15 @@ size_t copy_to_iter_mcsafe(void *addr, size_t bytes, struct iov_iter *i)
size_t iov_iter_zero(size_t bytes, struct iov_iter *); size_t iov_iter_zero(size_t bytes, struct iov_iter *);
unsigned long iov_iter_alignment(const struct iov_iter *i); unsigned long iov_iter_alignment(const struct iov_iter *i);
unsigned long iov_iter_gap_alignment(const struct iov_iter *i); unsigned long iov_iter_gap_alignment(const struct iov_iter *i);
void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, void iov_iter_init(struct iov_iter *i, unsigned int direction, const struct iovec *iov,
unsigned long nr_segs, size_t count); unsigned long nr_segs, size_t count);
void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec, void iov_iter_kvec(struct iov_iter *i, unsigned int direction, const struct kvec *kvec,
unsigned long nr_segs, size_t count); unsigned long nr_segs, size_t count);
void iov_iter_bvec(struct iov_iter *i, int direction, const struct bio_vec *bvec, void iov_iter_bvec(struct iov_iter *i, unsigned int direction, const struct bio_vec *bvec,
unsigned long nr_segs, size_t count); unsigned long nr_segs, size_t count);
void iov_iter_pipe(struct iov_iter *i, int direction, struct pipe_inode_info *pipe, void iov_iter_pipe(struct iov_iter *i, unsigned int direction, struct pipe_inode_info *pipe,
size_t count); size_t count);
void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count);
ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
size_t maxsize, unsigned maxpages, size_t *start); size_t maxsize, unsigned maxpages, size_t *start);
ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
@ -202,19 +240,6 @@ static inline size_t iov_iter_count(const struct iov_iter *i)
return i->count; return i->count;
} }
static inline bool iter_is_iovec(const struct iov_iter *i)
{
return !(i->type & (ITER_BVEC | ITER_KVEC | ITER_PIPE));
}
/*
* Get one of READ or WRITE out of iter->type without any other flags OR'd in
* with it.
*
* The ?: is just for type safety.
*/
#define iov_iter_rw(i) ((0 ? (struct iov_iter *)0 : (i))->type & (READ | WRITE))
/* /*
* Cap the iov_iter by given limit; note that the second argument is * Cap the iov_iter by given limit; note that the second argument is
* *not* the new size - it's upper limit for such. Passing it a value * *not* the new size - it's upper limit for such. Passing it a value

View File

@ -54,6 +54,35 @@ enum afs_fs_operation {
afs_FS_StoreData64 = 65538, /* AFS Store file data */ afs_FS_StoreData64 = 65538, /* AFS Store file data */
afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */ afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */
afs_FS_GetCapabilities = 65540, /* AFS Get FS server capabilities */ afs_FS_GetCapabilities = 65540, /* AFS Get FS server capabilities */
yfs_FS_FetchData = 130, /* YFS Fetch file data */
yfs_FS_FetchACL = 64131, /* YFS Fetch file ACL */
yfs_FS_FetchStatus = 64132, /* YFS Fetch file status */
yfs_FS_StoreACL = 64134, /* YFS Store file ACL */
yfs_FS_StoreStatus = 64135, /* YFS Store file status */
yfs_FS_RemoveFile = 64136, /* YFS Remove a file */
yfs_FS_CreateFile = 64137, /* YFS Create a file */
yfs_FS_Rename = 64138, /* YFS Rename or move a file or directory */
yfs_FS_Symlink = 64139, /* YFS Create a symbolic link */
yfs_FS_Link = 64140, /* YFS Create a hard link */
yfs_FS_MakeDir = 64141, /* YFS Create a directory */
yfs_FS_RemoveDir = 64142, /* YFS Remove a directory */
yfs_FS_GetVolumeStatus = 64149, /* YFS Get volume status information */
yfs_FS_SetVolumeStatus = 64150, /* YFS Set volume status information */
yfs_FS_SetLock = 64156, /* YFS Request a file lock */
yfs_FS_ExtendLock = 64157, /* YFS Extend a file lock */
yfs_FS_ReleaseLock = 64158, /* YFS Release a file lock */
yfs_FS_Lookup = 64161, /* YFS lookup file in directory */
yfs_FS_FlushCPS = 64165,
yfs_FS_FetchOpaqueACL = 64168,
yfs_FS_WhoAmI = 64170,
yfs_FS_RemoveACL = 64171,
yfs_FS_RemoveFile2 = 64173,
yfs_FS_StoreOpaqueACL2 = 64174,
yfs_FS_InlineBulkStatus = 64536, /* YFS Fetch multiple file statuses with errors */
yfs_FS_FetchData64 = 64537, /* YFS Fetch file data */
yfs_FS_StoreData64 = 64538, /* YFS Store file data */
yfs_FS_UpdateSymlink = 64540,
}; };
enum afs_vl_operation { enum afs_vl_operation {
@ -84,6 +113,44 @@ enum afs_edit_dir_reason {
afs_edit_dir_for_unlink, afs_edit_dir_for_unlink,
}; };
enum afs_eproto_cause {
afs_eproto_bad_status,
afs_eproto_cb_count,
afs_eproto_cb_fid_count,
afs_eproto_file_type,
afs_eproto_ibulkst_cb_count,
afs_eproto_ibulkst_count,
afs_eproto_motd_len,
afs_eproto_offline_msg_len,
afs_eproto_volname_len,
afs_eproto_yvl_fsendpt4_len,
afs_eproto_yvl_fsendpt6_len,
afs_eproto_yvl_fsendpt_num,
afs_eproto_yvl_fsendpt_type,
afs_eproto_yvl_vlendpt4_len,
afs_eproto_yvl_vlendpt6_len,
afs_eproto_yvl_vlendpt_type,
};
enum afs_io_error {
afs_io_error_cm_reply,
afs_io_error_extract,
afs_io_error_fs_probe_fail,
afs_io_error_vl_lookup_fail,
afs_io_error_vl_probe_fail,
};
enum afs_file_error {
afs_file_error_dir_bad_magic,
afs_file_error_dir_big,
afs_file_error_dir_missing_page,
afs_file_error_dir_over_end,
afs_file_error_dir_small,
afs_file_error_dir_unmarked_ext,
afs_file_error_mntpt,
afs_file_error_writeback_fail,
};
#endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */
/* /*
@ -119,7 +186,34 @@ enum afs_edit_dir_reason {
EM(afs_FS_FetchData64, "FS.FetchData64") \ EM(afs_FS_FetchData64, "FS.FetchData64") \
EM(afs_FS_StoreData64, "FS.StoreData64") \ EM(afs_FS_StoreData64, "FS.StoreData64") \
EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \ EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \
E_(afs_FS_GetCapabilities, "FS.GetCapabilities") EM(afs_FS_GetCapabilities, "FS.GetCapabilities") \
EM(yfs_FS_FetchACL, "YFS.FetchACL") \
EM(yfs_FS_FetchStatus, "YFS.FetchStatus") \
EM(yfs_FS_StoreACL, "YFS.StoreACL") \
EM(yfs_FS_StoreStatus, "YFS.StoreStatus") \
EM(yfs_FS_RemoveFile, "YFS.RemoveFile") \
EM(yfs_FS_CreateFile, "YFS.CreateFile") \
EM(yfs_FS_Rename, "YFS.Rename") \
EM(yfs_FS_Symlink, "YFS.Symlink") \
EM(yfs_FS_Link, "YFS.Link") \
EM(yfs_FS_MakeDir, "YFS.MakeDir") \
EM(yfs_FS_RemoveDir, "YFS.RemoveDir") \
EM(yfs_FS_GetVolumeStatus, "YFS.GetVolumeStatus") \
EM(yfs_FS_SetVolumeStatus, "YFS.SetVolumeStatus") \
EM(yfs_FS_SetLock, "YFS.SetLock") \
EM(yfs_FS_ExtendLock, "YFS.ExtendLock") \
EM(yfs_FS_ReleaseLock, "YFS.ReleaseLock") \
EM(yfs_FS_Lookup, "YFS.Lookup") \
EM(yfs_FS_FlushCPS, "YFS.FlushCPS") \
EM(yfs_FS_FetchOpaqueACL, "YFS.FetchOpaqueACL") \
EM(yfs_FS_WhoAmI, "YFS.WhoAmI") \
EM(yfs_FS_RemoveACL, "YFS.RemoveACL") \
EM(yfs_FS_RemoveFile2, "YFS.RemoveFile2") \
EM(yfs_FS_StoreOpaqueACL2, "YFS.StoreOpaqueACL2") \
EM(yfs_FS_InlineBulkStatus, "YFS.InlineBulkStatus") \
EM(yfs_FS_FetchData64, "YFS.FetchData64") \
EM(yfs_FS_StoreData64, "YFS.StoreData64") \
E_(yfs_FS_UpdateSymlink, "YFS.UpdateSymlink")
#define afs_vl_operations \ #define afs_vl_operations \
EM(afs_VL_GetEntryByNameU, "VL.GetEntryByNameU") \ EM(afs_VL_GetEntryByNameU, "VL.GetEntryByNameU") \
@ -146,6 +240,40 @@ enum afs_edit_dir_reason {
EM(afs_edit_dir_for_symlink, "Symlnk") \ EM(afs_edit_dir_for_symlink, "Symlnk") \
E_(afs_edit_dir_for_unlink, "Unlink") E_(afs_edit_dir_for_unlink, "Unlink")
#define afs_eproto_causes \
EM(afs_eproto_bad_status, "BadStatus") \
EM(afs_eproto_cb_count, "CbCount") \
EM(afs_eproto_cb_fid_count, "CbFidCount") \
EM(afs_eproto_file_type, "FileTYpe") \
EM(afs_eproto_ibulkst_cb_count, "IBS.CbCount") \
EM(afs_eproto_ibulkst_count, "IBS.FidCount") \
EM(afs_eproto_motd_len, "MotdLen") \
EM(afs_eproto_offline_msg_len, "OfflineMsgLen") \
EM(afs_eproto_volname_len, "VolNameLen") \
EM(afs_eproto_yvl_fsendpt4_len, "YVL.FsEnd4Len") \
EM(afs_eproto_yvl_fsendpt6_len, "YVL.FsEnd6Len") \
EM(afs_eproto_yvl_fsendpt_num, "YVL.FsEndCount") \
EM(afs_eproto_yvl_fsendpt_type, "YVL.FsEndType") \
EM(afs_eproto_yvl_vlendpt4_len, "YVL.VlEnd4Len") \
EM(afs_eproto_yvl_vlendpt6_len, "YVL.VlEnd6Len") \
E_(afs_eproto_yvl_vlendpt_type, "YVL.VlEndType")
#define afs_io_errors \
EM(afs_io_error_cm_reply, "CM_REPLY") \
EM(afs_io_error_extract, "EXTRACT") \
EM(afs_io_error_fs_probe_fail, "FS_PROBE_FAIL") \
EM(afs_io_error_vl_lookup_fail, "VL_LOOKUP_FAIL") \
E_(afs_io_error_vl_probe_fail, "VL_PROBE_FAIL")
#define afs_file_errors \
EM(afs_file_error_dir_bad_magic, "DIR_BAD_MAGIC") \
EM(afs_file_error_dir_big, "DIR_BIG") \
EM(afs_file_error_dir_missing_page, "DIR_MISSING_PAGE") \
EM(afs_file_error_dir_over_end, "DIR_ENT_OVER_END") \
EM(afs_file_error_dir_small, "DIR_SMALL") \
EM(afs_file_error_dir_unmarked_ext, "DIR_UNMARKED_EXT") \
EM(afs_file_error_mntpt, "MNTPT_READ_FAILED") \
E_(afs_file_error_writeback_fail, "WRITEBACK_FAILED")
/* /*
* Export enum symbols via userspace. * Export enum symbols via userspace.
@ -160,6 +288,9 @@ afs_fs_operations;
afs_vl_operations; afs_vl_operations;
afs_edit_dir_ops; afs_edit_dir_ops;
afs_edit_dir_reasons; afs_edit_dir_reasons;
afs_eproto_causes;
afs_io_errors;
afs_file_errors;
/* /*
* Now redefine the EM() and E_() macros to map the enums to the strings that * Now redefine the EM() and E_() macros to map the enums to the strings that
@ -170,17 +301,16 @@ afs_edit_dir_reasons;
#define EM(a, b) { a, b }, #define EM(a, b) { a, b },
#define E_(a, b) { a, b } #define E_(a, b) { a, b }
TRACE_EVENT(afs_recv_data, TRACE_EVENT(afs_receive_data,
TP_PROTO(struct afs_call *call, unsigned count, unsigned offset, TP_PROTO(struct afs_call *call, struct iov_iter *iter,
bool want_more, int ret), bool want_more, int ret),
TP_ARGS(call, count, offset, want_more, ret), TP_ARGS(call, iter, want_more, ret),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(loff_t, remain )
__field(unsigned int, call ) __field(unsigned int, call )
__field(enum afs_call_state, state ) __field(enum afs_call_state, state )
__field(unsigned int, count )
__field(unsigned int, offset )
__field(unsigned short, unmarshall ) __field(unsigned short, unmarshall )
__field(bool, want_more ) __field(bool, want_more )
__field(int, ret ) __field(int, ret )
@ -190,17 +320,18 @@ TRACE_EVENT(afs_recv_data,
__entry->call = call->debug_id; __entry->call = call->debug_id;
__entry->state = call->state; __entry->state = call->state;
__entry->unmarshall = call->unmarshall; __entry->unmarshall = call->unmarshall;
__entry->count = count; __entry->remain = iov_iter_count(iter);
__entry->offset = offset;
__entry->want_more = want_more; __entry->want_more = want_more;
__entry->ret = ret; __entry->ret = ret;
), ),
TP_printk("c=%08x s=%u u=%u %u/%u wm=%u ret=%d", TP_printk("c=%08x r=%llu u=%u w=%u s=%u ret=%d",
__entry->call, __entry->call,
__entry->state, __entry->unmarshall, __entry->remain,
__entry->offset, __entry->count, __entry->unmarshall,
__entry->want_more, __entry->ret) __entry->want_more,
__entry->state,
__entry->ret)
); );
TRACE_EVENT(afs_notify_call, TRACE_EVENT(afs_notify_call,
@ -301,7 +432,7 @@ TRACE_EVENT(afs_make_fs_call,
} }
), ),
TP_printk("c=%08x %06x:%06x:%06x %s", TP_printk("c=%08x %06llx:%06llx:%06x %s",
__entry->call, __entry->call,
__entry->fid.vid, __entry->fid.vid,
__entry->fid.vnode, __entry->fid.vnode,
@ -555,24 +686,70 @@ TRACE_EVENT(afs_edit_dir,
); );
TRACE_EVENT(afs_protocol_error, TRACE_EVENT(afs_protocol_error,
TP_PROTO(struct afs_call *call, int error, const void *where), TP_PROTO(struct afs_call *call, int error, enum afs_eproto_cause cause),
TP_ARGS(call, error, cause),
TP_STRUCT__entry(
__field(unsigned int, call )
__field(int, error )
__field(enum afs_eproto_cause, cause )
),
TP_fast_assign(
__entry->call = call ? call->debug_id : 0;
__entry->error = error;
__entry->cause = cause;
),
TP_printk("c=%08x r=%d %s",
__entry->call, __entry->error,
__print_symbolic(__entry->cause, afs_eproto_causes))
);
TRACE_EVENT(afs_io_error,
TP_PROTO(unsigned int call, int error, enum afs_io_error where),
TP_ARGS(call, error, where), TP_ARGS(call, error, where),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned int, call ) __field(unsigned int, call )
__field(int, error ) __field(int, error )
__field(const void *, where ) __field(enum afs_io_error, where )
), ),
TP_fast_assign( TP_fast_assign(
__entry->call = call ? call->debug_id : 0; __entry->call = call;
__entry->error = error; __entry->error = error;
__entry->where = where; __entry->where = where;
), ),
TP_printk("c=%08x r=%d sp=%pSR", TP_printk("c=%08x r=%d %s",
__entry->call, __entry->error, __entry->where) __entry->call, __entry->error,
__print_symbolic(__entry->where, afs_io_errors))
);
TRACE_EVENT(afs_file_error,
TP_PROTO(struct afs_vnode *vnode, int error, enum afs_file_error where),
TP_ARGS(vnode, error, where),
TP_STRUCT__entry(
__field_struct(struct afs_fid, fid )
__field(int, error )
__field(enum afs_file_error, where )
),
TP_fast_assign(
__entry->fid = vnode->fid;
__entry->error = error;
__entry->where = where;
),
TP_printk("%llx:%llx:%x r=%d %s",
__entry->fid.vid, __entry->fid.vnode, __entry->fid.unique,
__entry->error,
__print_symbolic(__entry->where, afs_file_errors))
); );
TRACE_EVENT(afs_cm_no_server, TRACE_EVENT(afs_cm_no_server,

View File

@ -83,6 +83,7 @@
const struct kvec *kvec; \ const struct kvec *kvec; \
struct kvec v; \ struct kvec v; \
iterate_kvec(i, n, v, kvec, skip, (K)) \ iterate_kvec(i, n, v, kvec, skip, (K)) \
} else if (unlikely(i->type & ITER_DISCARD)) { \
} else { \ } else { \
const struct iovec *iov; \ const struct iovec *iov; \
struct iovec v; \ struct iovec v; \
@ -114,6 +115,8 @@
} \ } \
i->nr_segs -= kvec - i->kvec; \ i->nr_segs -= kvec - i->kvec; \
i->kvec = kvec; \ i->kvec = kvec; \
} else if (unlikely(i->type & ITER_DISCARD)) { \
skip += n; \
} else { \ } else { \
const struct iovec *iov; \ const struct iovec *iov; \
struct iovec v; \ struct iovec v; \
@ -428,17 +431,19 @@ int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
} }
EXPORT_SYMBOL(iov_iter_fault_in_readable); EXPORT_SYMBOL(iov_iter_fault_in_readable);
void iov_iter_init(struct iov_iter *i, int direction, void iov_iter_init(struct iov_iter *i, unsigned int direction,
const struct iovec *iov, unsigned long nr_segs, const struct iovec *iov, unsigned long nr_segs,
size_t count) size_t count)
{ {
WARN_ON(direction & ~(READ | WRITE));
direction &= READ | WRITE;
/* It will get better. Eventually... */ /* It will get better. Eventually... */
if (uaccess_kernel()) { if (uaccess_kernel()) {
direction |= ITER_KVEC; i->type = ITER_KVEC | direction;
i->type = direction;
i->kvec = (struct kvec *)iov; i->kvec = (struct kvec *)iov;
} else { } else {
i->type = direction; i->type = ITER_IOVEC | direction;
i->iov = iov; i->iov = iov;
} }
i->nr_segs = nr_segs; i->nr_segs = nr_segs;
@ -558,7 +563,7 @@ static size_t copy_pipe_to_iter(const void *addr, size_t bytes,
size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
{ {
const char *from = addr; const char *from = addr;
if (unlikely(i->type & ITER_PIPE)) if (unlikely(iov_iter_is_pipe(i)))
return copy_pipe_to_iter(addr, bytes, i); return copy_pipe_to_iter(addr, bytes, i);
if (iter_is_iovec(i)) if (iter_is_iovec(i))
might_fault(); might_fault();
@ -658,7 +663,7 @@ size_t _copy_to_iter_mcsafe(const void *addr, size_t bytes, struct iov_iter *i)
const char *from = addr; const char *from = addr;
unsigned long rem, curr_addr, s_addr = (unsigned long) addr; unsigned long rem, curr_addr, s_addr = (unsigned long) addr;
if (unlikely(i->type & ITER_PIPE)) if (unlikely(iov_iter_is_pipe(i)))
return copy_pipe_to_iter_mcsafe(addr, bytes, i); return copy_pipe_to_iter_mcsafe(addr, bytes, i);
if (iter_is_iovec(i)) if (iter_is_iovec(i))
might_fault(); might_fault();
@ -692,7 +697,7 @@ EXPORT_SYMBOL_GPL(_copy_to_iter_mcsafe);
size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
{ {
char *to = addr; char *to = addr;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
WARN_ON(1); WARN_ON(1);
return 0; return 0;
} }
@ -712,7 +717,7 @@ EXPORT_SYMBOL(_copy_from_iter);
bool _copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) bool _copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i)
{ {
char *to = addr; char *to = addr;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
WARN_ON(1); WARN_ON(1);
return false; return false;
} }
@ -739,7 +744,7 @@ EXPORT_SYMBOL(_copy_from_iter_full);
size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i)
{ {
char *to = addr; char *to = addr;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
WARN_ON(1); WARN_ON(1);
return 0; return 0;
} }
@ -773,7 +778,7 @@ EXPORT_SYMBOL(_copy_from_iter_nocache);
size_t _copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i) size_t _copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i)
{ {
char *to = addr; char *to = addr;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
WARN_ON(1); WARN_ON(1);
return 0; return 0;
} }
@ -794,7 +799,7 @@ EXPORT_SYMBOL_GPL(_copy_from_iter_flushcache);
bool _copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i) bool _copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i)
{ {
char *to = addr; char *to = addr;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
WARN_ON(1); WARN_ON(1);
return false; return false;
} }
@ -836,7 +841,9 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
size_t wanted = copy_to_iter(kaddr + offset, bytes, i); size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
kunmap_atomic(kaddr); kunmap_atomic(kaddr);
return wanted; return wanted;
} else if (likely(!(i->type & ITER_PIPE))) } else if (unlikely(iov_iter_is_discard(i)))
return bytes;
else if (likely(!iov_iter_is_pipe(i)))
return copy_page_to_iter_iovec(page, offset, bytes, i); return copy_page_to_iter_iovec(page, offset, bytes, i);
else else
return copy_page_to_iter_pipe(page, offset, bytes, i); return copy_page_to_iter_pipe(page, offset, bytes, i);
@ -848,7 +855,7 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
{ {
if (unlikely(!page_copy_sane(page, offset, bytes))) if (unlikely(!page_copy_sane(page, offset, bytes)))
return 0; return 0;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
WARN_ON(1); WARN_ON(1);
return 0; return 0;
} }
@ -888,7 +895,7 @@ static size_t pipe_zero(size_t bytes, struct iov_iter *i)
size_t iov_iter_zero(size_t bytes, struct iov_iter *i) size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
{ {
if (unlikely(i->type & ITER_PIPE)) if (unlikely(iov_iter_is_pipe(i)))
return pipe_zero(bytes, i); return pipe_zero(bytes, i);
iterate_and_advance(i, bytes, v, iterate_and_advance(i, bytes, v,
clear_user(v.iov_base, v.iov_len), clear_user(v.iov_base, v.iov_len),
@ -908,7 +915,7 @@ size_t iov_iter_copy_from_user_atomic(struct page *page,
kunmap_atomic(kaddr); kunmap_atomic(kaddr);
return 0; return 0;
} }
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
kunmap_atomic(kaddr); kunmap_atomic(kaddr);
WARN_ON(1); WARN_ON(1);
return 0; return 0;
@ -972,10 +979,14 @@ static void pipe_advance(struct iov_iter *i, size_t size)
void iov_iter_advance(struct iov_iter *i, size_t size) void iov_iter_advance(struct iov_iter *i, size_t size)
{ {
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
pipe_advance(i, size); pipe_advance(i, size);
return; return;
} }
if (unlikely(iov_iter_is_discard(i))) {
i->count -= size;
return;
}
iterate_and_advance(i, size, v, 0, 0, 0) iterate_and_advance(i, size, v, 0, 0, 0)
} }
EXPORT_SYMBOL(iov_iter_advance); EXPORT_SYMBOL(iov_iter_advance);
@ -987,7 +998,7 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll)
if (WARN_ON(unroll > MAX_RW_COUNT)) if (WARN_ON(unroll > MAX_RW_COUNT))
return; return;
i->count += unroll; i->count += unroll;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
struct pipe_inode_info *pipe = i->pipe; struct pipe_inode_info *pipe = i->pipe;
int idx = i->idx; int idx = i->idx;
size_t off = i->iov_offset; size_t off = i->iov_offset;
@ -1011,12 +1022,14 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll)
pipe_truncate(i); pipe_truncate(i);
return; return;
} }
if (unlikely(iov_iter_is_discard(i)))
return;
if (unroll <= i->iov_offset) { if (unroll <= i->iov_offset) {
i->iov_offset -= unroll; i->iov_offset -= unroll;
return; return;
} }
unroll -= i->iov_offset; unroll -= i->iov_offset;
if (i->type & ITER_BVEC) { if (iov_iter_is_bvec(i)) {
const struct bio_vec *bvec = i->bvec; const struct bio_vec *bvec = i->bvec;
while (1) { while (1) {
size_t n = (--bvec)->bv_len; size_t n = (--bvec)->bv_len;
@ -1049,23 +1062,25 @@ EXPORT_SYMBOL(iov_iter_revert);
*/ */
size_t iov_iter_single_seg_count(const struct iov_iter *i) size_t iov_iter_single_seg_count(const struct iov_iter *i)
{ {
if (unlikely(i->type & ITER_PIPE)) if (unlikely(iov_iter_is_pipe(i)))
return i->count; // it is a silly place, anyway return i->count; // it is a silly place, anyway
if (i->nr_segs == 1) if (i->nr_segs == 1)
return i->count; return i->count;
else if (i->type & ITER_BVEC) if (unlikely(iov_iter_is_discard(i)))
return i->count;
else if (iov_iter_is_bvec(i))
return min(i->count, i->bvec->bv_len - i->iov_offset); return min(i->count, i->bvec->bv_len - i->iov_offset);
else else
return min(i->count, i->iov->iov_len - i->iov_offset); return min(i->count, i->iov->iov_len - i->iov_offset);
} }
EXPORT_SYMBOL(iov_iter_single_seg_count); EXPORT_SYMBOL(iov_iter_single_seg_count);
void iov_iter_kvec(struct iov_iter *i, int direction, void iov_iter_kvec(struct iov_iter *i, unsigned int direction,
const struct kvec *kvec, unsigned long nr_segs, const struct kvec *kvec, unsigned long nr_segs,
size_t count) size_t count)
{ {
BUG_ON(!(direction & ITER_KVEC)); WARN_ON(direction & ~(READ | WRITE));
i->type = direction; i->type = ITER_KVEC | (direction & (READ | WRITE));
i->kvec = kvec; i->kvec = kvec;
i->nr_segs = nr_segs; i->nr_segs = nr_segs;
i->iov_offset = 0; i->iov_offset = 0;
@ -1073,12 +1088,12 @@ void iov_iter_kvec(struct iov_iter *i, int direction,
} }
EXPORT_SYMBOL(iov_iter_kvec); EXPORT_SYMBOL(iov_iter_kvec);
void iov_iter_bvec(struct iov_iter *i, int direction, void iov_iter_bvec(struct iov_iter *i, unsigned int direction,
const struct bio_vec *bvec, unsigned long nr_segs, const struct bio_vec *bvec, unsigned long nr_segs,
size_t count) size_t count)
{ {
BUG_ON(!(direction & ITER_BVEC)); WARN_ON(direction & ~(READ | WRITE));
i->type = direction; i->type = ITER_BVEC | (direction & (READ | WRITE));
i->bvec = bvec; i->bvec = bvec;
i->nr_segs = nr_segs; i->nr_segs = nr_segs;
i->iov_offset = 0; i->iov_offset = 0;
@ -1086,13 +1101,13 @@ void iov_iter_bvec(struct iov_iter *i, int direction,
} }
EXPORT_SYMBOL(iov_iter_bvec); EXPORT_SYMBOL(iov_iter_bvec);
void iov_iter_pipe(struct iov_iter *i, int direction, void iov_iter_pipe(struct iov_iter *i, unsigned int direction,
struct pipe_inode_info *pipe, struct pipe_inode_info *pipe,
size_t count) size_t count)
{ {
BUG_ON(direction != ITER_PIPE); BUG_ON(direction != READ);
WARN_ON(pipe->nrbufs == pipe->buffers); WARN_ON(pipe->nrbufs == pipe->buffers);
i->type = direction; i->type = ITER_PIPE | READ;
i->pipe = pipe; i->pipe = pipe;
i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
i->iov_offset = 0; i->iov_offset = 0;
@ -1101,12 +1116,30 @@ void iov_iter_pipe(struct iov_iter *i, int direction,
} }
EXPORT_SYMBOL(iov_iter_pipe); EXPORT_SYMBOL(iov_iter_pipe);
/**
* iov_iter_discard - Initialise an I/O iterator that discards data
* @i: The iterator to initialise.
* @direction: The direction of the transfer.
* @count: The size of the I/O buffer in bytes.
*
* Set up an I/O iterator that just discards everything that's written to it.
* It's only available as a READ iterator.
*/
void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count)
{
BUG_ON(direction != READ);
i->type = ITER_DISCARD | READ;
i->count = count;
i->iov_offset = 0;
}
EXPORT_SYMBOL(iov_iter_discard);
unsigned long iov_iter_alignment(const struct iov_iter *i) unsigned long iov_iter_alignment(const struct iov_iter *i)
{ {
unsigned long res = 0; unsigned long res = 0;
size_t size = i->count; size_t size = i->count;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
if (size && i->iov_offset && allocated(&i->pipe->bufs[i->idx])) if (size && i->iov_offset && allocated(&i->pipe->bufs[i->idx]))
return size | i->iov_offset; return size | i->iov_offset;
return size; return size;
@ -1125,7 +1158,7 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
unsigned long res = 0; unsigned long res = 0;
size_t size = i->count; size_t size = i->count;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
WARN_ON(1); WARN_ON(1);
return ~0U; return ~0U;
} }
@ -1193,8 +1226,11 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
if (maxsize > i->count) if (maxsize > i->count)
maxsize = i->count; maxsize = i->count;
if (unlikely(i->type & ITER_PIPE)) if (unlikely(iov_iter_is_pipe(i)))
return pipe_get_pages(i, pages, maxsize, maxpages, start); return pipe_get_pages(i, pages, maxsize, maxpages, start);
if (unlikely(iov_iter_is_discard(i)))
return -EFAULT;
iterate_all_kinds(i, maxsize, v, ({ iterate_all_kinds(i, maxsize, v, ({
unsigned long addr = (unsigned long)v.iov_base; unsigned long addr = (unsigned long)v.iov_base;
size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1)); size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
@ -1205,7 +1241,7 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
len = maxpages * PAGE_SIZE; len = maxpages * PAGE_SIZE;
addr &= ~(PAGE_SIZE - 1); addr &= ~(PAGE_SIZE - 1);
n = DIV_ROUND_UP(len, PAGE_SIZE); n = DIV_ROUND_UP(len, PAGE_SIZE);
res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages); res = get_user_pages_fast(addr, n, iov_iter_rw(i) != WRITE, pages);
if (unlikely(res < 0)) if (unlikely(res < 0))
return res; return res;
return (res == n ? len : res * PAGE_SIZE) - *start; return (res == n ? len : res * PAGE_SIZE) - *start;
@ -1270,8 +1306,11 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
if (maxsize > i->count) if (maxsize > i->count)
maxsize = i->count; maxsize = i->count;
if (unlikely(i->type & ITER_PIPE)) if (unlikely(iov_iter_is_pipe(i)))
return pipe_get_pages_alloc(i, pages, maxsize, start); return pipe_get_pages_alloc(i, pages, maxsize, start);
if (unlikely(iov_iter_is_discard(i)))
return -EFAULT;
iterate_all_kinds(i, maxsize, v, ({ iterate_all_kinds(i, maxsize, v, ({
unsigned long addr = (unsigned long)v.iov_base; unsigned long addr = (unsigned long)v.iov_base;
size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1)); size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
@ -1283,7 +1322,7 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
p = get_pages_array(n); p = get_pages_array(n);
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p); res = get_user_pages_fast(addr, n, iov_iter_rw(i) != WRITE, p);
if (unlikely(res < 0)) { if (unlikely(res < 0)) {
kvfree(p); kvfree(p);
return res; return res;
@ -1313,7 +1352,7 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
__wsum sum, next; __wsum sum, next;
size_t off = 0; size_t off = 0;
sum = *csum; sum = *csum;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
WARN_ON(1); WARN_ON(1);
return 0; return 0;
} }
@ -1355,7 +1394,7 @@ bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum,
__wsum sum, next; __wsum sum, next;
size_t off = 0; size_t off = 0;
sum = *csum; sum = *csum;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
WARN_ON(1); WARN_ON(1);
return false; return false;
} }
@ -1400,7 +1439,7 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum,
__wsum sum, next; __wsum sum, next;
size_t off = 0; size_t off = 0;
sum = *csum; sum = *csum;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
WARN_ON(1); /* for now */ WARN_ON(1); /* for now */
return 0; return 0;
} }
@ -1442,8 +1481,10 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages)
if (!size) if (!size)
return 0; return 0;
if (unlikely(iov_iter_is_discard(i)))
return 0;
if (unlikely(i->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(i))) {
struct pipe_inode_info *pipe = i->pipe; struct pipe_inode_info *pipe = i->pipe;
size_t off; size_t off;
int idx; int idx;
@ -1481,11 +1522,13 @@ EXPORT_SYMBOL(iov_iter_npages);
const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
{ {
*new = *old; *new = *old;
if (unlikely(new->type & ITER_PIPE)) { if (unlikely(iov_iter_is_pipe(new))) {
WARN_ON(1); WARN_ON(1);
return NULL; return NULL;
} }
if (new->type & ITER_BVEC) if (unlikely(iov_iter_is_discard(new)))
return NULL;
if (iov_iter_is_bvec(new))
return new->bvec = kmemdup(new->bvec, return new->bvec = kmemdup(new->bvec,
new->nr_segs * sizeof(struct bio_vec), new->nr_segs * sizeof(struct bio_vec),
flags); flags);

View File

@ -2049,7 +2049,7 @@ find_page:
!mapping->a_ops->is_partially_uptodate) !mapping->a_ops->is_partially_uptodate)
goto page_not_up_to_date; goto page_not_up_to_date;
/* pipes can't handle partially uptodate pages */ /* pipes can't handle partially uptodate pages */
if (unlikely(iter->type & ITER_PIPE)) if (unlikely(iov_iter_is_pipe(iter)))
goto page_not_up_to_date; goto page_not_up_to_date;
if (!trylock_page(page)) if (!trylock_page(page))
goto page_not_up_to_date; goto page_not_up_to_date;

View File

@ -294,7 +294,7 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc,
}; };
struct iov_iter from; struct iov_iter from;
iov_iter_bvec(&from, ITER_BVEC | WRITE, &bv, 1, PAGE_SIZE); iov_iter_bvec(&from, WRITE, &bv, 1, PAGE_SIZE);
init_sync_kiocb(&kiocb, swap_file); init_sync_kiocb(&kiocb, swap_file);
kiocb.ki_pos = page_file_offset(page); kiocb.ki_pos = page_file_offset(page);

View File

@ -2066,7 +2066,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
struct kvec kv = {.iov_base = data, .iov_len = count}; struct kvec kv = {.iov_base = data, .iov_len = count};
struct iov_iter to; struct iov_iter to;
iov_iter_kvec(&to, READ | ITER_KVEC, &kv, 1, count); iov_iter_kvec(&to, READ, &kv, 1, count);
p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
fid->fid, (unsigned long long) offset, count); fid->fid, (unsigned long long) offset, count);

View File

@ -329,7 +329,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
if (!iov_iter_count(data)) if (!iov_iter_count(data))
return 0; return 0;
if (!(data->type & ITER_KVEC)) { if (iov_iter_is_kvec(data)) {
int n; int n;
/* /*
* We allow only p9_max_pages pinned. We wait for the * We allow only p9_max_pages pinned. We wait for the

View File

@ -467,7 +467,7 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
iv.iov_len = skb->len; iv.iov_len = skb->len;
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iv, 1, skb->len); iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, skb->len);
err = l2cap_chan_send(chan, &msg, skb->len); err = l2cap_chan_send(chan, &msg, skb->len);
if (err > 0) { if (err > 0) {

View File

@ -63,7 +63,7 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *dat
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iv, 1, total_len); iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, total_len);
l2cap_chan_send(chan, &msg, total_len); l2cap_chan_send(chan, &msg, total_len);

View File

@ -622,7 +622,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iv, 2, 1 + len); iov_iter_kvec(&msg.msg_iter, WRITE, iv, 2, 1 + len);
l2cap_chan_send(chan, &msg, 1 + len); l2cap_chan_send(chan, &msg, 1 + len);

View File

@ -513,7 +513,7 @@ static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
if (!buf) if (!buf)
msg.msg_flags |= MSG_TRUNC; msg.msg_flags |= MSG_TRUNC;
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, len); iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, len);
r = sock_recvmsg(sock, &msg, msg.msg_flags); r = sock_recvmsg(sock, &msg, msg.msg_flags);
if (r == -EAGAIN) if (r == -EAGAIN)
r = 0; r = 0;
@ -532,7 +532,7 @@ static int ceph_tcp_recvpage(struct socket *sock, struct page *page,
int r; int r;
BUG_ON(page_offset + length > PAGE_SIZE); BUG_ON(page_offset + length > PAGE_SIZE);
iov_iter_bvec(&msg.msg_iter, READ | ITER_BVEC, &bvec, 1, length); iov_iter_bvec(&msg.msg_iter, READ, &bvec, 1, length);
r = sock_recvmsg(sock, &msg, msg.msg_flags); r = sock_recvmsg(sock, &msg, msg.msg_flags);
if (r == -EAGAIN) if (r == -EAGAIN)
r = 0; r = 0;
@ -594,7 +594,7 @@ static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
else else
msg.msg_flags |= MSG_EOR; /* superfluous, but what the hell */ msg.msg_flags |= MSG_EOR; /* superfluous, but what the hell */
iov_iter_bvec(&msg.msg_iter, WRITE | ITER_BVEC, &bvec, 1, size); iov_iter_bvec(&msg.msg_iter, WRITE, &bvec, 1, size);
ret = sock_sendmsg(sock, &msg); ret = sock_sendmsg(sock, &msg);
if (ret == -EAGAIN) if (ret == -EAGAIN)
ret = 0; ret = 0;

View File

@ -1616,7 +1616,7 @@ ip_vs_receive(struct socket *sock, char *buffer, const size_t buflen)
EnterFunction(7); EnterFunction(7);
/* Receive a packet */ /* Receive a packet */
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, buflen); iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, buflen);
len = sock_recvmsg(sock, &msg, MSG_DONTWAIT); len = sock_recvmsg(sock, &msg, MSG_DONTWAIT);
if (len < 0) if (len < 0)
return len; return len;

View File

@ -286,7 +286,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
*/ */
krflags = MSG_PEEK | MSG_WAITALL; krflags = MSG_PEEK | MSG_WAITALL;
smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME; smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME;
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &vec, 1, iov_iter_kvec(&msg.msg_iter, READ, &vec, 1,
sizeof(struct smc_clc_msg_hdr)); sizeof(struct smc_clc_msg_hdr));
len = sock_recvmsg(smc->clcsock, &msg, krflags); len = sock_recvmsg(smc->clcsock, &msg, krflags);
if (signal_pending(current)) { if (signal_pending(current)) {
@ -325,7 +325,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
/* receive the complete CLC message */ /* receive the complete CLC message */
memset(&msg, 0, sizeof(struct msghdr)); memset(&msg, 0, sizeof(struct msghdr));
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &vec, 1, datlen); iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, datlen);
krflags = MSG_WAITALL; krflags = MSG_WAITALL;
len = sock_recvmsg(smc->clcsock, &msg, krflags); len = sock_recvmsg(smc->clcsock, &msg, krflags);
if (len < datlen || !smc_clc_msg_hdr_valid(clcm)) { if (len < datlen || !smc_clc_msg_hdr_valid(clcm)) {

View File

@ -635,7 +635,7 @@ EXPORT_SYMBOL(sock_sendmsg);
int kernel_sendmsg(struct socket *sock, struct msghdr *msg, int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size) struct kvec *vec, size_t num, size_t size)
{ {
iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size); iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size);
return sock_sendmsg(sock, msg); return sock_sendmsg(sock, msg);
} }
EXPORT_SYMBOL(kernel_sendmsg); EXPORT_SYMBOL(kernel_sendmsg);
@ -648,7 +648,7 @@ int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
if (!sock->ops->sendmsg_locked) if (!sock->ops->sendmsg_locked)
return sock_no_sendmsg_locked(sk, msg, size); return sock_no_sendmsg_locked(sk, msg, size);
iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size); iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size);
return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg)); return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg));
} }
@ -823,7 +823,7 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
mm_segment_t oldfs = get_fs(); mm_segment_t oldfs = get_fs();
int result; int result;
iov_iter_kvec(&msg->msg_iter, READ | ITER_KVEC, vec, num, size); iov_iter_kvec(&msg->msg_iter, READ, vec, num, size);
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
result = sock_recvmsg(sock, msg, flags); result = sock_recvmsg(sock, msg, flags);
set_fs(oldfs); set_fs(oldfs);

View File

@ -336,7 +336,7 @@ static ssize_t svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov,
rqstp->rq_xprt_hlen = 0; rqstp->rq_xprt_hlen = 0;
clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, iov, nr, buflen); iov_iter_kvec(&msg.msg_iter, READ, iov, nr, buflen);
if (base != 0) { if (base != 0) {
iov_iter_advance(&msg.msg_iter, base); iov_iter_advance(&msg.msg_iter, base);
buflen -= base; buflen -= base;

View File

@ -361,7 +361,7 @@ static ssize_t
xs_read_kvec(struct socket *sock, struct msghdr *msg, int flags, xs_read_kvec(struct socket *sock, struct msghdr *msg, int flags,
struct kvec *kvec, size_t count, size_t seek) struct kvec *kvec, size_t count, size_t seek)
{ {
iov_iter_kvec(&msg->msg_iter, READ | ITER_KVEC, kvec, 1, count); iov_iter_kvec(&msg->msg_iter, READ, kvec, 1, count);
return xs_sock_recvmsg(sock, msg, flags, seek); return xs_sock_recvmsg(sock, msg, flags, seek);
} }
@ -370,7 +370,7 @@ xs_read_bvec(struct socket *sock, struct msghdr *msg, int flags,
struct bio_vec *bvec, unsigned long nr, size_t count, struct bio_vec *bvec, unsigned long nr, size_t count,
size_t seek) size_t seek)
{ {
iov_iter_bvec(&msg->msg_iter, READ | ITER_BVEC, bvec, nr, count); iov_iter_bvec(&msg->msg_iter, READ, bvec, nr, count);
return xs_sock_recvmsg(sock, msg, flags, seek); return xs_sock_recvmsg(sock, msg, flags, seek);
} }

View File

@ -394,7 +394,7 @@ static int tipc_conn_rcv_from_sock(struct tipc_conn *con)
iov.iov_base = &s; iov.iov_base = &s;
iov.iov_len = sizeof(s); iov.iov_len = sizeof(s);
msg.msg_name = NULL; msg.msg_name = NULL;
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, iov.iov_len); iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, iov.iov_len);
ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT); ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT);
if (ret == -EWOULDBLOCK) if (ret == -EWOULDBLOCK)
return -EWOULDBLOCK; return -EWOULDBLOCK;

View File

@ -489,7 +489,7 @@ int tls_device_sendpage(struct sock *sk, struct page *page,
iov.iov_base = kaddr + offset; iov.iov_base = kaddr + offset;
iov.iov_len = size; iov.iov_len = size;
iov_iter_kvec(&msg_iter, WRITE | ITER_KVEC, &iov, 1, size); iov_iter_kvec(&msg_iter, WRITE, &iov, 1, size);
rc = tls_push_data(sk, &msg_iter, size, rc = tls_push_data(sk, &msg_iter, size,
flags, TLS_RECORD_TYPE_DATA); flags, TLS_RECORD_TYPE_DATA);
kunmap(page); kunmap(page);
@ -538,7 +538,7 @@ static int tls_device_push_pending_record(struct sock *sk, int flags)
{ {
struct iov_iter msg_iter; struct iov_iter msg_iter;
iov_iter_kvec(&msg_iter, WRITE | ITER_KVEC, NULL, 0, 0); iov_iter_kvec(&msg_iter, WRITE, NULL, 0, 0);
return tls_push_data(sk, &msg_iter, 0, flags, TLS_RECORD_TYPE_DATA); return tls_push_data(sk, &msg_iter, 0, flags, TLS_RECORD_TYPE_DATA);
} }

View File

@ -799,7 +799,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
struct crypto_tfm *tfm = crypto_aead_tfm(ctx->aead_send); struct crypto_tfm *tfm = crypto_aead_tfm(ctx->aead_send);
bool async_capable = tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC; bool async_capable = tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC;
unsigned char record_type = TLS_RECORD_TYPE_DATA; unsigned char record_type = TLS_RECORD_TYPE_DATA;
bool is_kvec = msg->msg_iter.type & ITER_KVEC; bool is_kvec = iov_iter_is_kvec(&msg->msg_iter);
bool eor = !(msg->msg_flags & MSG_MORE); bool eor = !(msg->msg_flags & MSG_MORE);
size_t try_to_copy, copied = 0; size_t try_to_copy, copied = 0;
struct sk_msg *msg_pl, *msg_en; struct sk_msg *msg_pl, *msg_en;
@ -1457,7 +1457,7 @@ int tls_sw_recvmsg(struct sock *sk,
bool cmsg = false; bool cmsg = false;
int target, err = 0; int target, err = 0;
long timeo; long timeo;
bool is_kvec = msg->msg_iter.type & ITER_KVEC; bool is_kvec = iov_iter_is_kvec(&msg->msg_iter);
int num_async = 0; int num_async = 0;
flags |= nonblock; flags |= nonblock;