mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
AFS fixes
-----BEGIN PGP SIGNATURE----- iQIVAwUAXECcyPu3V2unywtrAQIpGw//ctcGHg2sfUEra17pvlKEbpZe9bMeJxp6 UY2YR5gPpiYMmvNe8hLl3I68b43h03jGOx+KmqowqX7anNq3o2nMy0pDbuGmKtuS 5NmIOECAml8k2uPSpacAF2s6TsxB2lTDYwZdyeuRmZ4scOTujNby33RlijGIxX4s 87WJFRuCacm9I1KkiKKn4PWoYGjDdsZ7rsDyEeBmQ/MiKOSLG4QP5XuNr4X9zFMX r8uF3N8h/NzJWefEirc2DPFfiWLJqkyclq9tgsTB1Z3l+x5u/MHnIg3rZpZhH0uC GhGWjlGYqTxOwzYCaOOsNIDRF4rAGPi3lzuJXjONnhvbOO7DCGJ+Mo2obxkAqLL6 PrtFuQvgXIOl/k8y6AdckuPPu/OMHT1hyY0PQXmTGhHAAfPP3RHoPl7owEjmAbRg hvRkFDSIKZ4Kr1nKP4vwaJYEKtxUQrkOwZKmN6ve31ZeJsyrH12MsCgWvp7oQwRJ fVbk8DWVRtYzy4RaO3Xr+0WfD+03dDi6KKCPPiC2gtNKOO+1Kco/EtIqPi6SXg0m ee/mFOkRsmEh++iNxS58qLxH37On6GSYOElSIMN0NJDNA2TzLrvidXlMSOTD1hj4 n6gL38E3br/CIimKPYm87qi6yC59CAtrJCulYiPOoMc20eaEUP4DIXN8yjgjLNQp Hj5M9GRTwXk= =cUrU -----END PGP SIGNATURE----- Merge tag 'afs-fixes-20190117' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs Pull AFS fixes from David Howells: "Here's a set of fixes for AFS: - Use struct_size() for kzalloc() size calculation. - When calling YFS.CreateFile rather than AFS.CreateFile, it is possible to create a file with a file lock already held. The default value indicating no lock required is actually -1, not 0. - Fix an oops in inode/vnode validation if the target inode doesn't have a server interest assigned (ie. a server that will notify us of changes by third parties). - Fix refcounting of keys in file locking. - Fix a race in refcounting asynchronous operations in the event of an error during request transmission. The provision of a dedicated function to get an extra ref on a call is split into a separate commit" * tag 'afs-fixes-20190117' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs: afs: Fix race in async call refcounting afs: Provide a function to get a ref on a call afs: Fix key refcounting in file locking code afs: Don't set vnode->cb_s_break in afs_validate() afs: Set correct lock type for the yfs CreateFile afs: Use struct_size() in kzalloc()
This commit is contained in:
commit
a3a80255d5
@ -208,7 +208,7 @@ again:
|
||||
/* The new front of the queue now owns the state variables. */
|
||||
next = list_entry(vnode->pending_locks.next,
|
||||
struct file_lock, fl_u.afs.link);
|
||||
vnode->lock_key = afs_file_key(next->fl_file);
|
||||
vnode->lock_key = key_get(afs_file_key(next->fl_file));
|
||||
vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
|
||||
vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB;
|
||||
goto again;
|
||||
@ -413,7 +413,7 @@ static void afs_dequeue_lock(struct afs_vnode *vnode, struct file_lock *fl)
|
||||
/* The new front of the queue now owns the state variables. */
|
||||
next = list_entry(vnode->pending_locks.next,
|
||||
struct file_lock, fl_u.afs.link);
|
||||
vnode->lock_key = afs_file_key(next->fl_file);
|
||||
vnode->lock_key = key_get(afs_file_key(next->fl_file));
|
||||
vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
|
||||
vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB;
|
||||
afs_lock_may_be_available(vnode);
|
||||
|
@ -414,7 +414,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
|
||||
} else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
|
||||
valid = true;
|
||||
} else {
|
||||
vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
|
||||
vnode->cb_v_break = vnode->volume->cb_v_break;
|
||||
valid = false;
|
||||
}
|
||||
@ -546,6 +545,8 @@ void afs_evict_inode(struct inode *inode)
|
||||
#endif
|
||||
|
||||
afs_put_permits(rcu_access_pointer(vnode->permit_cache));
|
||||
key_put(vnode->lock_key);
|
||||
vnode->lock_key = NULL;
|
||||
_leave("");
|
||||
}
|
||||
|
||||
|
@ -161,3 +161,14 @@ struct yfs_xdr_YFSStoreVolumeStatus {
|
||||
struct yfs_xdr_u64 max_quota;
|
||||
struct yfs_xdr_u64 file_quota;
|
||||
} __packed;
|
||||
|
||||
enum yfs_lock_type {
|
||||
yfs_LockNone = -1,
|
||||
yfs_LockRead = 0,
|
||||
yfs_LockWrite = 1,
|
||||
yfs_LockExtend = 2,
|
||||
yfs_LockRelease = 3,
|
||||
yfs_LockMandatoryRead = 0x100,
|
||||
yfs_LockMandatoryWrite = 0x101,
|
||||
yfs_LockMandatoryExtend = 0x102,
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ struct workqueue_struct *afs_async_calls;
|
||||
static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long);
|
||||
static long afs_wait_for_call_to_complete(struct afs_call *, struct afs_addr_cursor *);
|
||||
static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long);
|
||||
static void afs_delete_async_call(struct work_struct *);
|
||||
static void afs_process_async_call(struct work_struct *);
|
||||
static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long);
|
||||
static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long);
|
||||
@ -203,20 +204,26 @@ void afs_put_call(struct afs_call *call)
|
||||
}
|
||||
}
|
||||
|
||||
static struct afs_call *afs_get_call(struct afs_call *call,
|
||||
enum afs_call_trace why)
|
||||
{
|
||||
int u = atomic_inc_return(&call->usage);
|
||||
|
||||
trace_afs_call(call, why, u,
|
||||
atomic_read(&call->net->nr_outstanding_calls),
|
||||
__builtin_return_address(0));
|
||||
return call;
|
||||
}
|
||||
|
||||
/*
|
||||
* Queue the call for actual work.
|
||||
*/
|
||||
static void afs_queue_call_work(struct afs_call *call)
|
||||
{
|
||||
if (call->type->work) {
|
||||
int u = atomic_inc_return(&call->usage);
|
||||
|
||||
trace_afs_call(call, afs_call_trace_work, u,
|
||||
atomic_read(&call->net->nr_outstanding_calls),
|
||||
__builtin_return_address(0));
|
||||
|
||||
INIT_WORK(&call->work, call->type->work);
|
||||
|
||||
afs_get_call(call, afs_call_trace_work);
|
||||
if (!queue_work(afs_wq, &call->work))
|
||||
afs_put_call(call);
|
||||
}
|
||||
@ -398,6 +405,12 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
|
||||
}
|
||||
}
|
||||
|
||||
/* If the call is going to be asynchronous, we need an extra ref for
|
||||
* the call to hold itself so the caller need not hang on to its ref.
|
||||
*/
|
||||
if (call->async)
|
||||
afs_get_call(call, afs_call_trace_get);
|
||||
|
||||
/* create a call */
|
||||
rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key,
|
||||
(unsigned long)call,
|
||||
@ -438,15 +451,17 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
|
||||
goto error_do_abort;
|
||||
}
|
||||
|
||||
/* at this point, an async call may no longer exist as it may have
|
||||
* already completed */
|
||||
if (call->async)
|
||||
/* Note that at this point, we may have received the reply or an abort
|
||||
* - and an asynchronous call may already have completed.
|
||||
*/
|
||||
if (call->async) {
|
||||
afs_put_call(call);
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
return afs_wait_for_call_to_complete(call, ac);
|
||||
|
||||
error_do_abort:
|
||||
call->state = AFS_CALL_COMPLETE;
|
||||
if (ret != -ECONNABORTED) {
|
||||
rxrpc_kernel_abort_call(call->net->socket, rxcall,
|
||||
RX_USER_ABORT, ret, "KSD");
|
||||
@ -463,8 +478,24 @@ error_do_abort:
|
||||
error_kill_call:
|
||||
if (call->type->done)
|
||||
call->type->done(call);
|
||||
afs_put_call(call);
|
||||
|
||||
/* We need to dispose of the extra ref we grabbed for an async call.
|
||||
* The call, however, might be queued on afs_async_calls and we need to
|
||||
* make sure we don't get any more notifications that might requeue it.
|
||||
*/
|
||||
if (call->rxcall) {
|
||||
rxrpc_kernel_end_call(call->net->socket, call->rxcall);
|
||||
call->rxcall = NULL;
|
||||
}
|
||||
if (call->async) {
|
||||
if (cancel_work_sync(&call->async_work))
|
||||
afs_put_call(call);
|
||||
afs_put_call(call);
|
||||
}
|
||||
|
||||
ac->error = ret;
|
||||
call->state = AFS_CALL_COMPLETE;
|
||||
afs_put_call(call);
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -42,9 +42,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
|
||||
if (vldb->fs_mask[i] & type_mask)
|
||||
nr_servers++;
|
||||
|
||||
slist = kzalloc(sizeof(struct afs_server_list) +
|
||||
sizeof(struct afs_server_entry) * nr_servers,
|
||||
GFP_KERNEL);
|
||||
slist = kzalloc(struct_size(slist, servers, nr_servers), GFP_KERNEL);
|
||||
if (!slist)
|
||||
goto error;
|
||||
|
||||
|
@ -803,7 +803,7 @@ int yfs_fs_create_file(struct afs_fs_cursor *fc,
|
||||
bp = xdr_encode_YFSFid(bp, &vnode->fid);
|
||||
bp = xdr_encode_string(bp, name, namesz);
|
||||
bp = xdr_encode_YFSStoreStatus_mode(bp, mode);
|
||||
bp = xdr_encode_u32(bp, 0); /* ViceLockType */
|
||||
bp = xdr_encode_u32(bp, yfs_LockNone); /* ViceLockType */
|
||||
yfs_check_req(call, bp);
|
||||
|
||||
afs_use_fs_server(call, fc->cbi);
|
||||
|
@ -25,6 +25,7 @@
|
||||
enum afs_call_trace {
|
||||
afs_call_trace_alloc,
|
||||
afs_call_trace_free,
|
||||
afs_call_trace_get,
|
||||
afs_call_trace_put,
|
||||
afs_call_trace_wake,
|
||||
afs_call_trace_work,
|
||||
@ -159,6 +160,7 @@ enum afs_file_error {
|
||||
#define afs_call_traces \
|
||||
EM(afs_call_trace_alloc, "ALLOC") \
|
||||
EM(afs_call_trace_free, "FREE ") \
|
||||
EM(afs_call_trace_get, "GET ") \
|
||||
EM(afs_call_trace_put, "PUT ") \
|
||||
EM(afs_call_trace_wake, "WAKE ") \
|
||||
E_(afs_call_trace_work, "WORK ")
|
||||
|
Loading…
Reference in New Issue
Block a user