diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-16 17:00:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-16 17:00:13 -0700 |
commit | 227747fb9eab37aaeb360aeba795362c01889427 (patch) | |
tree | 6bc179332007a270373703c5f04cbc19af242702 /net | |
parent | 1d9d7cbf28a1c2f84f2a0224466f8eb5f0a62ace (diff) | |
parent | fd711586bb7d63f257da5eff234e68c446ac35ea (diff) | |
download | lwn-227747fb9eab37aaeb360aeba795362c01889427.tar.gz lwn-227747fb9eab37aaeb360aeba795362c01889427.zip |
Merge tag 'afs-fixes-20190516' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull misc AFS fixes from David Howells:
"This fixes a set of miscellaneous issues in the afs filesystem,
including:
- leak of keys on file close.
- broken error handling in xattr functions.
- missing locking when updating VL server list.
- volume location server DNS lookup whereby preloaded cells may not
ever get a lookup and regular DNS lookups to maintain server lists
consume power unnecessarily.
- incorrect error propagation and handling in the fileserver
iteration code causes operations to sometimes apparently succeed.
- interruption of server record check/update side op during
fileserver iteration causes uninterruptible main operations to fail
unexpectedly.
- callback promise expiry time miscalculation.
- over invalidation of the callback promise on directories.
- double locking on callback break waking up file locking waiters.
- double increment of the vnode callback break counter.
Note that it makes some changes outside of the afs code, including:
- an extra parameter to dns_query() to allow the dns_resolver key
just accessed to be immediately invalidated. AFS is caching the
results itself, so the key can be discarded.
- an interruptible version of wait_var_event().
- an rxrpc function to allow the maximum lifespan to be set on a
call.
- a way for an rxrpc call to be marked as non-interruptible"
* tag 'afs-fixes-20190516' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
afs: Fix double inc of vnode->cb_break
afs: Fix lock-wait/callback-break double locking
afs: Don't invalidate callback if AFS_VNODE_DIR_VALID not set
afs: Fix calculation of callback expiry time
afs: Make dynamic root population wait uninterruptibly for proc_cells_lock
afs: Make some RPC operations non-interruptible
rxrpc: Allow the kernel to mark a call as being non-interruptible
afs: Fix error propagation from server record check/update
afs: Fix the maximum lifespan of VL and probe calls
rxrpc: Provide kernel interface to set max lifespan on a call
afs: Fix "kAFS: AFS vnode with undefined type 0"
afs: Fix cell DNS lookup
Add wait_var_event_interruptible()
dns_resolver: Allow used keys to be invalidated
afs: Fix afs_cell records to always have a VL server list record
afs: Fix missing lock when replacing VL server list
afs: Fix afs_xattr_get_yfs() to not try freeing an error value
afs: Fix incorrect error handling in afs_xattr_get_acl()
afs: Fix key leak in afs_release() and afs_evict_inode()
Diffstat (limited to 'net')
-rw-r--r-- | net/ceph/messenger.c | 2 | ||||
-rw-r--r-- | net/dns_resolver/dns_query.c | 6 | ||||
-rw-r--r-- | net/rxrpc/af_rxrpc.c | 28 | ||||
-rw-r--r-- | net/rxrpc/ar-internal.h | 2 | ||||
-rw-r--r-- | net/rxrpc/call_object.c | 2 | ||||
-rw-r--r-- | net/rxrpc/conn_client.c | 8 | ||||
-rw-r--r-- | net/rxrpc/sendmsg.c | 4 |
7 files changed, 47 insertions, 5 deletions
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 3ee380758ddd..cd0b094468b6 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1887,7 +1887,7 @@ static int ceph_dns_resolve_name(const char *name, size_t namelen, return -EINVAL; /* do dns_resolve upcall */ - ip_len = dns_query(NULL, name, end - name, NULL, &ip_addr, NULL); + ip_len = dns_query(NULL, name, end - name, NULL, &ip_addr, NULL, false); if (ip_len > 0) ret = ceph_pton(ip_addr, ip_len, addr, -1, NULL); else diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index 19aa32fc1802..2d260432b3be 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c @@ -54,6 +54,7 @@ * @options: Request options (or NULL if no options) * @_result: Where to place the returned data (or NULL) * @_expiry: Where to store the result expiry time (or NULL) + * @invalidate: Always invalidate the key after use * * The data will be returned in the pointer at *result, if provided, and the * caller is responsible for freeing it. @@ -69,7 +70,8 @@ * Returns the size of the result on success, -ve error code otherwise. */ int dns_query(const char *type, const char *name, size_t namelen, - const char *options, char **_result, time64_t *_expiry) + const char *options, char **_result, time64_t *_expiry, + bool invalidate) { struct key *rkey; struct user_key_payload *upayload; @@ -157,6 +159,8 @@ int dns_query(const char *type, const char *name, size_t namelen, ret = len; put: up_read(&rkey->sem); + if (invalidate) + key_invalidate(rkey); key_put(rkey); out: kleave(" = %d", ret); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index ae8c5d7f3bf1..ffde5b187f5d 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -270,6 +270,7 @@ static int rxrpc_listen(struct socket *sock, int backlog) * @gfp: The allocation constraints * @notify_rx: Where to send notifications instead of socket queue * @upgrade: Request service upgrade for call + * @intr: The call is interruptible * @debug_id: The debug ID for tracing to be assigned to the call * * Allow a kernel service to begin a call on the nominated socket. This just @@ -287,6 +288,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, gfp_t gfp, rxrpc_notify_rx_t notify_rx, bool upgrade, + bool intr, unsigned int debug_id) { struct rxrpc_conn_parameters cp; @@ -311,6 +313,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, memset(&p, 0, sizeof(p)); p.user_call_ID = user_call_ID; p.tx_total_len = tx_total_len; + p.intr = intr; memset(&cp, 0, sizeof(cp)); cp.local = rx->local; @@ -443,6 +446,31 @@ void rxrpc_kernel_new_call_notification( } EXPORT_SYMBOL(rxrpc_kernel_new_call_notification); +/** + * rxrpc_kernel_set_max_life - Set maximum lifespan on a call + * @sock: The socket the call is on + * @call: The call to configure + * @hard_timeout: The maximum lifespan of the call in jiffies + * + * Set the maximum lifespan of a call. The call will end with ETIME or + * ETIMEDOUT if it takes longer than this. + */ +void rxrpc_kernel_set_max_life(struct socket *sock, struct rxrpc_call *call, + unsigned long hard_timeout) +{ + unsigned long now; + + mutex_lock(&call->user_mutex); + + now = jiffies; + hard_timeout += now; + WRITE_ONCE(call->expect_term_by, hard_timeout); + rxrpc_reduce_call_timer(call, hard_timeout, now, rxrpc_timer_set_for_hard); + + mutex_unlock(&call->user_mutex); +} +EXPORT_SYMBOL(rxrpc_kernel_set_max_life); + /* * connect an RxRPC socket * - this just targets it at a specific destination; no actual connection diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 062ca9dc29b8..07fc1dfa4878 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -482,6 +482,7 @@ enum rxrpc_call_flag { RXRPC_CALL_BEGAN_RX_TIMER, /* We began the expect_rx_by timer */ RXRPC_CALL_RX_HEARD, /* The peer responded at least once to this call */ RXRPC_CALL_RX_UNDERRUN, /* Got data underrun */ + RXRPC_CALL_IS_INTR, /* The call is interruptible */ }; /* @@ -711,6 +712,7 @@ struct rxrpc_call_params { u32 normal; /* Max time since last call packet (msec) */ } timeouts; u8 nr_timeouts; /* Number of timeouts specified */ + bool intr; /* The call is interruptible */ }; struct rxrpc_send_params { diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index fe96881a334d..d0ca98d7aef5 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -241,6 +241,8 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, return call; } + if (p->intr) + __set_bit(RXRPC_CALL_IS_INTR, &call->flags); call->tx_total_len = p->tx_total_len; trace_rxrpc_call(call, rxrpc_call_new_client, atomic_read(&call->usage), here, (const void *)p->user_call_ID); diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 83797b3949e2..5cf5595a14d8 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -656,10 +656,14 @@ static int rxrpc_wait_for_channel(struct rxrpc_call *call, gfp_t gfp) add_wait_queue_exclusive(&call->waitq, &myself); for (;;) { - set_current_state(TASK_INTERRUPTIBLE); + if (test_bit(RXRPC_CALL_IS_INTR, &call->flags)) + set_current_state(TASK_INTERRUPTIBLE); + else + set_current_state(TASK_UNINTERRUPTIBLE); if (call->call_id) break; - if (signal_pending(current)) { + if (test_bit(RXRPC_CALL_IS_INTR, &call->flags) && + signal_pending(current)) { ret = -ERESTARTSYS; break; } diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index bec64deb7b0a..45a05d9a27fa 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -80,7 +80,8 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx, if (call->state >= RXRPC_CALL_COMPLETE) return call->error; - if (timeout == 0 && + if (test_bit(RXRPC_CALL_IS_INTR, &call->flags) && + timeout == 0 && tx_win == tx_start && signal_pending(current)) return -EINTR; @@ -620,6 +621,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) .call.tx_total_len = -1, .call.user_call_ID = 0, .call.nr_timeouts = 0, + .call.intr = true, .abort_code = 0, .command = RXRPC_CMD_SEND_DATA, .exclusive = false, |