Skip to content

Commit a3a8025

Browse files
committed
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()
2 parents 6d060fa + 34fa476 commit a3a8025

File tree

7 files changed

+61
-18
lines changed

7 files changed

+61
-18
lines changed

fs/afs/flock.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ void afs_lock_work(struct work_struct *work)
208208
/* The new front of the queue now owns the state variables. */
209209
next = list_entry(vnode->pending_locks.next,
210210
struct file_lock, fl_u.afs.link);
211-
vnode->lock_key = afs_file_key(next->fl_file);
211+
vnode->lock_key = key_get(afs_file_key(next->fl_file));
212212
vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
213213
vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB;
214214
goto again;
@@ -413,7 +413,7 @@ static void afs_dequeue_lock(struct afs_vnode *vnode, struct file_lock *fl)
413413
/* The new front of the queue now owns the state variables. */
414414
next = list_entry(vnode->pending_locks.next,
415415
struct file_lock, fl_u.afs.link);
416-
vnode->lock_key = afs_file_key(next->fl_file);
416+
vnode->lock_key = key_get(afs_file_key(next->fl_file));
417417
vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
418418
vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB;
419419
afs_lock_may_be_available(vnode);

fs/afs/inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
414414
} else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
415415
valid = true;
416416
} else {
417-
vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
418417
vnode->cb_v_break = vnode->volume->cb_v_break;
419418
valid = false;
420419
}
@@ -546,6 +545,8 @@ void afs_evict_inode(struct inode *inode)
546545
#endif
547546

548547
afs_put_permits(rcu_access_pointer(vnode->permit_cache));
548+
key_put(vnode->lock_key);
549+
vnode->lock_key = NULL;
549550
_leave("");
550551
}
551552

fs/afs/protocol_yfs.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,14 @@ struct yfs_xdr_YFSStoreVolumeStatus {
161161
struct yfs_xdr_u64 max_quota;
162162
struct yfs_xdr_u64 file_quota;
163163
} __packed;
164+
165+
enum yfs_lock_type {
166+
yfs_LockNone = -1,
167+
yfs_LockRead = 0,
168+
yfs_LockWrite = 1,
169+
yfs_LockExtend = 2,
170+
yfs_LockRelease = 3,
171+
yfs_LockMandatoryRead = 0x100,
172+
yfs_LockMandatoryWrite = 0x101,
173+
yfs_LockMandatoryExtend = 0x102,
174+
};

fs/afs/rxrpc.c

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct workqueue_struct *afs_async_calls;
2323
static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long);
2424
static long afs_wait_for_call_to_complete(struct afs_call *, struct afs_addr_cursor *);
2525
static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long);
26+
static void afs_delete_async_call(struct work_struct *);
2627
static void afs_process_async_call(struct work_struct *);
2728
static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long);
2829
static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long);
@@ -203,20 +204,26 @@ void afs_put_call(struct afs_call *call)
203204
}
204205
}
205206

207+
static struct afs_call *afs_get_call(struct afs_call *call,
208+
enum afs_call_trace why)
209+
{
210+
int u = atomic_inc_return(&call->usage);
211+
212+
trace_afs_call(call, why, u,
213+
atomic_read(&call->net->nr_outstanding_calls),
214+
__builtin_return_address(0));
215+
return call;
216+
}
217+
206218
/*
207219
* Queue the call for actual work.
208220
*/
209221
static void afs_queue_call_work(struct afs_call *call)
210222
{
211223
if (call->type->work) {
212-
int u = atomic_inc_return(&call->usage);
213-
214-
trace_afs_call(call, afs_call_trace_work, u,
215-
atomic_read(&call->net->nr_outstanding_calls),
216-
__builtin_return_address(0));
217-
218224
INIT_WORK(&call->work, call->type->work);
219225

226+
afs_get_call(call, afs_call_trace_work);
220227
if (!queue_work(afs_wq, &call->work))
221228
afs_put_call(call);
222229
}
@@ -398,6 +405,12 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
398405
}
399406
}
400407

