Unverified Commit f28fc201 authored by David Howells's avatar David Howells Committed by Christian Brauner
Browse files

afs: Eliminate afs_read



Now that directory and symlink reads go through netfslib, the afs_read
struct is mostly redundant with almost all data duplicated in the
netfs_io_request and netfs_io_subrequest structs that are also available
any time we're doing a fetch.

Eliminate afs_read by moving the one field we still need there to the
afs_call struct (we may be given a different amount of data than what we
asked for and have to track what remains of that) and using the
netfs_io_subrequest directly instead.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20241216204124.3752367-24-dhowells@redhat.com


cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent eae9e789
Loading
Loading
Loading
Loading
+18 −78
Original line number Diff line number Diff line
@@ -200,50 +200,12 @@ int afs_release(struct inode *inode, struct file *file)
	return ret;
}

/*
 * Allocate a new read record.
 */
struct afs_read *afs_alloc_read(gfp_t gfp)
{
	struct afs_read *req;

	req = kzalloc(sizeof(struct afs_read), gfp);
	if (req)
		refcount_set(&req->usage, 1);

	return req;
}

/*
 * Dispose of a ref to a read record.
 */
void afs_put_read(struct afs_read *req)
{
	if (refcount_dec_and_test(&req->usage)) {
		if (req->cleanup)
			req->cleanup(req);
		key_put(req->key);
		kfree(req);
	}
}

static void afs_fetch_data_notify(struct afs_operation *op)
{
	struct afs_read *req = op->fetch.req;
	struct netfs_io_subrequest *subreq = req->subreq;
	int error = afs_op_error(op);

	req->error = error;
	if (subreq) {
		subreq->rreq->i_size = req->file_size;
		if (req->pos + req->actual_len >= req->file_size)
			__set_bit(NETFS_SREQ_HIT_EOF, &subreq->flags);
		subreq->error = error;
	struct netfs_io_subrequest *subreq = op->fetch.subreq;

	subreq->error = afs_op_error(op);
	netfs_read_subreq_terminated(subreq);
		req->subreq = NULL;
	} else if (req->done) {
		req->done(req);
	}
}

static void afs_fetch_data_success(struct afs_operation *op)
@@ -253,7 +215,7 @@ static void afs_fetch_data_success(struct afs_operation *op)
	_enter("op=%08x", op->debug_id);
	afs_vnode_commit_status(op, &op->file[0]);
	afs_stat_v(vnode, n_fetches);
	atomic_long_add(op->fetch.req->actual_len, &op->net->n_fetch_bytes);
	atomic_long_add(op->fetch.subreq->transferred, &op->net->n_fetch_bytes);
	afs_fetch_data_notify(op);
}

@@ -265,11 +227,10 @@ static void afs_fetch_data_aborted(struct afs_operation *op)

static void afs_fetch_data_put(struct afs_operation *op)
{
	op->fetch.req->error = afs_op_error(op);
	afs_put_read(op->fetch.req);
	op->fetch.subreq->error = afs_op_error(op);
}

