brintos

brintos / linux-shallow public Read only

0
0
Text · 6.4 KiB · 428721b Raw
279 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Fileserver-directed operation handling.3 *4 * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.5 * Written by David Howells (dhowells@redhat.com)6 */7 8#include <linux/kernel.h>9#include <linux/slab.h>10#include <linux/fs.h>11#include "internal.h"12 13static atomic_t afs_operation_debug_counter;14 15/*16 * Create an operation against a volume.17 */18struct afs_operation *afs_alloc_operation(struct key *key, struct afs_volume *volume)19{20	struct afs_operation *op;21 22	_enter("");23 24	op = kzalloc(sizeof(*op), GFP_KERNEL);25	if (!op)26		return ERR_PTR(-ENOMEM);27 28	if (!key) {29		key = afs_request_key(volume->cell);30		if (IS_ERR(key)) {31			kfree(op);32			return ERR_CAST(key);33		}34	} else {35		key_get(key);36	}37 38	op->key			= key;39	op->volume		= afs_get_volume(volume, afs_volume_trace_get_new_op);40	op->net			= volume->cell->net;41	op->cb_v_break		= atomic_read(&volume->cb_v_break);42	op->pre_volsync.creation = volume->creation_time;43	op->pre_volsync.update	= volume->update_time;44	op->debug_id		= atomic_inc_return(&afs_operation_debug_counter);45	op->nr_iterations	= -1;46	afs_op_set_error(op, -EDESTADDRREQ);47 48	_leave(" = [op=%08x]", op->debug_id);49	return op;50}51 52/*53 * Lock the vnode(s) being operated upon.54 */55static bool afs_get_io_locks(struct afs_operation *op)56{57	struct afs_vnode *vnode = op->file[0].vnode;58	struct afs_vnode *vnode2 = op->file[1].vnode;59 60	_enter("");61 62	if (op->flags & AFS_OPERATION_UNINTR) {63		mutex_lock(&vnode->io_lock);64		op->flags |= AFS_OPERATION_LOCK_0;65		_leave(" = t [1]");66		return true;67	}68 69	if (!vnode2 || !op->file[1].need_io_lock || vnode == vnode2)70		vnode2 = NULL;71 72	if (vnode2 > vnode)73		swap(vnode, vnode2);74 75	if (mutex_lock_interruptible(&vnode->io_lock) < 0) {76		afs_op_set_error(op, -ERESTARTSYS);77		op->flags |= AFS_OPERATION_STOP;78		_leave(" = f [I 0]");79		return false;80	}81	op->flags |= AFS_OPERATION_LOCK_0;82 83	if (vnode2) {84		if (mutex_lock_interruptible_nested(&vnode2->io_lock, 1) < 0) {85			afs_op_set_error(op, -ERESTARTSYS);86			op->flags |= AFS_OPERATION_STOP;87			mutex_unlock(&vnode->io_lock);88			op->flags &= ~AFS_OPERATION_LOCK_0;89			_leave(" = f [I 1]");90			return false;91		}92		op->flags |= AFS_OPERATION_LOCK_1;93	}94 95	_leave(" = t [2]");96	return true;97}98 99static void afs_drop_io_locks(struct afs_operation *op)100{101	struct afs_vnode *vnode = op->file[0].vnode;102	struct afs_vnode *vnode2 = op->file[1].vnode;103 104	_enter("");105 106	if (op->flags & AFS_OPERATION_LOCK_1)107		mutex_unlock(&vnode2->io_lock);108	if (op->flags & AFS_OPERATION_LOCK_0)109		mutex_unlock(&vnode->io_lock);110}111 112static void afs_prepare_vnode(struct afs_operation *op, struct afs_vnode_param *vp,113			      unsigned int index)114{115	struct afs_vnode *vnode = vp->vnode;116 117	if (vnode) {118		vp->fid			= vnode->fid;119		vp->dv_before		= vnode->status.data_version;120		vp->cb_break_before	= afs_calc_vnode_cb_break(vnode);121		if (vnode->lock_state != AFS_VNODE_LOCK_NONE)122			op->flags	|= AFS_OPERATION_CUR_ONLY;123		if (vp->modification)124			set_bit(AFS_VNODE_MODIFYING, &vnode->flags);125	}126 127	if (vp->fid.vnode)128		_debug("PREP[%u] {%llx:%llu.%u}",129		       index, vp->fid.vid, vp->fid.vnode, vp->fid.unique);130}131 132/*133 * Begin an operation on the fileserver.134 *135 * Fileserver operations are serialised on the server by vnode, so we serialise136 * them here also using the io_lock.137 */138bool afs_begin_vnode_operation(struct afs_operation *op)139{140	struct afs_vnode *vnode = op->file[0].vnode;141 142	ASSERT(vnode);143 144	_enter("");145 146	if (op->file[0].need_io_lock)147		if (!afs_get_io_locks(op))148			return false;149 150	afs_prepare_vnode(op, &op->file[0], 0);151	afs_prepare_vnode(op, &op->file[1], 1);152	op->cb_v_break = atomic_read(&op->volume->cb_v_break);153	_leave(" = true");154	return true;155}156 157/*158 * Tidy up a filesystem cursor and unlock the vnode.159 */160static void afs_end_vnode_operation(struct afs_operation *op)161{162	_enter("");163 164	switch (afs_op_error(op)) {165	case -EDESTADDRREQ:166	case -EADDRNOTAVAIL:167	case -ENETUNREACH:168	case -EHOSTUNREACH:169		afs_dump_edestaddrreq(op);170		break;171	}172 173	afs_drop_io_locks(op);174}175 176/*177 * Wait for an in-progress operation to complete.178 */179void afs_wait_for_operation(struct afs_operation *op)180{181	_enter("");182 183	while (afs_select_fileserver(op)) {184		op->call_responded = false;185		op->call_error = 0;186		op->call_abort_code = 0;187		if (test_bit(AFS_SERVER_FL_IS_YFS, &op->server->flags) &&188		    op->ops->issue_yfs_rpc)189			op->ops->issue_yfs_rpc(op);190		else if (op->ops->issue_afs_rpc)191			op->ops->issue_afs_rpc(op);192		else193			op->call_error = -ENOTSUPP;194 195		if (op->call) {196			afs_wait_for_call_to_complete(op->call);197			op->call_abort_code = op->call->abort_code;198			op->call_error = op->call->error;199			op->call_responded = op->call->responded;200			afs_put_call(op->call);201		}202	}203 204	if (op->call_responded && op->server)205		set_bit(AFS_SERVER_FL_RESPONDING, &op->server->flags);206 207	if (!afs_op_error(op)) {208		_debug("success");209		op->ops->success(op);210	} else if (op->cumul_error.aborted) {211		if (op->ops->aborted)212			op->ops->aborted(op);213	} else {214		if (op->ops->failed)215			op->ops->failed(op);216	}217 218	afs_end_vnode_operation(op);219 220	if (!afs_op_error(op) && op->ops->edit_dir) {221		_debug("edit_dir");222		op->ops->edit_dir(op);223	}224	_leave("");225}226 227/*228 * Dispose of an operation.229 */230int afs_put_operation(struct afs_operation *op)231{232	struct afs_addr_list *alist;233	int i, ret = afs_op_error(op);234 235	_enter("op=%08x,%d", op->debug_id, ret);236 237	if (op->ops && op->ops->put)238		op->ops->put(op);239	if (op->file[0].modification)240		clear_bit(AFS_VNODE_MODIFYING, &op->file[0].vnode->flags);241	if (op->file[1].modification && op->file[1].vnode != op->file[0].vnode)242		clear_bit(AFS_VNODE_MODIFYING, &op->file[1].vnode->flags);243	if (op->file[0].put_vnode)244		iput(&op->file[0].vnode->netfs.inode);245	if (op->file[1].put_vnode)246		iput(&op->file[1].vnode->netfs.inode);247 248	if (op->more_files) {249		for (i = 0; i < op->nr_files - 2; i++)250			if (op->more_files[i].put_vnode)251				iput(&op->more_files[i].vnode->netfs.inode);252		kfree(op->more_files);253	}254 255	if (op->estate) {256		alist = op->estate->addresses;257		if (alist) {258			if (op->call_responded &&259			    op->addr_index != alist->preferred &&260			    test_bit(alist->preferred, &op->addr_tried))261				WRITE_ONCE(alist->preferred, op->addr_index);262		}263	}264 265	afs_clear_server_states(op);266	afs_put_serverlist(op->net, op->server_list);267	afs_put_volume(op->volume, afs_volume_trace_put_put_op);268	key_put(op->key);269	kfree(op);270	return ret;271}272 273int afs_do_sync_operation(struct afs_operation *op)274{275	afs_begin_vnode_operation(op);276	afs_wait_for_operation(op);277	return afs_put_operation(op);278}279