408+
/* If the call is going to be asynchronous, we need an extra ref for
409+
* the call to hold itself so the caller need not hang on to its ref.
410+
*/
411+
if (call->async)
412+
afs_get_call(call, afs_call_trace_get);
413+
401414
/* create a call */
402415
rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key,
403416
(unsigned long)call,
@@ -438,15 +451,17 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
438451
goto error_do_abort;
439452
}
440453

441-
/* at this point, an async call may no longer exist as it may have
442-
* already completed */
443-
if (call->async)
454+
/* Note that at this point, we may have received the reply or an abort
455+
* - and an asynchronous call may already have completed.
456+
*/
457+
if (call->async) {
458+
afs_put_call(call);
444459
return -EINPROGRESS;
460+
}
445461

446462
return afs_wait_for_call_to_complete(call, ac);
447463

448464
error_do_abort:
449-
call->state = AFS_CALL_COMPLETE;
450465
if (ret != -ECONNABORTED) {
451466
rxrpc_kernel_abort_call(call->net->socket, rxcall,
452467
RX_USER_ABORT, ret, "KSD");
@@ -463,8 +478,24 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
463478
error_kill_call:
464479
if (call->type->done)
465480
call->type->done(call);
466-
afs_put_call(call);
481+
482+
/* We need to dispose of the extra ref we grabbed for an async call.
483+
* The call, however, might be queued on afs_async_calls and we need to
484+
* make sure we don't get any more notifications that might requeue it.
485+
*/
486+
if (call->rxcall) {
487+
rxrpc_kernel_end_call(call->net->socket, call->rxcall);
488+
call->rxcall = NULL;
489+
}
490+
if (call->async) {
491+
if (cancel_work_sync(&call->async_work))
492+
afs_put_call(call);
493+
afs_put_call(call);
494+
}
495+
467496
ac->error = ret;
497+
call->state = AFS_CALL_COMPLETE;
498+
afs_put_call(call);
468499
_leave(" = %d", ret);
469500
return ret;
470501
}

fs/afs/server_list.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
4242
if (vldb->fs_mask[i] & type_mask)
4343
nr_servers++;
4444

45-
slist = kzalloc(sizeof(struct afs_server_list) +
46-
sizeof(struct afs_server_entry) * nr_servers,
47-
GFP_KERNEL);
45+
slist = kzalloc(struct_size(slist, servers, nr_servers), GFP_KERNEL);
4846
if (!slist)
4947
goto error;
5048

fs/afs/yfsclient.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ int yfs_fs_create_file(struct afs_fs_cursor *fc,
803803
bp = xdr_encode_YFSFid(bp, &vnode->fid);
804804
bp = xdr_encode_string(bp, name, namesz);
805805
bp = xdr_encode_YFSStoreStatus_mode(bp, mode);
806-
bp = xdr_encode_u32(bp, 0); /* ViceLockType */
806+
bp = xdr_encode_u32(bp, yfs_LockNone); /* ViceLockType */
807807
yfs_check_req(call, bp);
808808

809809
afs_use_fs_server(call, fc->cbi);

include/trace/events/afs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
enum afs_call_trace {
2626
afs_call_trace_alloc,
2727
afs_call_trace_free,
28+
afs_call_trace_get,
2829
afs_call_trace_put,
2930
afs_call_trace_wake,
3031
afs_call_trace_work,
@@ -159,6 +160,7 @@ enum afs_file_error {
159160
#define afs_call_traces \
160161
EM(afs_call_trace_alloc, "ALLOC") \
161162
EM(afs_call_trace_free, "FREE ") \
163+
EM(afs_call_trace_get, "GET ") \
162164
EM(afs_call_trace_put, "PUT ") \
163165
EM(afs_call_trace_wake, "WAKE ") \
164166
E_(afs_call_trace_work, "WORK ")

0 commit comments

Comments
 (0)