static const struct afs_operation_ops afs_fetch_data_operation = {
const struct afs_operation_ops afs_fetch_data_operation = {
	.issue_afs_rpc	= afs_fs_fetch_data,
	.issue_yfs_rpc	= yfs_fs_fetch_data,
	.success	= afs_fetch_data_success,
@@ -281,55 +242,34 @@ static const struct afs_operation_ops afs_fetch_data_operation = {
/*
 * Fetch file data from the volume.
 */
int afs_fetch_data(struct afs_vnode *vnode, struct afs_read *req)
static void afs_read_worker(struct work_struct *work)
{
	struct netfs_io_subrequest *subreq = container_of(work, struct netfs_io_subrequest, work);
	struct afs_operation *op;
	struct afs_vnode *vnode = AFS_FS_I(subreq->rreq->inode);
	struct key *key = subreq->rreq->netfs_priv;

	_enter("%s{%llx:%llu.%u},%x,,,",
	       vnode->volume->name,
	       vnode->fid.vid,
	       vnode->fid.vnode,
	       vnode->fid.unique,
	       key_serial(req->key));
	       key_serial(key));

	op = afs_alloc_operation(req->key, vnode->volume);
	op = afs_alloc_operation(key, vnode->volume);
	if (IS_ERR(op)) {
		if (req->subreq) {
			req->subreq->error = PTR_ERR(op);
			netfs_read_subreq_terminated(req->subreq);
		}
		return PTR_ERR(op);
		subreq->error = PTR_ERR(op);
		netfs_read_subreq_terminated(subreq);
		return;
	}

	afs_op_set_vnode(op, 0, vnode);

	op->fetch.req	= afs_get_read(req);
	op->fetch.subreq = subreq;
	op->ops		= &afs_fetch_data_operation;
	return afs_do_sync_operation(op);
}

static void afs_read_worker(struct work_struct *work)
{
	struct netfs_io_subrequest *subreq = container_of(work, struct netfs_io_subrequest, work);
	struct afs_vnode *vnode = AFS_FS_I(subreq->rreq->inode);
	struct afs_read *fsreq;

	fsreq = afs_alloc_read(GFP_NOFS);
	if (!fsreq) {
		subreq->error = -ENOMEM;
		return netfs_read_subreq_terminated(subreq);
	}

	fsreq->subreq	= subreq;
	fsreq->pos	= subreq->start + subreq->transferred;
	fsreq->len	= subreq->len   - subreq->transferred;
	fsreq->key	= key_get(subreq->rreq->netfs_priv);
	fsreq->vnode	= vnode;
	fsreq->iter	= &subreq->io_iter;

	trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
	afs_fetch_data(fsreq->vnode, fsreq);
	afs_put_read(fsreq);
	afs_do_sync_operation(op);
}

static void afs_issue_read(struct netfs_io_subrequest *subreq)
+26 −29
Original line number Diff line number Diff line
@@ -301,19 +301,19 @@ void afs_fs_fetch_status(struct afs_operation *op)
static int afs_deliver_fs_fetch_data(struct afs_call *call)
{
	struct afs_operation *op = call->op;
	struct netfs_io_subrequest *subreq = op->fetch.subreq;
	struct afs_vnode_param *vp = &op->file[0];
	struct afs_read *req = op->fetch.req;
	const __be32 *bp;
	size_t count_before;
	int ret;

	_enter("{%u,%zu,%zu/%llu}",
	       call->unmarshall, call->iov_len, iov_iter_count(call->iter),
	       req->actual_len);
	       call->remaining);

	switch (call->unmarshall) {
	case 0:
		req->actual_len = 0;
		call->remaining = 0;
		call->unmarshall++;
		if (call->operation_ID == FSFETCHDATA64) {
			afs_extract_to_tmp64(call);
@@ -323,8 +323,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
		}
		fallthrough;

		/* Extract the returned data length into
		 * ->actual_len.  This may indicate more or less data than was
		/* Extract the returned data length into ->remaining.
		 * This may indicate more or less data than was
		 * requested will be returned.
		 */
	case 1:
@@ -333,42 +333,41 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
		if (ret < 0)
			return ret;

		req->actual_len = be64_to_cpu(call->tmp64);
		_debug("DATA length: %llu", req->actual_len);
		call->remaining = be64_to_cpu(call->tmp64);
		_debug("DATA length: %llu", call->remaining);

		if (req->actual_len == 0)
		if (call->remaining == 0)
			goto no_more_data;

		call->iter = req->iter;
		call->iov_len = min(req->actual_len, req->len);
		call->iter = &subreq->io_iter;
		call->iov_len = umin(call->remaining, subreq->len - subreq->transferred);
		call->unmarshall++;
		fallthrough;

		/* extract the returned data */
	case 2:
		count_before = call->iov_len;
		_debug("extract data %zu/%llu", count_before, req->actual_len);
		_debug("extract data %zu/%llu", count_before, call->remaining);

		ret = afs_extract_data(call, true);
		if (req->subreq) {
			req->subreq->transferred += count_before - call->iov_len;
			netfs_read_subreq_progress(req->subreq);
		}
		subreq->transferred += count_before - call->iov_len;
		call->remaining -= count_before - call->iov_len;
		netfs_read_subreq_progress(subreq);
		if (ret < 0)
			return ret;

		call->iter = &call->def_iter;
		if (req->actual_len <= req->len)
		if (call->remaining)
			goto no_more_data;

		/* Discard any excess data the server gave us */
		afs_extract_discard(call, req->actual_len - req->len);
		afs_extract_discard(call, call->remaining);
		call->unmarshall = 3;
		fallthrough;

	case 3:
		_debug("extract discard %zu/%llu",
		       iov_iter_count(call->iter), req->actual_len - req->len);
		       iov_iter_count(call->iter), call->remaining);

		ret = afs_extract_data(call, true);
		if (ret < 0)
@@ -390,8 +389,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
		xdr_decode_AFSCallBack(&bp, call, &vp->scb);
		xdr_decode_AFSVolSync(&bp, &op->volsync);

		req->data_version = vp->scb.status.data_version;
		req->file_size = vp->scb.status.size;
		if (subreq->start + subreq->transferred >= vp->scb.status.size)
			__set_bit(NETFS_SREQ_HIT_EOF, &subreq->flags);

		call->unmarshall++;
		fallthrough;
@@ -426,8 +425,8 @@ static const struct afs_call_type afs_RXFSFetchData64 = {
 */
static void afs_fs_fetch_data64(struct afs_operation *op)
{
	struct netfs_io_subrequest *subreq = op->fetch.subreq;
	struct afs_vnode_param *vp = &op->file[0];
	struct afs_read *req = op->fetch.req;
	struct afs_call *call;
	__be32 *bp;

@@ -443,10 +442,10 @@ static void afs_fs_fetch_data64(struct afs_operation *op)
	bp[1] = htonl(vp->fid.vid);
	bp[2] = htonl(vp->fid.vnode);
	bp[3] = htonl(vp->fid.unique);
	bp[4] = htonl(upper_32_bits(req->pos));
	bp[5] = htonl(lower_32_bits(req->pos));
	bp[4] = htonl(upper_32_bits(subreq->start + subreq->transferred));
	bp[5] = htonl(lower_32_bits(subreq->start + subreq->transferred));
	bp[6] = 0;
	bp[7] = htonl(lower_32_bits(req->len));
	bp[7] = htonl(lower_32_bits(subreq->len   - subreq->transferred));

	call->fid = vp->fid;
	trace_afs_make_fs_call(call, &vp->fid);
@@ -458,9 +457,9 @@ static void afs_fs_fetch_data64(struct afs_operation *op)
 */
void afs_fs_fetch_data(struct afs_operation *op)
{
	struct netfs_io_subrequest *subreq = op->fetch.subreq;
	struct afs_vnode_param *vp = &op->file[0];
	struct afs_call *call;
	struct afs_read *req = op->fetch.req;
	__be32 *bp;

	if (test_bit(AFS_SERVER_FL_HAS_FS64, &op->server->flags))
@@ -472,16 +471,14 @@ void afs_fs_fetch_data(struct afs_operation *op)
	if (!call)
		return afs_op_nomem(op);

	req->call_debug_id = call->debug_id;

	/* marshall the parameters */
	bp = call->request;
	bp[0] = htonl(FSFETCHDATA);
	bp[1] = htonl(vp->fid.vid);
	bp[2] = htonl(vp->fid.vnode);
	bp[3] = htonl(vp->fid.unique);
	bp[4] = htonl(lower_32_bits(req->pos));
	bp[5] = htonl(lower_32_bits(req->len));
	bp[4] = htonl(lower_32_bits(subreq->start + subreq->transferred));
	bp[5] = htonl(lower_32_bits(subreq->len   + subreq->transferred));

	call->fid = vp->fid;
	trace_afs_make_fs_call(call, &vp->fid);
+2 −0
Original line number Diff line number Diff line
@@ -317,6 +317,8 @@ static void afs_apply_status(struct afs_operation *op,
			inode_set_ctime_to_ts(inode, t);
			inode_set_atime_to_ts(inode, t);
		}
		if (op->ops == &afs_fetch_data_operation)
			op->fetch.subreq->rreq->i_size = status->size;
	}
}

+3 −32
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ struct afs_call {
	spinlock_t		state_lock;
	int			error;		/* error code */
	u32			abort_code;	/* Remote abort ID or 0 */
	unsigned long long	remaining;	/* How much is left to receive */
	unsigned int		max_lifespan;	/* Maximum lifespan in secs to set if not 0 */
	unsigned		request_size;	/* size of request data */
	unsigned		reply_max;	/* maximum size of reply */
@@ -232,28 +233,6 @@ static inline struct key *afs_file_key(struct file *file)
	return af->key;
}

/*
 * Record of an outstanding read operation on a vnode.
 */
struct afs_read {
	loff_t			pos;		/* Where to start reading */
	loff_t			len;		/* How much we're asking for */
	loff_t			actual_len;	/* How much we're actually getting */
	loff_t			file_size;	/* File size returned by server */
	struct key		*key;		/* The key to use to reissue the read */
	struct afs_vnode	*vnode;		/* The file being read into. */
	struct netfs_io_subrequest *subreq;	/* Fscache helper read request this belongs to */
	afs_dataversion_t	data_version;	/* Version number returned by server */
	refcount_t		usage;
	unsigned int		call_debug_id;
	unsigned int		nr_pages;
	int			error;
	void (*done)(struct afs_read *);
	void (*cleanup)(struct afs_read *);
	struct iov_iter		*iter;		/* Iterator representing the buffer */
	struct iov_iter		def_iter;	/* Default iterator */
};

/*
 * AFS superblock private data
 * - there's one superblock per volume
@@ -911,7 +890,7 @@ struct afs_operation {
			bool	new_negative;
		} rename;
		struct {
			struct afs_read *req;
			struct netfs_io_subrequest *subreq;
		} fetch;
		struct {
			afs_lock_type_t type;
@@ -1118,21 +1097,13 @@ extern void afs_dynroot_depopulate(struct super_block *);
extern const struct address_space_operations afs_file_aops;
extern const struct inode_operations afs_file_inode_operations;
extern const struct file_operations afs_file_operations;
extern const struct afs_operation_ops afs_fetch_data_operation;
extern const struct netfs_request_ops afs_req_ops;

extern int afs_cache_wb_key(struct afs_vnode *, struct afs_file *);
extern void afs_put_wb_key(struct afs_wb_key *);
extern int afs_open(struct inode *, struct file *);
extern int afs_release(struct inode *, struct file *);
extern int afs_fetch_data(struct afs_vnode *, struct afs_read *);
extern struct afs_read *afs_alloc_read(gfp_t);
extern void afs_put_read(struct afs_read *);

static inline struct afs_read *afs_get_read(struct afs_read *req)
{
	refcount_inc(&req->usage);
	return req;
}

/*
 * flock.c
+22 −25
Original line number Diff line number Diff line
@@ -352,19 +352,19 @@ static int yfs_deliver_status_and_volsync(struct afs_call *call)
static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
{
	struct afs_operation *op = call->op;
	struct netfs_io_subrequest *subreq = op->fetch.subreq;
	struct afs_vnode_param *vp = &op->file[0];
	struct afs_read *req = op->fetch.req;
	const __be32 *bp;
	size_t count_before;
	int ret;

	_enter("{%u,%zu, %zu/%llu}",
	       call->unmarshall, call->iov_len, iov_iter_count(call->iter),
	       req->actual_len);
	       call->remaining);

	switch (call->unmarshall) {
	case 0:
		req->actual_len = 0;
		call->remaining = 0;
		afs_extract_to_tmp64(call);
		call->unmarshall++;
		fallthrough;
@@ -379,42 +379,40 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
		if (ret < 0)
			return ret;

		req->actual_len = be64_to_cpu(call->tmp64);
		_debug("DATA length: %llu", req->actual_len);
		call->remaining = be64_to_cpu(call->tmp64);
		_debug("DATA length: %llu", call->remaining);

		if (req->actual_len == 0)
		if (call->remaining == 0)
			goto no_more_data;

		call->iter = req->iter;
		call->iov_len = min(req->actual_len, req->len);
		call->iter = &subreq->io_iter;
		call->iov_len = min(call->remaining, subreq->len - subreq->transferred);
		call->unmarshall++;
		fallthrough;

		/* extract the returned data */
	case 2:
		count_before = call->iov_len;
		_debug("extract data %zu/%llu", count_before, req->actual_len);
		_debug("extract data %zu/%llu", count_before, call->remaining);

		ret = afs_extract_data(call, true);
		if (req->subreq) {
			req->subreq->transferred += count_before - call->iov_len;
			netfs_read_subreq_progress(req->subreq);
		}
		subreq->transferred += count_before - call->iov_len;
		netfs_read_subreq_progress(subreq);
		if (ret < 0)
			return ret;

		call->iter = &call->def_iter;
		if (req->actual_len <= req->len)
		if (call->remaining)
			goto no_more_data;

		/* Discard any excess data the server gave us */
		afs_extract_discard(call, req->actual_len - req->len);
		afs_extract_discard(call, call->remaining);
		call->unmarshall = 3;
		fallthrough;

	case 3:
		_debug("extract discard %zu/%llu",
		       iov_iter_count(call->iter), req->actual_len - req->len);
		       iov_iter_count(call->iter), call->remaining);

		ret = afs_extract_data(call, true);
		if (ret < 0)
@@ -439,8 +437,8 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
		xdr_decode_YFSCallBack(&bp, call, &vp->scb);
		xdr_decode_YFSVolSync(&bp, &op->volsync);

		req->data_version = vp->scb.status.data_version;
		req->file_size = vp->scb.status.size;
		if (subreq->start + subreq->transferred >= vp->scb.status.size)
			__set_bit(NETFS_SREQ_HIT_EOF, &subreq->flags);

		call->unmarshall++;
		fallthrough;
@@ -468,14 +466,15 @@ static const struct afs_call_type yfs_RXYFSFetchData64 = {
 */
void yfs_fs_fetch_data(struct afs_operation *op)
{
	struct netfs_io_subrequest *subreq = op->fetch.subreq;
	struct afs_vnode_param *vp = &op->file[0];
	struct afs_read *req = op->fetch.req;
	struct afs_call *call;
	__be32 *bp;

	_enter(",%x,{%llx:%llu},%llx,%llx",
	_enter(",%x,{%llx:%llu},%llx,%zx",
	       key_serial(op->key), vp->fid.vid, vp->fid.vnode,
	       req->pos, req->len);
	       subreq->start + subreq->transferred,
	       subreq->len   - subreq->transferred);

	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchData64,
				   sizeof(__be32) * 2 +
@@ -487,15 +486,13 @@ void yfs_fs_fetch_data(struct afs_operation *op)
	if (!call)
		return afs_op_nomem(op);

	req->call_debug_id = call->debug_id;

	/* marshall the parameters */
	bp = call->request;
	bp = xdr_encode_u32(bp, YFSFETCHDATA64);
	bp = xdr_encode_u32(bp, 0); /* RPC flags */
	bp = xdr_encode_YFSFid(bp, &vp->fid);
	bp = xdr_encode_u64(bp, req->pos);
	bp = xdr_encode_u64(bp, req->len);
	bp = xdr_encode_u64(bp, subreq->start + subreq->transferred);
	bp = xdr_encode_u64(bp, subreq->len   - subreq->transferred);
	yfs_check_req(call, bp);

	call->fid = vp->fid;
Loading