1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Fileserver-directed operation handling.
4 * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
8 #include <linux/kernel.h>
9 #include <linux/slab.h>
13 static atomic_t afs_operation_debug_counter
;
16 * Create an operation against a volume.
18 struct afs_operation
*afs_alloc_operation(struct key
*key
, struct afs_volume
*volume
)
20 struct afs_operation
*op
;
24 op
= kzalloc(sizeof(*op
), GFP_KERNEL
);
26 return ERR_PTR(-ENOMEM
);
29 key
= afs_request_key(volume
->cell
);
39 op
->volume
= afs_get_volume(volume
, afs_volume_trace_get_new_op
);
40 op
->net
= volume
->cell
->net
;
41 op
->cb_v_break
= volume
->cb_v_break
;
42 op
->debug_id
= atomic_inc_return(&afs_operation_debug_counter
);
43 op
->error
= -EDESTADDRREQ
;
44 op
->ac
.error
= SHRT_MAX
;
46 _leave(" = [op=%08x]", op
->debug_id
);
51 * Lock the vnode(s) being operated upon.
53 static bool afs_get_io_locks(struct afs_operation
*op
)
55 struct afs_vnode
*vnode
= op
->file
[0].vnode
;
56 struct afs_vnode
*vnode2
= op
->file
[1].vnode
;
60 if (op
->flags
& AFS_OPERATION_UNINTR
) {
61 mutex_lock(&vnode
->io_lock
);
62 op
->flags
|= AFS_OPERATION_LOCK_0
;
67 if (!vnode2
|| !op
->file
[1].need_io_lock
|| vnode
== vnode2
)
73 if (mutex_lock_interruptible(&vnode
->io_lock
) < 0) {
74 op
->error
= -ERESTARTSYS
;
75 op
->flags
|= AFS_OPERATION_STOP
;
79 op
->flags
|= AFS_OPERATION_LOCK_0
;
82 if (mutex_lock_interruptible_nested(&vnode2
->io_lock
, 1) < 0) {
83 op
->error
= -ERESTARTSYS
;
84 op
->flags
|= AFS_OPERATION_STOP
;
85 mutex_unlock(&vnode
->io_lock
);
86 op
->flags
&= ~AFS_OPERATION_LOCK_0
;
90 op
->flags
|= AFS_OPERATION_LOCK_1
;
97 static void afs_drop_io_locks(struct afs_operation
*op
)
99 struct afs_vnode
*vnode
= op
->file
[0].vnode
;
100 struct afs_vnode
*vnode2
= op
->file
[1].vnode
;
104 if (op
->flags
& AFS_OPERATION_LOCK_1
)
105 mutex_unlock(&vnode2
->io_lock
);
106 if (op
->flags
& AFS_OPERATION_LOCK_0
)
107 mutex_unlock(&vnode
->io_lock
);
110 static void afs_prepare_vnode(struct afs_operation
*op
, struct afs_vnode_param
*vp
,
113 struct afs_vnode
*vnode
= vp
->vnode
;
116 vp
->fid
= vnode
->fid
;
117 vp
->dv_before
= vnode
->status
.data_version
;
118 vp
->cb_break_before
= afs_calc_vnode_cb_break(vnode
);
119 if (vnode
->lock_state
!= AFS_VNODE_LOCK_NONE
)
120 op
->flags
|= AFS_OPERATION_CUR_ONLY
;
124 _debug("PREP[%u] {%llx:%llu.%u}",
125 index
, vp
->fid
.vid
, vp
->fid
.vnode
, vp
->fid
.unique
);
129 * Begin an operation on the fileserver.
131 * Fileserver operations are serialised on the server by vnode, so we serialise
132 * them here also using the io_lock.
134 bool afs_begin_vnode_operation(struct afs_operation
*op
)
136 struct afs_vnode
*vnode
= op
->file
[0].vnode
;
142 if (op
->file
[0].need_io_lock
)
143 if (!afs_get_io_locks(op
))
146 afs_prepare_vnode(op
, &op
->file
[0], 0);
147 afs_prepare_vnode(op
, &op
->file
[1], 1);
148 op
->cb_v_break
= op
->volume
->cb_v_break
;
154 * Tidy up a filesystem cursor and unlock the vnode.
156 static void afs_end_vnode_operation(struct afs_operation
*op
)
160 if (op
->error
== -EDESTADDRREQ
||
161 op
->error
== -EADDRNOTAVAIL
||
162 op
->error
== -ENETUNREACH
||
163 op
->error
== -EHOSTUNREACH
)
164 afs_dump_edestaddrreq(op
);
166 afs_drop_io_locks(op
);
168 if (op
->error
== -ECONNABORTED
)
169 op
->error
= afs_abort_to_error(op
->ac
.abort_code
);
173 * Wait for an in-progress operation to complete.
175 void afs_wait_for_operation(struct afs_operation
*op
)
179 while (afs_select_fileserver(op
)) {
180 op
->cb_s_break
= op
->server
->cb_s_break
;
181 if (test_bit(AFS_SERVER_FL_IS_YFS
, &op
->server
->flags
) &&
182 op
->ops
->issue_yfs_rpc
)
183 op
->ops
->issue_yfs_rpc(op
);
185 op
->ops
->issue_afs_rpc(op
);
187 op
->error
= afs_wait_for_call_to_complete(op
->call
, &op
->ac
);
193 op
->ops
->success(op
);
196 if (op
->ops
->aborted
)
197 op
->ops
->aborted(op
);
203 afs_end_vnode_operation(op
);
205 if (op
->error
== 0 && op
->ops
->edit_dir
) {
207 op
->ops
->edit_dir(op
);
213 * Dispose of an operation.
215 int afs_put_operation(struct afs_operation
*op
)
217 int i
, ret
= op
->error
;
219 _enter("op=%08x,%d", op
->debug_id
, ret
);
221 if (op
->ops
&& op
->ops
->put
)
223 if (op
->file
[0].put_vnode
)
224 iput(&op
->file
[0].vnode
->vfs_inode
);
225 if (op
->file
[1].put_vnode
)
226 iput(&op
->file
[1].vnode
->vfs_inode
);
228 if (op
->more_files
) {
229 for (i
= 0; i
< op
->nr_files
- 2; i
++)
230 if (op
->more_files
[i
].put_vnode
)
231 iput(&op
->more_files
[i
].vnode
->vfs_inode
);
232 kfree(op
->more_files
);
235 afs_end_cursor(&op
->ac
);
236 afs_put_serverlist(op
->net
, op
->server_list
);
237 afs_put_volume(op
->net
, op
->volume
, afs_volume_trace_put_put_op
);
243 int afs_do_sync_operation(struct afs_operation
*op
)
245 afs_begin_vnode_operation(op
);
246 afs_wait_for_operation(op
);
247 return afs_put_operation(op
);