Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Fileserver-directed operation handling.
0003  *
0004  * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/slab.h>
0010 #include <linux/fs.h>
0011 #include "internal.h"
0012 
0013 static atomic_t afs_operation_debug_counter;
0014 
0015 /*
0016  * Create an operation against a volume.
0017  */
0018 struct afs_operation *afs_alloc_operation(struct key *key, struct afs_volume *volume)
0019 {
0020     struct afs_operation *op;
0021 
0022     _enter("");
0023 
0024     op = kzalloc(sizeof(*op), GFP_KERNEL);
0025     if (!op)
0026         return ERR_PTR(-ENOMEM);
0027 
0028     if (!key) {
0029         key = afs_request_key(volume->cell);
0030         if (IS_ERR(key)) {
0031             kfree(op);
0032             return ERR_CAST(key);
0033         }
0034     } else {
0035         key_get(key);
0036     }
0037 
0038     op->key     = key;
0039     op->volume  = afs_get_volume(volume, afs_volume_trace_get_new_op);
0040     op->net     = volume->cell->net;
0041     op->cb_v_break  = volume->cb_v_break;
0042     op->debug_id    = atomic_inc_return(&afs_operation_debug_counter);
0043     op->error   = -EDESTADDRREQ;
0044     op->ac.error    = SHRT_MAX;
0045 
0046     _leave(" = [op=%08x]", op->debug_id);
0047     return op;
0048 }
0049 
0050 /*
0051  * Lock the vnode(s) being operated upon.
0052  */
0053 static bool afs_get_io_locks(struct afs_operation *op)
0054 {
0055     struct afs_vnode *vnode = op->file[0].vnode;
0056     struct afs_vnode *vnode2 = op->file[1].vnode;
0057 
0058     _enter("");
0059 
0060     if (op->flags & AFS_OPERATION_UNINTR) {
0061         mutex_lock(&vnode->io_lock);
0062         op->flags |= AFS_OPERATION_LOCK_0;
0063         _leave(" = t [1]");
0064         return true;
0065     }
0066 
0067     if (!vnode2 || !op->file[1].need_io_lock || vnode == vnode2)
0068         vnode2 = NULL;
0069 
0070     if (vnode2 > vnode)
0071         swap(vnode, vnode2);
0072 
0073     if (mutex_lock_interruptible(&vnode->io_lock) < 0) {
0074         op->error = -ERESTARTSYS;
0075         op->flags |= AFS_OPERATION_STOP;
0076         _leave(" = f [I 0]");
0077         return false;
0078     }
0079     op->flags |= AFS_OPERATION_LOCK_0;
0080 
0081     if (vnode2) {
0082         if (mutex_lock_interruptible_nested(&vnode2->io_lock, 1) < 0) {
0083             op->error = -ERESTARTSYS;
0084             op->flags |= AFS_OPERATION_STOP;
0085             mutex_unlock(&vnode->io_lock);
0086             op->flags &= ~AFS_OPERATION_LOCK_0;
0087             _leave(" = f [I 1]");
0088             return false;
0089         }
0090         op->flags |= AFS_OPERATION_LOCK_1;
0091     }
0092 
0093     _leave(" = t [2]");
0094     return true;
0095 }
0096 
0097 static void afs_drop_io_locks(struct afs_operation *op)
0098 {
0099     struct afs_vnode *vnode = op->file[0].vnode;
0100     struct afs_vnode *vnode2 = op->file[1].vnode;
0101 
0102     _enter("");
0103 
0104     if (op->flags & AFS_OPERATION_LOCK_1)
0105         mutex_unlock(&vnode2->io_lock);
0106     if (op->flags & AFS_OPERATION_LOCK_0)
0107         mutex_unlock(&vnode->io_lock);
0108 }
0109 
0110 static void afs_prepare_vnode(struct afs_operation *op, struct afs_vnode_param *vp,
0111                   unsigned int index)
0112 {
0113     struct afs_vnode *vnode = vp->vnode;
0114 
0115     if (vnode) {
0116         vp->fid         = vnode->fid;
0117         vp->dv_before       = vnode->status.data_version;
0118         vp->cb_break_before = afs_calc_vnode_cb_break(vnode);
0119         if (vnode->lock_state != AFS_VNODE_LOCK_NONE)
0120             op->flags   |= AFS_OPERATION_CUR_ONLY;
0121         if (vp->modification)
0122             set_bit(AFS_VNODE_MODIFYING, &vnode->flags);
0123     }
0124 
0125     if (vp->fid.vnode)
0126         _debug("PREP[%u] {%llx:%llu.%u}",
0127                index, vp->fid.vid, vp->fid.vnode, vp->fid.unique);
0128 }
0129 
0130 /*
0131  * Begin an operation on the fileserver.
0132  *
0133  * Fileserver operations are serialised on the server by vnode, so we serialise
0134  * them here also using the io_lock.
0135  */
0136 bool afs_begin_vnode_operation(struct afs_operation *op)
0137 {
0138     struct afs_vnode *vnode = op->file[0].vnode;
0139 
0140     ASSERT(vnode);
0141 
0142     _enter("");
0143 
0144     if (op->file[0].need_io_lock)
0145         if (!afs_get_io_locks(op))
0146             return false;
0147 
0148     afs_prepare_vnode(op, &op->file[0], 0);
0149     afs_prepare_vnode(op, &op->file[1], 1);
0150     op->cb_v_break = op->volume->cb_v_break;
0151     _leave(" = true");
0152     return true;
0153 }
0154 
0155 /*
0156  * Tidy up a filesystem cursor and unlock the vnode.
0157  */
0158 static void afs_end_vnode_operation(struct afs_operation *op)
0159 {
0160     _enter("");
0161 
0162     if (op->error == -EDESTADDRREQ ||
0163         op->error == -EADDRNOTAVAIL ||
0164         op->error == -ENETUNREACH ||
0165         op->error == -EHOSTUNREACH)
0166         afs_dump_edestaddrreq(op);
0167 
0168     afs_drop_io_locks(op);
0169 
0170     if (op->error == -ECONNABORTED)
0171         op->error = afs_abort_to_error(op->ac.abort_code);
0172 }
0173 
0174 /*
0175  * Wait for an in-progress operation to complete.
0176  */
0177 void afs_wait_for_operation(struct afs_operation *op)
0178 {
0179     _enter("");
0180 
0181     while (afs_select_fileserver(op)) {
0182         op->cb_s_break = op->server->cb_s_break;
0183         if (test_bit(AFS_SERVER_FL_IS_YFS, &op->server->flags) &&
0184             op->ops->issue_yfs_rpc)
0185             op->ops->issue_yfs_rpc(op);
0186         else if (op->ops->issue_afs_rpc)
0187             op->ops->issue_afs_rpc(op);
0188         else
0189             op->ac.error = -ENOTSUPP;
0190 
0191         if (op->call)
0192             op->error = afs_wait_for_call_to_complete(op->call, &op->ac);
0193     }
0194 
0195     switch (op->error) {
0196     case 0:
0197         _debug("success");
0198         op->ops->success(op);
0199         break;
0200     case -ECONNABORTED:
0201         if (op->ops->aborted)
0202             op->ops->aborted(op);
0203         fallthrough;
0204     default:
0205         if (op->ops->failed)
0206             op->ops->failed(op);
0207         break;
0208     }
0209 
0210     afs_end_vnode_operation(op);
0211 
0212     if (op->error == 0 && op->ops->edit_dir) {
0213         _debug("edit_dir");
0214         op->ops->edit_dir(op);
0215     }
0216     _leave("");
0217 }
0218 
0219 /*
0220  * Dispose of an operation.
0221  */
0222 int afs_put_operation(struct afs_operation *op)
0223 {
0224     int i, ret = op->error;
0225 
0226     _enter("op=%08x,%d", op->debug_id, ret);
0227 
0228     if (op->ops && op->ops->put)
0229         op->ops->put(op);
0230     if (op->file[0].modification)
0231         clear_bit(AFS_VNODE_MODIFYING, &op->file[0].vnode->flags);
0232     if (op->file[1].modification && op->file[1].vnode != op->file[0].vnode)
0233         clear_bit(AFS_VNODE_MODIFYING, &op->file[1].vnode->flags);
0234     if (op->file[0].put_vnode)
0235         iput(&op->file[0].vnode->netfs.inode);
0236     if (op->file[1].put_vnode)
0237         iput(&op->file[1].vnode->netfs.inode);
0238 
0239     if (op->more_files) {
0240         for (i = 0; i < op->nr_files - 2; i++)
0241             if (op->more_files[i].put_vnode)
0242                 iput(&op->more_files[i].vnode->netfs.inode);
0243         kfree(op->more_files);
0244     }
0245 
0246     afs_end_cursor(&op->ac);
0247     afs_put_serverlist(op->net, op->server_list);
0248     afs_put_volume(op->net, op->volume, afs_volume_trace_put_put_op);
0249     key_put(op->key);
0250     kfree(op);
0251     return ret;
0252 }
0253 
0254 int afs_do_sync_operation(struct afs_operation *op)
0255 {
0256     afs_begin_vnode_operation(op);
0257     afs_wait_for_operation(op);
0258     return afs_put_operation(op);
0259 }