Commit 227747fb authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 1d9d7cbf fd711586
...@@ -796,7 +796,9 @@ The kernel interface functions are as follows: ...@@ -796,7 +796,9 @@ The kernel interface functions are as follows:
s64 tx_total_len, s64 tx_total_len,
gfp_t gfp, gfp_t gfp,
rxrpc_notify_rx_t notify_rx, rxrpc_notify_rx_t notify_rx,
bool upgrade); bool upgrade,
bool intr,
unsigned int debug_id);
This allocates the infrastructure to make a new RxRPC call and assigns This allocates the infrastructure to make a new RxRPC call and assigns
call and connection numbers. The call will be made on the UDP port that call and connection numbers. The call will be made on the UDP port that
...@@ -824,6 +826,13 @@ The kernel interface functions are as follows: ...@@ -824,6 +826,13 @@ The kernel interface functions are as follows:
the server upgrade the service to a better one. The resultant service ID the server upgrade the service to a better one. The resultant service ID
is returned by rxrpc_kernel_recv_data(). is returned by rxrpc_kernel_recv_data().
intr should be set to true if the call should be interruptible. If this
is not set, this function may not return until a channel has been
allocated; if it is set, the function may return -ERESTARTSYS.
debug_id is the call debugging ID to be used for tracing. This can be
obtained by atomically incrementing rxrpc_debug_id.
If this function is successful, an opaque reference to the RxRPC call is If this function is successful, an opaque reference to the RxRPC call is
returned. The caller now holds a reference on this and it must be returned. The caller now holds a reference on this and it must be
properly ended. properly ended.
...@@ -1056,6 +1065,16 @@ The kernel interface functions are as follows: ...@@ -1056,6 +1065,16 @@ The kernel interface functions are as follows:
This value can be used to determine if the remote client has been This value can be used to determine if the remote client has been
restarted as it shouldn't change otherwise. restarted as it shouldn't change otherwise.
(*) Set the maxmimum lifespan on a call.
void rxrpc_kernel_set_max_life(struct socket *sock,
struct rxrpc_call *call,
unsigned long hard_timeout)
This sets the maximum lifespan on a call to hard_timeout (which is in
jiffies). In the event of the timeout occurring, the call will be
aborted and -ETIME or -ETIMEDOUT will be returned.
======================= =======================
CONFIGURABLE PARAMETERS CONFIGURABLE PARAMETERS
......
...@@ -251,7 +251,7 @@ struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry ...@@ -251,7 +251,7 @@ struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry
_enter("%s", cell->name); _enter("%s", cell->name);
ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1", ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1",
&result, _expiry); &result, _expiry, true);
if (ret < 0) { if (ret < 0) {
_leave(" = %d [dns]", ret); _leave(" = %d [dns]", ret);
return ERR_PTR(ret); return ERR_PTR(ret);
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#define AFSPATHMAX 1024 /* Maximum length of a pathname plus NUL */ #define AFSPATHMAX 1024 /* Maximum length of a pathname plus NUL */
#define AFSOPAQUEMAX 1024 /* Maximum length of an opaque field */ #define AFSOPAQUEMAX 1024 /* Maximum length of an opaque field */
#define AFS_VL_MAX_LIFESPAN (120 * HZ)
#define AFS_PROBE_MAX_LIFESPAN (30 * HZ)
typedef u64 afs_volid_t; typedef u64 afs_volid_t;
typedef u64 afs_vnodeid_t; typedef u64 afs_vnodeid_t;
typedef u64 afs_dataversion_t; typedef u64 afs_dataversion_t;
......
...@@ -218,14 +218,8 @@ void __afs_break_callback(struct afs_vnode *vnode) ...@@ -218,14 +218,8 @@ void __afs_break_callback(struct afs_vnode *vnode)
vnode->cb_break++; vnode->cb_break++;
afs_clear_permits(vnode); afs_clear_permits(vnode);
spin_lock(&vnode->lock); if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB)
_debug("break callback");
if (list_empty(&vnode->granted_locks) &&
!list_empty(&vnode->pending_locks))
afs_lock_may_be_available(vnode); afs_lock_may_be_available(vnode);
spin_unlock(&vnode->lock);
} }
} }
......
...@@ -123,6 +123,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, ...@@ -123,6 +123,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
const char *name, unsigned int namelen, const char *name, unsigned int namelen,
const char *addresses) const char *addresses)
{ {
struct afs_vlserver_list *vllist;
struct afs_cell *cell; struct afs_cell *cell;
int i, ret; int i, ret;
...@@ -151,18 +152,14 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, ...@@ -151,18 +152,14 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
atomic_set(&cell->usage, 2); atomic_set(&cell->usage, 2);
INIT_WORK(&cell->manager, afs_manage_cell); INIT_WORK(&cell->manager, afs_manage_cell);
cell->flags = ((1 << AFS_CELL_FL_NOT_READY) |
(1 << AFS_CELL_FL_NO_LOOKUP_YET));
INIT_LIST_HEAD(&cell->proc_volumes); INIT_LIST_HEAD(&cell->proc_volumes);
rwlock_init(&cell->proc_lock); rwlock_init(&cell->proc_lock);
rwlock_init(&cell->vl_servers_lock); rwlock_init(&cell->vl_servers_lock);
/* Fill in the VL server list if we were given a list of addresses to /* Provide a VL server list, filling it in if we were given a list of
* use. * addresses to use.
*/ */
if (addresses) { if (addresses) {
struct afs_vlserver_list *vllist;
vllist = afs_parse_text_addrs(net, vllist = afs_parse_text_addrs(net,
addresses, strlen(addresses), ':', addresses, strlen(addresses), ':',
VL_SERVICE, AFS_VL_PORT); VL_SERVICE, AFS_VL_PORT);
...@@ -171,19 +168,32 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, ...@@ -171,19 +168,32 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
goto parse_failed; goto parse_failed;
} }
rcu_assign_pointer(cell->vl_servers, vllist); vllist->source = DNS_RECORD_FROM_CONFIG;
vllist->status = DNS_LOOKUP_NOT_DONE;
cell->dns_expiry = TIME64_MAX; cell->dns_expiry = TIME64_MAX;
__clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags);
} else { } else {
ret = -ENOMEM;
vllist = afs_alloc_vlserver_list(0);
if (!vllist)
goto error;
vllist->source = DNS_RECORD_UNAVAILABLE;
vllist->status = DNS_LOOKUP_NOT_DONE;
cell->dns_expiry = ktime_get_real_seconds(); cell->dns_expiry = ktime_get_real_seconds();
} }
rcu_assign_pointer(cell->vl_servers, vllist);
cell->dns_source = vllist->source;
cell->dns_status = vllist->status;
smp_store_release(&cell->dns_lookup_count, 1); /* vs source/status */
_leave(" = %p", cell); _leave(" = %p", cell);
return cell; return cell;
parse_failed: parse_failed:
if (ret == -EINVAL) if (ret == -EINVAL)
printk(KERN_ERR "kAFS: bad VL server IP address\n"); printk(KERN_ERR "kAFS: bad VL server IP address\n");
error:
kfree(cell); kfree(cell);
_leave(" = %d", ret); _leave(" = %d", ret);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -208,6 +218,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, ...@@ -208,6 +218,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
{ {
struct afs_cell *cell, *candidate, *cursor; struct afs_cell *cell, *candidate, *cursor;
struct rb_node *parent, **pp; struct rb_node *parent, **pp;
enum afs_cell_state state;
int ret, n; int ret, n;
_enter("%s,%s", name, vllist); _enter("%s,%s", name, vllist);
...@@ -267,18 +278,16 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, ...@@ -267,18 +278,16 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
wait_for_cell: wait_for_cell:
_debug("wait_for_cell"); _debug("wait_for_cell");
ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NOT_READY, TASK_INTERRUPTIBLE); wait_var_event(&cell->state,
smp_rmb(); ({
state = smp_load_acquire(&cell->state); /* vs error */
switch (READ_ONCE(cell->state)) { state == AFS_CELL_ACTIVE || state == AFS_CELL_FAILED;
case AFS_CELL_FAILED: }));
/* Check the state obtained from the wait check. */
if (state == AFS_CELL_FAILED) {
ret = cell->error; ret = cell->error;
goto error; goto error;
default:
_debug("weird %u %d", cell->state, cell->error);
goto error;
case AFS_CELL_ACTIVE:
break;
} }
_leave(" = %p [cell]", cell); _leave(" = %p [cell]", cell);
...@@ -360,16 +369,46 @@ int afs_cell_init(struct afs_net *net, const char *rootcell) ...@@ -360,16 +369,46 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
/* /*
* Update a cell's VL server address list from the DNS. * Update a cell's VL server address list from the DNS.
*/ */
static void afs_update_cell(struct afs_cell *cell) static int afs_update_cell(struct afs_cell *cell)
{ {
struct afs_vlserver_list *vllist, *old; struct afs_vlserver_list *vllist, *old = NULL, *p;
unsigned int min_ttl = READ_ONCE(afs_cell_min_ttl); unsigned int min_ttl = READ_ONCE(afs_cell_min_ttl);
unsigned int max_ttl = READ_ONCE(afs_cell_max_ttl); unsigned int max_ttl = READ_ONCE(afs_cell_max_ttl);
time64_t now, expiry = 0; time64_t now, expiry = 0;
int ret = 0;
_enter("%s", cell->name); _enter("%s", cell->name);
vllist = afs_dns_query(cell, &expiry); vllist = afs_dns_query(cell, &expiry);
if (IS_ERR(vllist)) {
ret = PTR_ERR(vllist);
_debug("%s: fail %d", cell->name, ret);
if (ret == -ENOMEM)
goto out_wake;
ret = -ENOMEM;
vllist = afs_alloc_vlserver_list(0);
if (!vllist)
goto out_wake;
switch (ret) {
case -ENODATA:
case -EDESTADDRREQ:
vllist->status = DNS_LOOKUP_GOT_NOT_FOUND;
break;
case -EAGAIN:
case -ECONNREFUSED:
vllist->status = DNS_LOOKUP_GOT_TEMP_FAILURE;
break;
default:
vllist->status = DNS_LOOKUP_GOT_LOCAL_FAILURE;
break;
}
}
_debug("%s: got list %d %d", cell->name, vllist->source, vllist->status);
cell->dns_status = vllist->status;
now = ktime_get_real_seconds(); now = ktime_get_real_seconds();
if (min_ttl > max_ttl) if (min_ttl > max_ttl)
...@@ -379,48 +418,47 @@ static void afs_update_cell(struct afs_cell *cell) ...@@ -379,48 +418,47 @@ static void afs_update_cell(struct afs_cell *cell)
else if (expiry > now + max_ttl) else if (expiry > now + max_ttl)
expiry = now + max_ttl; expiry = now + max_ttl;
if (IS_ERR(vllist)) { _debug("%s: status %d", cell->name, vllist->status);
switch (PTR_ERR(vllist)) { if (vllist->source == DNS_RECORD_UNAVAILABLE) {
case -ENODATA: switch (vllist->status) {
case -EDESTADDRREQ: case DNS_LOOKUP_GOT_NOT_FOUND:
/* The DNS said that the cell does not exist or there /* The DNS said that the cell does not exist or there
* weren't any addresses to be had. * weren't any addresses to be had.
*/ */
set_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
cell->dns_expiry = expiry; cell->dns_expiry = expiry;
break; break;
case -EAGAIN: case DNS_LOOKUP_BAD:
case -ECONNREFUSED: case DNS_LOOKUP_GOT_LOCAL_FAILURE:
case DNS_LOOKUP_GOT_TEMP_FAILURE:
case DNS_LOOKUP_GOT_NS_FAILURE:
default: default:
set_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
cell->dns_expiry = now + 10; cell->dns_expiry = now + 10;
break; break;
} }
cell->error = -EDESTADDRREQ;
} else { } else {
clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
clear_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
/* Exclusion on changing vl_addrs is achieved by a
* non-reentrant work item.
*/
old = rcu_dereference_protected(cell->vl_servers, true);
rcu_assign_pointer(cell->vl_servers, vllist);
cell->dns_expiry = expiry; cell->dns_expiry = expiry;
if (old)
afs_put_vlserverlist(cell->net, old);
} }
if (test_and_clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags)) /* Replace the VL server list if the new record has servers or the old
wake_up_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET); * record doesn't.
*/
write_lock(&cell->vl_servers_lock);
p = rcu_dereference_protected(cell->vl_servers, true);
if (vllist->nr_servers > 0 || p->nr_servers == 0) {
rcu_assign_pointer(cell->vl_servers, vllist);
cell->dns_source = vllist->source;
old = p;
}
write_unlock(&cell->vl_servers_lock);
afs_put_vlserverlist(cell->net, old);
now = ktime_get_real_seconds(); out_wake:
afs_set_cell_timer(cell->net, cell->dns_expiry - now); smp_store_release(&cell->dns_lookup_count,
_leave(""); cell->dns_lookup_count + 1); /* vs source/status */
wake_up_var(&cell->dns_lookup_count);
_leave(" = %d", ret);
return ret;
} }
/* /*
...@@ -491,8 +529,7 @@ void afs_put_cell(struct afs_net *net, struct afs_cell *cell) ...@@ -491,8 +529,7 @@ void afs_put_cell(struct afs_net *net, struct afs_cell *cell)
now = ktime_get_real_seconds(); now = ktime_get_real_seconds();
cell->last_inactive = now; cell->last_inactive = now;
expire_delay = 0; expire_delay = 0;
if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) && if (cell->vl_servers->nr_servers)
!test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags))
expire_delay = afs_cell_gc_delay; expire_delay = afs_cell_gc_delay;
if (atomic_dec_return(&cell->usage) > 1) if (atomic_dec_return(&cell->usage) > 1)
...@@ -623,11 +660,13 @@ static void afs_manage_cell(struct work_struct *work) ...@@ -623,11 +660,13 @@ static void afs_manage_cell(struct work_struct *work)
goto final_destruction; goto final_destruction;
if (cell->state == AFS_CELL_FAILED) if (cell->state == AFS_CELL_FAILED)
goto done; goto done;
cell->state = AFS_CELL_UNSET; smp_store_release(&cell->state, AFS_CELL_UNSET);
wake_up_var(&cell->state);
goto again; goto again;
case AFS_CELL_UNSET: case AFS_CELL_UNSET:
cell->state = AFS_CELL_ACTIVATING; smp_store_release(&cell->state, AFS_CELL_ACTIVATING);
wake_up_var(&cell->state);
goto again; goto again;
case AFS_CELL_ACTIVATING: case AFS_CELL_ACTIVATING:
...@@ -635,28 +674,29 @@ static void afs_manage_cell(struct work_struct *work) ...@@ -635,28 +674,29 @@ static void afs_manage_cell(struct work_struct *work)
if (ret < 0) if (ret < 0)
goto activation_failed; goto activation_failed;
cell->state = AFS_CELL_ACTIVE; smp_store_release(&cell->state, AFS_CELL_ACTIVE);
smp_wmb(); wake_up_var(&cell->state);
clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
goto again; goto again;
case AFS_CELL_ACTIVE: case AFS_CELL_ACTIVE:
if (atomic_read(&cell->usage) > 1) { if (atomic_read(&cell->usage) > 1) {
time64_t now = ktime_get_real_seconds(); if (test_and_clear_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) {
if (cell->dns_expiry <= now && net->live) ret = afs_update_cell(cell);
afs_update_cell(cell); if (ret < 0)
cell->error = ret;
}
goto done; goto done;
} }
cell->state = AFS_CELL_DEACTIVATING; smp_store_release(&cell->state, AFS_CELL_DEACTIVATING);
wake_up_var(&cell->state);
goto again; goto again;
case AFS_CELL_DEACTIVATING: case AFS_CELL_DEACTIVATING:
set_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
if (atomic_read(&cell->usage) > 1) if (atomic_read(&cell->usage) > 1)
goto reverse_deactivation; goto reverse_deactivation;
afs_deactivate_cell(net, cell); afs_deactivate_cell(net, cell);
cell->state = AFS_CELL_INACTIVE; smp_store_release(&cell->state, AFS_CELL_INACTIVE);
wake_up_var(&cell->state);
goto again; goto again;
default: default:
...@@ -669,17 +709,13 @@ static void afs_manage_cell(struct work_struct *work) ...@@ -669,17 +709,13 @@ static void afs_manage_cell(struct work_struct *work)
cell->error = ret; cell->error = ret;
afs_deactivate_cell(net, cell); afs_deactivate_cell(net, cell);
cell->state = AFS_CELL_FAILED; smp_store_release(&cell->state, AFS_CELL_FAILED); /* vs error */
smp_wmb(); wake_up_var(&cell->state);
if (test_and_clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags))
wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
goto again; goto again;
reverse_deactivation: reverse_deactivation:
cell->state = AFS_CELL_ACTIVE; smp_store_release(&cell->state, AFS_CELL_ACTIVE);
smp_wmb(); wake_up_var(&cell->state);
clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
_leave(" [deact->act]"); _leave(" [deact->act]");
return; return;
...@@ -739,11 +775,16 @@ void afs_manage_cells(struct work_struct *work) ...@@ -739,11 +775,16 @@ void afs_manage_cells(struct work_struct *work)
} }
if (usage == 1) { if (usage == 1) {
struct afs_vlserver_list *vllist;
time64_t expire_at = cell->last_inactive; time64_t expire_at = cell->last_inactive;
if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) && read_lock(&cell->vl_servers_lock);
!test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags)) vllist = rcu_dereference_protected(
cell->vl_servers,
lockdep_is_held(&cell->vl_servers_lock));
if (vllist->nr_servers > 0)
expire_at += afs_cell_gc_delay; expire_at += afs_cell_gc_delay;
read_unlock(&cell->vl_servers_lock);
if (purging || expire_at <= now) if (purging || expire_at <= now)
sched_cell = true; sched_cell = true;
else if (expire_at < next_manage) else if (expire_at < next_manage)
...@@ -751,10 +792,8 @@ void afs_manage_cells(struct work_struct *work) ...@@ -751,10 +792,8 @@ void afs_manage_cells(struct work_struct *work)
} }
if (!purging) { if (!purging) {
if (cell->dns_expiry <= now) if (test_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags))
sched_cell = true; sched_cell = true;
else if (cell->dns_expiry <= next_manage)
next_manage = cell->dns_expiry;
} }
if (sched_cell) if (sched_cell)
......
...@@ -704,7 +704,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, ...@@ -704,7 +704,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
goto no_inline_bulk_status; goto no_inline_bulk_status;
inode = ERR_PTR(-ERESTARTSYS); inode = ERR_PTR(-ERESTARTSYS);
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
if (test_bit(AFS_SERVER_FL_NO_IBULK, if (test_bit(AFS_SERVER_FL_NO_IBULK,
&fc.cbi->server->flags)) { &fc.cbi->server->flags)) {
...@@ -739,7 +739,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, ...@@ -739,7 +739,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
*/ */
cookie->nr_fids = 1; cookie->nr_fids = 1;
inode = ERR_PTR(-ERESTARTSYS); inode = ERR_PTR(-ERESTARTSYS);
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
afs_fs_fetch_status(&fc, afs_fs_fetch_status(&fc,
afs_v2net(dvnode), afs_v2net(dvnode),
...@@ -1166,7 +1166,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -1166,7 +1166,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
} }
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_create(&fc, dentry->d_name.name, mode, data_version, afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
...@@ -1250,7 +1250,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1250,7 +1250,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
} }
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_remove(&fc, vnode, dentry->d_name.name, true, afs_fs_remove(&fc, vnode, dentry->d_name.name, true,
...@@ -1374,7 +1374,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1374,7 +1374,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
...@@ -1445,7 +1445,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -1445,7 +1445,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
} }
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_create(&fc, dentry->d_name.name, mode, data_version, afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
...@@ -1510,7 +1510,7 @@ static int afs_link(struct dentry *from, struct inode *dir, ...@@ -1510,7 +1510,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
} }
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) { if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) {
afs_end_vnode_operation(&fc); afs_end_vnode_operation(&fc);
goto error_key; goto error_key;
...@@ -1584,7 +1584,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1584,7 +1584,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
} }
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_symlink(&fc, dentry->d_name.name, afs_fs_symlink(&fc, dentry->d_name.name,
...@@ -1696,7 +1696,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1696,7 +1696,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, orig_dvnode, key)) { if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) {
if (orig_dvnode != new_dvnode) { if (orig_dvnode != new_dvnode) {
if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) { if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) {
afs_end_vnode_operation(&fc); afs_end_vnode_operation(&fc);
......
...@@ -30,7 +30,7 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode ...@@ -30,7 +30,7 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
_enter("%pd,%pd", old, new); _enter("%pd,%pd", old, new);
trace_afs_silly_rename(vnode, false); trace_afs_silly_rename(vnode, false);
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_rename(&fc, old->d_name.name, afs_fs_rename(&fc, old->d_name.name,
...@@ -149,7 +149,7 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode ...@@ -149,7 +149,7 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode
_enter(""); _enter("");
trace_afs_silly_rename(vnode, true); trace_afs_silly_rename(vnode, true);
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key, false)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break = afs_calc_vnode_cb_break(dvnode);
......
...@@ -46,7 +46,7 @@ static int afs_probe_cell_name(struct dentry *dentry) ...@@ -46,7 +46,7 @@ static int afs_probe_cell_name(struct dentry *dentry)
return 0; return 0;
} }
ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL); ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL, false);
if (ret == -ENODATA) if (ret == -ENODATA)
ret = -EDESTADDRREQ; ret = -EDESTADDRREQ;
return ret; return ret;
...@@ -261,8 +261,7 @@ int afs_dynroot_populate(struct super_block *sb) ...@@ -261,8 +261,7 @@ int afs_dynroot_populate(struct super_block *sb)
struct afs_net *net = afs_sb2net(sb); struct afs_net *net = afs_sb2net(sb);
int ret; int ret;
if (mutex_lock_interruptible(&net->proc_cells_lock) < 0) mutex_lock(&net->proc_cells_lock);
return -ERESTARTSYS;
net->dynroot_sb = sb; net->dynroot_sb = sb;
hlist_for_each_entry(cell, &net->proc_cells, proc_link) { hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
......
...@@ -170,11 +170,12 @@ int afs_release(struct inode *inode, struct file *file) ...@@ -170,11 +170,12 @@ int afs_release(struct inode *inode, struct file *file)
{ {
struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_vnode *vnode = AFS_FS_I(inode);
struct afs_file *af = file->private_data; struct afs_file *af = file->private_data;
int ret = 0;
_enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode); _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode);
if ((file->f_mode & FMODE_WRITE)) if ((file->f_mode & FMODE_WRITE))
return vfs_fsync(file, 0); ret = vfs_fsync(file, 0);
file->private_data = NULL; file->private_data = NULL;
if (af->wb) if (af->wb)
...@@ -182,8 +183,8 @@ int afs_release(struct inode *inode, struct file *file) ...@@ -182,8 +183,8 @@ int afs_release(struct inode *inode, struct file *file)
key_put(af->key); key_put(af->key);
kfree(af); kfree(af);
afs_prune_wb_keys(vnode); afs_prune_wb_keys(vnode);
_leave(" = 0"); _leave(" = %d", ret);
return 0; return ret;
} }
/* /*
...@@ -237,7 +238,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de ...@@ -237,7 +238,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
key_serial(key)); key_serial(key));
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_fetch_data(&fc, desc); afs_fs_fetch_data(&fc, desc);
......
...@@ -41,9 +41,6 @@ void afs_lock_may_be_available(struct afs_vnode *vnode) ...@@ -41,9 +41,6 @@ void afs_lock_may_be_available(struct afs_vnode *vnode)
{ {
_enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
if (vnode->lock_state != AFS_VNODE_LOCK_WAITING_FOR_CB)
return;
spin_lock(&vnode->lock); spin_lock(&vnode->lock);
if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB) if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB)
afs_next_locker(vnode, 0); afs_next_locker(vnode, 0);
...@@ -196,7 +193,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key, ...@@ -196,7 +193,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
key_serial(key), type); key_serial(key), type);
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_set_lock(&fc, type); afs_fs_set_lock(&fc, type);
...@@ -227,7 +224,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key) ...@@ -227,7 +224,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key)
key_serial(key)); key_serial(key));
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, false)) {
while (afs_select_current_fileserver(&fc)) { while (afs_select_current_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_extend_lock(&fc); afs_fs_extend_lock(&fc);
...@@ -258,7 +255,7 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key) ...@@ -258,7 +255,7 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key)
key_serial(key)); key_serial(key));
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, false)) {
while (afs_select_current_fileserver(&fc)) { while (afs_select_current_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_release_lock(&fc); afs_fs_release_lock(&fc);
......
...@@ -256,6 +256,23 @@ static int afs_decode_status(struct afs_call *call, ...@@ -256,6 +256,23 @@ static int afs_decode_status(struct afs_call *call,
return ret; return ret;
} }
static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
{
return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
}
static void xdr_decode_AFSCallBack_raw(struct afs_call *call,
struct afs_callback *cb,
const __be32 **_bp)
{
const __be32 *bp = *_bp;
cb->version = ntohl(*bp++);
cb->expires_at = xdr_decode_expiry(call, ntohl(*bp++));
cb->type = ntohl(*bp++);
*_bp = bp;
}
/* /*
* decode an AFSCallBack block * decode an AFSCallBack block
*/ */
...@@ -264,46 +281,26 @@ static void xdr_decode_AFSCallBack(struct afs_call *call, ...@@ -264,46 +281,26 @@ static void xdr_decode_AFSCallBack(struct afs_call *call,
const __be32 **_bp) const __be32 **_bp)
{ {
struct afs_cb_interest *old, *cbi = call->cbi; struct afs_cb_interest *old, *cbi = call->cbi;
const __be32 *bp = *_bp; struct afs_callback cb;
u32 cb_expiry;
xdr_decode_AFSCallBack_raw(call, &cb, _bp);
write_seqlock(&vnode->cb_lock); write_seqlock(&vnode->cb_lock);
if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) { if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) {
vnode->cb_version = ntohl(*bp++); vnode->cb_version = cb.version;
cb_expiry = ntohl(*bp++); vnode->cb_type = cb.type;
vnode->cb_type = ntohl(*bp++); vnode->cb_expires_at = cb.expires_at;
vnode->cb_expires_at = cb_expiry + ktime_get_real_seconds();
old = vnode->cb_interest; old = vnode->cb_interest;
if (old != call->cbi) { if (old != call->cbi) {
vnode->cb_interest = cbi; vnode->cb_interest = cbi;
cbi = old; cbi = old;
} }
set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
} else {
bp += 3;
} }
write_sequnlock(&vnode->cb_lock); write_sequnlock(&vnode->cb_lock);
call->cbi = cbi; call->cbi = cbi;
*_bp = bp;
}
static ktime_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
{
return ktime_add_ns(call->reply_time, expiry * NSEC_PER_SEC);
}
static void xdr_decode_AFSCallBack_raw(struct afs_call *call,
const __be32 **_bp,
struct afs_callback *cb)
{
const __be32 *bp = *_bp;
cb->version = ntohl(*bp++);
cb->expires_at = xdr_decode_expiry(call, ntohl(*bp++));
cb->type = ntohl(*bp++);
*_bp = bp;
} }
/* /*
...@@ -469,6 +466,7 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy ...@@ -469,6 +466,7 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -664,6 +662,7 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) ...@@ -664,6 +662,7 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
call->cb_break = fc->cb_break; call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -712,6 +711,7 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) ...@@ -712,6 +711,7 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
call->cb_break = fc->cb_break; call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -741,7 +741,7 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call) ...@@ -741,7 +741,7 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call)
&call->expected_version, NULL); &call->expected_version, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;
xdr_decode_AFSCallBack_raw(call, &bp, call->reply[3]); xdr_decode_AFSCallBack_raw(call, call->reply[3], &bp);
/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
_leave(" = 0 [done]"); _leave(" = 0 [done]");
...@@ -833,6 +833,7 @@ int afs_fs_create(struct afs_fs_cursor *fc, ...@@ -833,6 +833,7 @@ int afs_fs_create(struct afs_fs_cursor *fc,
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call1(call, &vnode->fid, name); trace_afs_make_fs_call1(call, &vnode->fid, name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -930,6 +931,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, ...@@ -930,6 +931,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call1(call, &dvnode->fid, name); trace_afs_make_fs_call1(call, &dvnode->fid, name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1023,6 +1025,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, ...@@ -1023,6 +1025,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call1(call, &vnode->fid, name); trace_afs_make_fs_call1(call, &vnode->fid, name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1138,6 +1141,7 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, ...@@ -1138,6 +1141,7 @@ int afs_fs_symlink(struct afs_fs_cursor *fc,
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call1(call, &vnode->fid, name); trace_afs_make_fs_call1(call, &vnode->fid, name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1257,6 +1261,7 @@ int afs_fs_rename(struct afs_fs_cursor *fc, ...@@ -1257,6 +1261,7 @@ int afs_fs_rename(struct afs_fs_cursor *fc,
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name); trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1362,6 +1367,7 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, ...@@ -1362,6 +1367,7 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
*bp++ = htonl((u32) i_size); *bp++ = htonl((u32) i_size);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1439,6 +1445,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, ...@@ -1439,6 +1445,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1538,6 +1545,7 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) ...@@ -1538,6 +1545,7 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1585,6 +1593,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) ...@@ -1585,6 +1593,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1630,6 +1639,7 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) ...@@ -1630,6 +1639,7 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1815,6 +1825,7 @@ int afs_fs_get_volume_status(struct afs_fs_cursor *fc, ...@@ -1815,6 +1825,7 @@ int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1906,6 +1917,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) ...@@ -1906,6 +1917,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_calli(call, &vnode->fid, type); trace_afs_make_fs_calli(call, &vnode->fid, type);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1942,6 +1954,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc) ...@@ -1942,6 +1954,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc)
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -1977,6 +1990,7 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc) ...@@ -1977,6 +1990,7 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc)
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid); trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -2115,6 +2129,7 @@ struct afs_call *afs_fs_get_capabilities(struct afs_net *net, ...@@ -2115,6 +2129,7 @@ struct afs_call *afs_fs_get_capabilities(struct afs_net *net,
call->upgrade = true; call->upgrade = true;
call->want_reply_time = true; call->want_reply_time = true;
call->async = true; call->async = true;
call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
/* marshall the parameters */ /* marshall the parameters */
bp = call->request; bp = call->request;
...@@ -2150,7 +2165,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call) ...@@ -2150,7 +2165,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call)
&call->expected_version, NULL); &call->expected_version, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;
xdr_decode_AFSCallBack_raw(call, &bp, callback); xdr_decode_AFSCallBack_raw(call, callback, &bp);
xdr_decode_AFSVolSync(&bp, volsync); xdr_decode_AFSVolSync(&bp, volsync);
_leave(" = 0 [done]"); _leave(" = 0 [done]");
...@@ -2210,6 +2225,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc, ...@@ -2210,6 +2225,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc,
call->cb_break = fc->cb_break; call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, fid); trace_afs_make_fs_call(call, fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
...@@ -2303,9 +2319,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) ...@@ -2303,9 +2319,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
_debug("unmarshall CB array"); _debug("unmarshall CB array");
bp = call->buffer; bp = call->buffer;
callbacks = call->reply[2]; callbacks = call->reply[2];
callbacks[call->count].version = ntohl(bp[0]); xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp);
callbacks[call->count].expires_at = xdr_decode_expiry(call, ntohl(bp[1]));
callbacks[call->count].type = ntohl(bp[2]);
statuses = call->reply[1]; statuses = call->reply[1];
if (call->count == 0 && vnode && statuses[0].abort_code == 0) if (call->count == 0 && vnode && statuses[0].abort_code == 0)
xdr_decode_AFSCallBack(call, vnode, &bp); xdr_decode_AFSCallBack(call, vnode, &bp);
...@@ -2396,6 +2410,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, ...@@ -2396,6 +2410,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
call->cb_break = fc->cb_break; call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi); afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &fids[0]); trace_afs_make_fs_call(call, &fids[0]);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS); afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac); return afs_wait_for_call_to_complete(call, &fc->ac);
} }
......
...@@ -136,7 +136,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode) ...@@ -136,7 +136,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
vnode->flags); vnode->flags);
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_fetch_file_status(&fc, NULL, new_inode); afs_fs_fetch_file_status(&fc, NULL, new_inode);
...@@ -430,12 +430,9 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) ...@@ -430,12 +430,9 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
vnode->cb_v_break = vnode->volume->cb_v_break; vnode->cb_v_break = vnode->volume->cb_v_break;
valid = false; valid = false;
} else if (vnode->status.type == AFS_FTYPE_DIR && } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
(!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) ||
vnode->cb_expires_at - 10 <= now)) {
valid = false; valid = false;
} else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) || } else if (vnode->cb_expires_at - 10 <= now) {
vnode->cb_expires_at - 10 <= now) {
valid = false; valid = false;
} else { } else {
valid = true; valid = true;
...@@ -573,6 +570,7 @@ void afs_evict_inode(struct inode *inode) ...@@ -573,6 +570,7 @@ void afs_evict_inode(struct inode *inode)
} }
#endif #endif
afs_prune_wb_keys(vnode);
afs_put_permits(rcu_access_pointer(vnode->permit_cache)); afs_put_permits(rcu_access_pointer(vnode->permit_cache));
key_put(vnode->silly_key); key_put(vnode->silly_key);
vnode->silly_key = NULL; vnode->silly_key = NULL;
...@@ -616,7 +614,7 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -616,7 +614,7 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
} }
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, false)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_setattr(&fc, attr); afs_fs_setattr(&fc, attr);
......
...@@ -131,6 +131,7 @@ struct afs_call { ...@@ -131,6 +131,7 @@ struct afs_call {
int error; /* error code */ int error; /* error code */
u32 abort_code; /* Remote abort ID or 0 */ u32 abort_code; /* Remote abort ID or 0 */
u32 epoch; u32 epoch;
unsigned int max_lifespan; /* Maximum lifespan to set if not 0 */
unsigned request_size; /* size of request data */ unsigned request_size; /* size of request data */
unsigned reply_max; /* maximum size of reply */ unsigned reply_max; /* maximum size of reply */
unsigned first_offset; /* offset into mapping[first] */ unsigned first_offset; /* offset into mapping[first] */
...@@ -148,6 +149,7 @@ struct afs_call { ...@@ -148,6 +149,7 @@ struct afs_call {
bool ret_reply0; /* T if should return reply[0] on success */ bool ret_reply0; /* T if should return reply[0] on success */
bool upgrade; /* T to request service upgrade */ bool upgrade; /* T to request service upgrade */
bool want_reply_time; /* T if want reply_time */ bool want_reply_time; /* T if want reply_time */
bool intr; /* T if interruptible */
u16 service_id; /* Actual service ID (after upgrade) */ u16 service_id; /* Actual service ID (after upgrade) */
unsigned int debug_id; /* Trace ID */ unsigned int debug_id; /* Trace ID */
u32 operation_ID; /* operation ID for an incoming call */ u32 operation_ID; /* operation ID for an incoming call */
...@@ -367,13 +369,13 @@ struct afs_cell { ...@@ -367,13 +369,13 @@ struct afs_cell {
time64_t last_inactive; /* Time of last drop of usage count */ time64_t last_inactive; /* Time of last drop of usage count */
atomic_t usage; atomic_t usage;
unsigned long flags; unsigned long flags;
#define AFS_CELL_FL_NOT_READY 0 /* The cell record is not ready for use */ #define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */
#define AFS_CELL_FL_NO_GC 1 /* The cell was added manually, don't auto-gc */ #define AFS_CELL_FL_DO_LOOKUP 1 /* DNS lookup requested */
#define AFS_CELL_FL_NOT_FOUND 2 /* Permanent DNS error */
#define AFS_CELL_FL_DNS_FAIL 3 /* Failed to access DNS */
#define AFS_CELL_FL_NO_LOOKUP_YET 4 /* Not completed first DNS lookup yet */
enum afs_cell_state state; enum afs_cell_state state;
short error; short error;
enum dns_record_source dns_source:8; /* Latest source of data from lookup */
enum dns_lookup_status dns_status:8; /* Latest status of data from lookup */
unsigned int dns_lookup_count; /* Counter of DNS lookups */
/* Active fileserver interaction state. */ /* Active fileserver interaction state. */
struct list_head proc_volumes; /* procfs volume list */ struct list_head proc_volumes; /* procfs volume list */
...@@ -772,6 +774,7 @@ struct afs_fs_cursor { ...@@ -772,6 +774,7 @@ struct afs_fs_cursor {
#define AFS_FS_CURSOR_VNOVOL 0x0008 /* Set if seen VNOVOL */ #define AFS_FS_CURSOR_VNOVOL 0x0008 /* Set if seen VNOVOL */
#define AFS_FS_CURSOR_CUR_ONLY 0x0010 /* Set if current server only (file lock held) */ #define AFS_FS_CURSOR_CUR_ONLY 0x0010 /* Set if current server only (file lock held) */
#define AFS_FS_CURSOR_NO_VSLEEP 0x0020 /* Set to prevent sleep on VBUSY, VOFFLINE, ... */ #define AFS_FS_CURSOR_NO_VSLEEP 0x0020 /* Set to prevent sleep on VBUSY, VOFFLINE, ... */
#define AFS_FS_CURSOR_INTR 0x0040 /* Set if op is interruptible */
unsigned short nr_iterations; /* Number of server iterations */ unsigned short nr_iterations; /* Number of server iterations */
}; };
...@@ -1096,7 +1099,7 @@ static inline void afs_put_sysnames(struct afs_sysnames *sysnames) {} ...@@ -1096,7 +1099,7 @@ static inline void afs_put_sysnames(struct afs_sysnames *sysnames) {}
* rotate.c * rotate.c
*/ */
extern bool afs_begin_vnode_operation(struct afs_fs_cursor *, struct afs_vnode *, extern bool afs_begin_vnode_operation(struct afs_fs_cursor *, struct afs_vnode *,
struct key *); struct key *, bool);
extern bool afs_select_fileserver(struct afs_fs_cursor *); extern bool afs_select_fileserver(struct afs_fs_cursor *);
extern bool afs_select_current_fileserver(struct afs_fs_cursor *); extern bool afs_select_current_fileserver(struct afs_fs_cursor *);
extern int afs_end_vnode_operation(struct afs_fs_cursor *); extern int afs_end_vnode_operation(struct afs_fs_cursor *);
...@@ -1121,6 +1124,11 @@ extern void afs_send_simple_reply(struct afs_call *, const void *, size_t); ...@@ -1121,6 +1124,11 @@ extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);
extern int afs_extract_data(struct afs_call *, bool); extern int afs_extract_data(struct afs_call *, bool);
extern int afs_protocol_error(struct afs_call *, int, enum afs_eproto_cause); extern int afs_protocol_error(struct afs_call *, int, enum afs_eproto_cause);
static inline void afs_set_fc_call(struct afs_call *call, struct afs_fs_cursor *fc)
{
call->intr = fc->flags & AFS_FS_CURSOR_INTR;
}
static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size) static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
{ {
call->kvec[0].iov_base = buf; call->kvec[0].iov_base = buf;
...@@ -1382,7 +1390,7 @@ struct yfs_acl { ...@@ -1382,7 +1390,7 @@ struct yfs_acl {
}; };
extern void yfs_free_opaque_acl(struct yfs_acl *); extern void yfs_free_opaque_acl(struct yfs_acl *);
extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, unsigned int); extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, struct yfs_acl *);
extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *); extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *);
/* /*
......
...@@ -53,7 +53,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v) ...@@ -53,7 +53,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
seq_printf(m, "%3u %6lld %2u %s\n", seq_printf(m, "%3u %6lld %2u %s\n",
atomic_read(&cell->usage), atomic_read(&cell->usage),
cell->dns_expiry - ktime_get_real_seconds(), cell->dns_expiry - ktime_get_real_seconds(),
vllist ? vllist->nr_servers : 0, vllist->nr_servers,
cell->name); cell->name);
return 0; return 0;
} }
...@@ -296,8 +296,8 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) ...@@ -296,8 +296,8 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
if (v == SEQ_START_TOKEN) { if (v == SEQ_START_TOKEN) {
seq_printf(m, "# source %s, status %s\n", seq_printf(m, "# source %s, status %s\n",
dns_record_sources[vllist->source], dns_record_sources[vllist ? vllist->source : 0],
dns_lookup_statuses[vllist->status]); dns_lookup_statuses[vllist ? vllist->status : 0]);
return 0; return 0;
} }
...@@ -336,7 +336,7 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) ...@@ -336,7 +336,7 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
if (pos == 0) if (pos == 0)
return SEQ_START_TOKEN; return SEQ_START_TOKEN;
if (!vllist || pos - 1 >= vllist->nr_servers) if (pos - 1 >= vllist->nr_servers)
return NULL; return NULL;
return &vllist->servers[pos - 1]; return &vllist->servers[pos - 1];
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
* them here also using the io_lock. * them here also using the io_lock.
*/ */
bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode, bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
struct key *key) struct key *key, bool intr)
{ {
memset(fc, 0, sizeof(*fc)); memset(fc, 0, sizeof(*fc));
fc->vnode = vnode; fc->vnode = vnode;
...@@ -33,10 +33,15 @@ bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode ...@@ -33,10 +33,15 @@ bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode
fc->ac.error = SHRT_MAX; fc->ac.error = SHRT_MAX;
fc->error = -EDESTADDRREQ; fc->error = -EDESTADDRREQ;
if (mutex_lock_interruptible(&vnode->io_lock) < 0) { if (intr) {
fc->error = -EINTR; fc->flags |= AFS_FS_CURSOR_INTR;
fc->flags |= AFS_FS_CURSOR_STOP; if (mutex_lock_interruptible(&vnode->io_lock) < 0) {
return false; fc->error = -EINTR;
fc->flags |= AFS_FS_CURSOR_STOP;
return false;
}
} else {
mutex_lock(&vnode->io_lock);
} }
if (vnode->lock_state != AFS_VNODE_LOCK_NONE) if (vnode->lock_state != AFS_VNODE_LOCK_NONE)
...@@ -118,10 +123,14 @@ static void afs_busy(struct afs_volume *volume, u32 abort_code) ...@@ -118,10 +123,14 @@ static void afs_busy(struct afs_volume *volume, u32 abort_code)
*/ */
static bool afs_sleep_and_retry(struct afs_fs_cursor *fc) static bool afs_sleep_and_retry(struct afs_fs_cursor *fc)
{ {
msleep_interruptible(1000); if (fc->flags & AFS_FS_CURSOR_INTR) {
if (signal_pending(current)) { msleep_interruptible(1000);
fc->error = -ERESTARTSYS; if (signal_pending(current)) {
return false; fc->error = -ERESTARTSYS;
return false;
}
} else {
msleep(1000);
} }
return true; return true;
...@@ -459,6 +468,8 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc) ...@@ -459,6 +468,8 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
s->probe.abort_code); s->probe.abort_code);
} }
error = e.error;
failed_set_error: failed_set_error:
fc->error = error; fc->error = error;
failed: failed:
......
...@@ -417,6 +417,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) ...@@ -417,6 +417,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
afs_wake_up_async_call : afs_wake_up_async_call :
afs_wake_up_call_waiter), afs_wake_up_call_waiter),
call->upgrade, call->upgrade,
call->intr,
call->debug_id); call->debug_id);
if (IS_ERR(rxcall)) { if (IS_ERR(rxcall)) {
ret = PTR_ERR(rxcall); ret = PTR_ERR(rxcall);
...@@ -426,6 +427,10 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) ...@@ -426,6 +427,10 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
call->rxcall = rxcall; call->rxcall = rxcall;
if (call->max_lifespan)
rxrpc_kernel_set_max_life(call->net->socket, rxcall,
call->max_lifespan);
/* send the request */ /* send the request */
iov[0].iov_base = call->request; iov[0].iov_base = call->request;
iov[0].iov_len = call->request_size; iov[0].iov_len = call->request_size;
...@@ -648,7 +653,7 @@ long afs_wait_for_call_to_complete(struct afs_call *call, ...@@ -648,7 +653,7 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
break; break;
} }
if (timeout == 0 && if (call->intr && timeout == 0 &&
life == last_life && signal_pending(current)) { life == last_life && signal_pending(current)) {
if (stalled) if (stalled)
break; break;
......
...@@ -87,11 +87,9 @@ void afs_clear_permits(struct afs_vnode *vnode) ...@@ -87,11 +87,9 @@ void afs_clear_permits(struct afs_vnode *vnode)
permits = rcu_dereference_protected(vnode->permit_cache, permits = rcu_dereference_protected(vnode->permit_cache,
lockdep_is_held(&vnode->lock)); lockdep_is_held(&vnode->lock));
RCU_INIT_POINTER(vnode->permit_cache, NULL); RCU_INIT_POINTER(vnode->permit_cache, NULL);
vnode->cb_break++;
spin_unlock(&vnode->lock); spin_unlock(&vnode->lock);
if (permits) afs_put_permits(permits);
afs_put_permits(permits);
} }
/* /*
......
...@@ -521,8 +521,15 @@ static noinline bool afs_update_server_record(struct afs_fs_cursor *fc, struct a ...@@ -521,8 +521,15 @@ static noinline bool afs_update_server_record(struct afs_fs_cursor *fc, struct a
alist = afs_vl_lookup_addrs(fc->vnode->volume->cell, fc->key, alist = afs_vl_lookup_addrs(fc->vnode->volume->cell, fc->key,
&server->uuid); &server->uuid);
if (IS_ERR(alist)) { if (IS_ERR(alist)) {
fc->ac.error = PTR_ERR(alist); if ((PTR_ERR(alist) == -ERESTARTSYS ||
_leave(" = f [%d]", fc->ac.error); PTR_ERR(alist) == -EINTR) &&
!(fc->flags & AFS_FS_CURSOR_INTR) &&
server->addresses) {
_leave(" = t [intr]");
return true;
}
fc->error = PTR_ERR(alist);
_leave(" = f [%d]", fc->error);
return false; return false;
} }
...@@ -574,7 +581,11 @@ bool afs_check_server_record(struct afs_fs_cursor *fc, struct afs_server *server ...@@ -574,7 +581,11 @@ bool afs_check_server_record(struct afs_fs_cursor *fc, struct afs_server *server
ret = wait_on_bit(&server->flags, AFS_SERVER_FL_UPDATING, ret = wait_on_bit(&server->flags, AFS_SERVER_FL_UPDATING,
TASK_INTERRUPTIBLE); TASK_INTERRUPTIBLE);
if (ret == -ERESTARTSYS) { if (ret == -ERESTARTSYS) {
fc->ac.error = ret; if (!(fc->flags & AFS_FS_CURSOR_INTR) && server->addresses) {
_leave(" = t [intr]");
return true;
}
fc->error = ret;
_leave(" = f [intr]"); _leave(" = f [intr]");
return false; return false;
} }
......
...@@ -741,7 +741,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -741,7 +741,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
return PTR_ERR(key); return PTR_ERR(key);
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; fc.flags |= AFS_FS_CURSOR_NO_VSLEEP;
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
......
...@@ -232,18 +232,16 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, ...@@ -232,18 +232,16 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
if (bs.status > NR__dns_lookup_status) if (bs.status > NR__dns_lookup_status)
bs.status = NR__dns_lookup_status; bs.status = NR__dns_lookup_status;
/* See if we can update an old server record */
server = NULL; server = NULL;
if (previous) { for (i = 0; i < previous->nr_servers; i++) {
/* See if we can update an old server record */ struct afs_vlserver *p = previous->servers[i].server;
for (i = 0; i < previous->nr_servers; i++) {
struct afs_vlserver *p = previous->servers[i].server; if (p->name_len == bs.name_len &&
p->port == bs.port &&
if (p->name_len == bs.name_len && strncasecmp(b, p->name, bs.name_len) == 0) {
p->port == bs.port && server = afs_get_vlserver(p);
strncasecmp(b, p->name, bs.name_len) == 0) { break;
server = afs_get_vlserver(p);
break;
}
} }
} }
......
...@@ -43,11 +43,29 @@ bool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cel ...@@ -43,11 +43,29 @@ bool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cel
static bool afs_start_vl_iteration(struct afs_vl_cursor *vc) static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
{ {
struct afs_cell *cell = vc->cell; struct afs_cell *cell = vc->cell;
unsigned int dns_lookup_count;
if (cell->dns_source == DNS_RECORD_UNAVAILABLE ||
cell->dns_expiry <= ktime_get_real_seconds()) {
dns_lookup_count = smp_load_acquire(&cell->dns_lookup_count);
set_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags);
queue_work(afs_wq, &cell->manager);
if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
if (wait_var_event_interruptible(
&cell->dns_lookup_count,
smp_load_acquire(&cell->dns_lookup_count)
!= dns_lookup_count) < 0) {
vc->error = -ERESTARTSYS;
return false;
}
}
if (wait_on_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET, /* Status load is ordered after lookup counter load */
TASK_INTERRUPTIBLE)) { if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
vc->error = -ERESTARTSYS; vc->error = -EDESTADDRREQ;
return false; return false;
}
} }
read_lock(&cell->vl_servers_lock); read_lock(&cell->vl_servers_lock);
...@@ -55,7 +73,7 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc) ...@@ -55,7 +73,7 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
rcu_dereference_protected(cell->vl_servers, rcu_dereference_protected(cell->vl_servers,
lockdep_is_held(&cell->vl_servers_lock))); lockdep_is_held(&cell->vl_servers_lock)));
read_unlock(&cell->vl_servers_lock); read_unlock(&cell->vl_servers_lock);
if (!vc->server_list || !vc->server_list->nr_servers) if (!vc->server_list->nr_servers)
return false; return false;
vc->untried = (1UL << vc->server_list->nr_servers) - 1; vc->untried = (1UL << vc->server_list->nr_servers) - 1;
......
...@@ -157,6 +157,7 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc, ...@@ -157,6 +157,7 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
call->key = vc->key; call->key = vc->key;
call->reply[0] = entry; call->reply[0] = entry;
call->ret_reply0 = true; call->ret_reply0 = true;
call->max_lifespan = AFS_VL_MAX_LIFESPAN;
/* Marshall the parameters */ /* Marshall the parameters */
bp = call->request; bp = call->request;
...@@ -289,6 +290,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc, ...@@ -289,6 +290,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
call->key = vc->key; call->key = vc->key;
call->reply[0] = NULL; call->reply[0] = NULL;
call->ret_reply0 = true; call->ret_reply0 = true;
call->max_lifespan = AFS_VL_MAX_LIFESPAN;
/* Marshall the parameters */ /* Marshall the parameters */
bp = call->request; bp = call->request;
...@@ -403,6 +405,7 @@ struct afs_call *afs_vl_get_capabilities(struct afs_net *net, ...@@ -403,6 +405,7 @@ struct afs_call *afs_vl_get_capabilities(struct afs_net *net,
call->upgrade = true; call->upgrade = true;
call->want_reply_time = true; call->want_reply_time = true;
call->async = true; call->async = true;
call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
/* marshall the parameters */ /* marshall the parameters */
bp = call->request; bp = call->request;
...@@ -646,6 +649,7 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc, ...@@ -646,6 +649,7 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
call->key = vc->key; call->key = vc->key;
call->reply[0] = NULL; call->reply[0] = NULL;
call->ret_reply0 = true; call->ret_reply0 = true;
call->max_lifespan = AFS_VL_MAX_LIFESPAN;
/* Marshall the parameters */ /* Marshall the parameters */
bp = call->request; bp = call->request;
......
...@@ -361,7 +361,7 @@ static int afs_store_data(struct address_space *mapping, ...@@ -361,7 +361,7 @@ static int afs_store_data(struct address_space *mapping,
_debug("USE WB KEY %u", key_serial(wbk->key)); _debug("USE WB KEY %u", key_serial(wbk->key));
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, wbk->key)) { if (afs_begin_vnode_operation(&fc, vnode, wbk->key, false)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_store_data(&fc, mapping, first, last, offset, to); afs_fs_store_data(&fc, mapping, first, last, offset, to);
......
...@@ -57,7 +57,7 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler, ...@@ -57,7 +57,7 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler,
return PTR_ERR(key); return PTR_ERR(key);
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
acl = afs_fs_fetch_acl(&fc); acl = afs_fs_fetch_acl(&fc);
...@@ -71,11 +71,10 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler, ...@@ -71,11 +71,10 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler,
if (ret == 0) { if (ret == 0) {
ret = acl->size; ret = acl->size;
if (size > 0) { if (size > 0) {
ret = -ERANGE; if (acl->size <= size)
if (acl->size > size) memcpy(buffer, acl->data, acl->size);
return -ERANGE; else
memcpy(buffer, acl->data, acl->size); ret = -ERANGE;
ret = acl->size;
} }
kfree(acl); kfree(acl);
} }
...@@ -115,7 +114,7 @@ static int afs_xattr_set_acl(const struct xattr_handler *handler, ...@@ -115,7 +114,7 @@ static int afs_xattr_set_acl(const struct xattr_handler *handler,
memcpy(acl->data, buffer, size); memcpy(acl->data, buffer, size);
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_store_acl(&fc, acl); afs_fs_store_acl(&fc, acl);
...@@ -149,9 +148,8 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, ...@@ -149,9 +148,8 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_vnode *vnode = AFS_FS_I(inode);
struct yfs_acl *yacl = NULL; struct yfs_acl *yacl = NULL;
struct key *key; struct key *key;
unsigned int flags = 0;
char buf[16], *data; char buf[16], *data;
int which = 0, dsize, ret; int which = 0, dsize, ret = -ENOMEM;
if (strcmp(name, "acl") == 0) if (strcmp(name, "acl") == 0)
which = 0; which = 0;
...@@ -164,20 +162,26 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, ...@@ -164,20 +162,26 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
else else
return -EOPNOTSUPP; return -EOPNOTSUPP;
yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
if (!yacl)
goto error;
if (which == 0) if (which == 0)
flags |= YFS_ACL_WANT_ACL; yacl->flags |= YFS_ACL_WANT_ACL;
else if (which == 3) else if (which == 3)
flags |= YFS_ACL_WANT_VOL_ACL; yacl->flags |= YFS_ACL_WANT_VOL_ACL;
key = afs_request_key(vnode->volume->cell); key = afs_request_key(vnode->volume->cell);
if (IS_ERR(key)) if (IS_ERR(key)) {
return PTR_ERR(key); ret = PTR_ERR(key);
goto error_yacl;
}
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
yacl = yfs_fs_fetch_opaque_acl(&fc, flags); yfs_fs_fetch_opaque_acl(&fc, yacl);
} }
afs_check_for_remote_deletion(&fc, fc.vnode); afs_check_for_remote_deletion(&fc, fc.vnode);
...@@ -185,44 +189,45 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, ...@@ -185,44 +189,45 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
ret = afs_end_vnode_operation(&fc); ret = afs_end_vnode_operation(&fc);
} }
if (ret == 0) { if (ret < 0)
switch (which) { goto error_key;
case 0:
data = yacl->acl->data; switch (which) {
dsize = yacl->acl->size; case 0:
break; data = yacl->acl->data;
case 1: dsize = yacl->acl->size;
data = buf; break;
dsize = snprintf(buf, sizeof(buf), "%u", case 1:
yacl->inherit_flag); data = buf;
break; dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
case 2: break;
data = buf; case 2:
dsize = snprintf(buf, sizeof(buf), "%u", data = buf;
yacl->num_cleaned); dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
break; break;
case 3: case 3:
data = yacl->vol_acl->data; data = yacl->vol_acl->data;
dsize = yacl->vol_acl->size; dsize = yacl->vol_acl->size;
break; break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out; goto error_key;
} }
ret = dsize; ret = dsize;
if (size > 0) { if (size > 0) {
if (dsize > size) { if (dsize > size) {
ret = -ERANGE; ret = -ERANGE;
goto out; goto error_key;
}
memcpy(buffer, data, dsize);
} }
memcpy(buffer, data, dsize);
} }
out: error_key:
yfs_free_opaque_acl(yacl);
key_put(key); key_put(key);
error_yacl:
yfs_free_opaque_acl(yacl);
error:
return ret; return ret;
} }
...@@ -258,7 +263,7 @@ static int afs_xattr_set_yfs(const struct xattr_handler *handler, ...@@ -258,7 +263,7 @@ static int afs_xattr_set_yfs(const struct xattr_handler *handler,
memcpy(acl->data, buffer, size); memcpy(acl->data, buffer, size);
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode); fc.cb_break = afs_calc_vnode_cb_break(vnode);
yfs_fs_store_opaque_acl2(&fc, acl); yfs_fs_store_opaque_acl2(&fc, acl);
......
This diff is collapsed.
...@@ -77,7 +77,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) ...@@ -77,7 +77,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
goto name_is_IP_address; goto name_is_IP_address;
/* Perform the upcall */ /* Perform the upcall */
rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL); rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL, false);
if (rc < 0) if (rc < 0)
cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n", cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
__func__, len, len, hostname); __func__, len, len, hostname);
......
...@@ -22,7 +22,7 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen, ...@@ -22,7 +22,7 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
char *ip_addr = NULL; char *ip_addr = NULL;
int ip_len; int ip_len;
ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL); ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL, false);
if (ip_len > 0) if (ip_len > 0)
ret = rpc_pton(net, ip_addr, ip_len, sa, salen); ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
else else
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <uapi/linux/dns_resolver.h> #include <uapi/linux/dns_resolver.h>
extern int dns_query(const char *type, const char *name, size_t namelen, extern 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);
#endif /* _LINUX_DNS_RESOLVER_H */ #endif /* _LINUX_DNS_RESOLVER_H */
...@@ -305,6 +305,19 @@ do { \ ...@@ -305,6 +305,19 @@ do { \
__ret; \ __ret; \
}) })
#define __wait_var_event_interruptible(var, condition) \
___wait_var_event(var, condition, TASK_INTERRUPTIBLE, 0, 0, \
schedule())
#define wait_var_event_interruptible(var, condition) \
({ \
int __ret = 0; \
might_sleep(); \
if (!(condition)) \
__ret = __wait_var_event_interruptible(var, condition); \
__ret; \
})
/** /**
* clear_and_wake_up_bit - clear a bit and wake up anyone waiting on that bit * clear_and_wake_up_bit - clear a bit and wake up anyone waiting on that bit
* *
......
...@@ -45,6 +45,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *, ...@@ -45,6 +45,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
gfp_t, gfp_t,
rxrpc_notify_rx_t, rxrpc_notify_rx_t,
bool, bool,
bool,
unsigned int); unsigned int);
int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *, int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
struct msghdr *, size_t, struct msghdr *, size_t,
...@@ -68,5 +69,7 @@ u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *); ...@@ -68,5 +69,7 @@ u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *);
bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *, bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *,
ktime_t *); ktime_t *);
bool rxrpc_kernel_call_is_complete(struct rxrpc_call *); bool rxrpc_kernel_call_is_complete(struct rxrpc_call *);
void rxrpc_kernel_set_max_life(struct socket *, struct rxrpc_call *,
unsigned long);
#endif /* _NET_RXRPC_H */ #endif /* _NET_RXRPC_H */
...@@ -1887,7 +1887,7 @@ static int ceph_dns_resolve_name(const char *name, size_t namelen, ...@@ -1887,7 +1887,7 @@ static int ceph_dns_resolve_name(const char *name, size_t namelen,
return -EINVAL; return -EINVAL;
/* do dns_resolve upcall */ /* 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) if (ip_len > 0)
ret = ceph_pton(ip_addr, ip_len, addr, -1, NULL); ret = ceph_pton(ip_addr, ip_len, addr, -1, NULL);
else else
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
* @options: Request options (or NULL if no options) * @options: Request options (or NULL if no options)
* @_result: Where to place the returned data (or NULL) * @_result: Where to place the returned data (or NULL)
* @_expiry: Where to store the result expiry time (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 * The data will be returned in the pointer at *result, if provided, and the
* caller is responsible for freeing it. * caller is responsible for freeing it.
...@@ -69,7 +70,8 @@ ...@@ -69,7 +70,8 @@
* Returns the size of the result on success, -ve error code otherwise. * Returns the size of the result on success, -ve error code otherwise.
*/ */
int dns_query(const char *type, const char *name, size_t namelen, 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 key *rkey;
struct user_key_payload *upayload; struct user_key_payload *upayload;
...@@ -157,6 +159,8 @@ int dns_query(const char *type, const char *name, size_t namelen, ...@@ -157,6 +159,8 @@ int dns_query(const char *type, const char *name, size_t namelen,
ret = len; ret = len;
put: put:
up_read(&rkey->sem); up_read(&rkey->sem);
if (invalidate)
key_invalidate(rkey);
key_put(rkey); key_put(rkey);
out: out:
kleave(" = %d", ret); kleave(" = %d", ret);
......
...@@ -270,6 +270,7 @@ static int rxrpc_listen(struct socket *sock, int backlog) ...@@ -270,6 +270,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
* @gfp: The allocation constraints * @gfp: The allocation constraints
* @notify_rx: Where to send notifications instead of socket queue * @notify_rx: Where to send notifications instead of socket queue
* @upgrade: Request service upgrade for call * @upgrade: Request service upgrade for call
* @intr: The call is interruptible
* @debug_id: The debug ID for tracing to be assigned to the call * @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 * 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, ...@@ -287,6 +288,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
gfp_t gfp, gfp_t gfp,
rxrpc_notify_rx_t notify_rx, rxrpc_notify_rx_t notify_rx,
bool upgrade, bool upgrade,
bool intr,
unsigned int debug_id) unsigned int debug_id)
{ {
struct rxrpc_conn_parameters cp; struct rxrpc_conn_parameters cp;
...@@ -311,6 +313,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, ...@@ -311,6 +313,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
memset(&p, 0, sizeof(p)); memset(&p, 0, sizeof(p));
p.user_call_ID = user_call_ID; p.user_call_ID = user_call_ID;
p.tx_total_len = tx_total_len; p.tx_total_len = tx_total_len;
p.intr = intr;
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
cp.local = rx->local; cp.local = rx->local;
...@@ -443,6 +446,31 @@ void rxrpc_kernel_new_call_notification( ...@@ -443,6 +446,31 @@ void rxrpc_kernel_new_call_notification(
} }
EXPORT_SYMBOL(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 * connect an RxRPC socket
* - this just targets it at a specific destination; no actual connection * - this just targets it at a specific destination; no actual connection
......
...@@ -482,6 +482,7 @@ enum rxrpc_call_flag { ...@@ -482,6 +482,7 @@ enum rxrpc_call_flag {
RXRPC_CALL_BEGAN_RX_TIMER, /* We began the expect_rx_by timer */ 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_HEARD, /* The peer responded at least once to this call */
RXRPC_CALL_RX_UNDERRUN, /* Got data underrun */ RXRPC_CALL_RX_UNDERRUN, /* Got data underrun */
RXRPC_CALL_IS_INTR, /* The call is interruptible */
}; };
/* /*
...@@ -711,6 +712,7 @@ struct rxrpc_call_params { ...@@ -711,6 +712,7 @@ struct rxrpc_call_params {
u32 normal; /* Max time since last call packet (msec) */ u32 normal; /* Max time since last call packet (msec) */
} timeouts; } timeouts;
u8 nr_timeouts; /* Number of timeouts specified */ u8 nr_timeouts; /* Number of timeouts specified */
bool intr; /* The call is interruptible */
}; };
struct rxrpc_send_params { struct rxrpc_send_params {
......
...@@ -241,6 +241,8 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, ...@@ -241,6 +241,8 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
return call; return call;
} }
if (p->intr)
__set_bit(RXRPC_CALL_IS_INTR, &call->flags);
call->tx_total_len = p->tx_total_len; call->tx_total_len = p->tx_total_len;
trace_rxrpc_call(call, rxrpc_call_new_client, atomic_read(&call->usage), trace_rxrpc_call(call, rxrpc_call_new_client, atomic_read(&call->usage),
here, (const void *)p->user_call_ID); here, (const void *)p->user_call_ID);
......
...@@ -656,10 +656,14 @@ static int rxrpc_wait_for_channel(struct rxrpc_call *call, gfp_t gfp) ...@@ -656,10 +656,14 @@ static int rxrpc_wait_for_channel(struct rxrpc_call *call, gfp_t gfp)
add_wait_queue_exclusive(&call->waitq, &myself); add_wait_queue_exclusive(&call->waitq, &myself);
for (;;) { 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) if (call->call_id)
break; break;
if (signal_pending(current)) { if (test_bit(RXRPC_CALL_IS_INTR, &call->flags) &&
signal_pending(current)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
break; break;
} }
......
...@@ -80,7 +80,8 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx, ...@@ -80,7 +80,8 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
if (call->state >= RXRPC_CALL_COMPLETE) if (call->state >= RXRPC_CALL_COMPLETE)
return call->error; return call->error;
if (timeout == 0 && if (test_bit(RXRPC_CALL_IS_INTR, &call->flags) &&
timeout == 0 &&
tx_win == tx_start && signal_pending(current)) tx_win == tx_start && signal_pending(current))
return -EINTR; return -EINTR;
...@@ -620,6 +621,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) ...@@ -620,6 +621,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
.call.tx_total_len = -1, .call.tx_total_len = -1,
.call.user_call_ID = 0, .call.user_call_ID = 0,
.call.nr_timeouts = 0, .call.nr_timeouts = 0,
.call.intr = true,
.abort_code = 0, .abort_code = 0,
.command = RXRPC_CMD_SEND_DATA, .command = RXRPC_CMD_SEND_DATA,
.exclusive = false, .exclusive = false,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment