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:
s64 tx_total_len,
gfp_t gfp,
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
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:
the server upgrade the service to a better one. The resultant service ID
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
returned. The caller now holds a reference on this and it must be
properly ended.
......@@ -1056,6 +1065,16 @@ The kernel interface functions are as follows:
This value can be used to determine if the remote client has been
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
......
......@@ -251,7 +251,7 @@ struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry
_enter("%s", cell->name);
ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1",
&result, _expiry);
&result, _expiry, true);
if (ret < 0) {
_leave(" = %d [dns]", ret);
return ERR_PTR(ret);
......
......@@ -23,6 +23,9 @@
#define AFSPATHMAX 1024 /* Maximum length of a pathname plus NUL */
#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_vnodeid_t;
typedef u64 afs_dataversion_t;
......
......@@ -218,14 +218,8 @@ void __afs_break_callback(struct afs_vnode *vnode)
vnode->cb_break++;
afs_clear_permits(vnode);
spin_lock(&vnode->lock);
_debug("break callback");
if (list_empty(&vnode->granted_locks) &&
!list_empty(&vnode->pending_locks))
if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB)
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,
const char *name, unsigned int namelen,
const char *addresses)
{
struct afs_vlserver_list *vllist;
struct afs_cell *cell;
int i, ret;
......@@ -151,18 +152,14 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
atomic_set(&cell->usage, 2);
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);
rwlock_init(&cell->proc_lock);
rwlock_init(&cell->vl_servers_lock);
/* Fill in the VL server list if we were given a list of addresses to
* use.
/* Provide a VL server list, filling it in if we were given a list of
* addresses to use.
*/
if (addresses) {
struct afs_vlserver_list *vllist;
vllist = afs_parse_text_addrs(net,
addresses, strlen(addresses), ':',
VL_SERVICE, AFS_VL_PORT);
......@@ -171,19 +168,32 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
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;
__clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags);
} 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();
}
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);
return cell;
parse_failed:
if (ret == -EINVAL)
printk(KERN_ERR "kAFS: bad VL server IP address\n");
error:
kfree(cell);
_leave(" = %d", ret);
return ERR_PTR(ret);
......@@ -208,6 +218,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
{
struct afs_cell *cell, *candidate, *cursor;
struct rb_node *parent, **pp;
enum afs_cell_state state;
int ret, n;
_enter("%s,%s", name, vllist);
......@@ -267,18 +278,16 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
wait_for_cell:
_debug("wait_for_cell");
ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NOT_READY, TASK_INTERRUPTIBLE);
smp_rmb();
switch (READ_ONCE(cell->state)) {
case AFS_CELL_FAILED:
wait_var_event(&cell->state,
({
state = smp_load_acquire(&cell->state); /* vs error */
state == AFS_CELL_ACTIVE || state == AFS_CELL_FAILED;
}));
/* Check the state obtained from the wait check. */
if (state == AFS_CELL_FAILED) {
ret = cell->error;
goto error;
default:
_debug("weird %u %d", cell->state, cell->error);
goto error;
case AFS_CELL_ACTIVE:
break;
}
_leave(" = %p [cell]", cell);
......@@ -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.
*/
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 max_ttl = READ_ONCE(afs_cell_max_ttl);
time64_t now, expiry = 0;
int ret = 0;
_enter("%s", cell->name);
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();
if (min_ttl > max_ttl)
......@@ -379,48 +418,47 @@ static void afs_update_cell(struct afs_cell *cell)
else if (expiry > now + max_ttl)
expiry = now + max_ttl;
if (IS_ERR(vllist)) {
switch (PTR_ERR(vllist)) {
case -ENODATA:
case -EDESTADDRREQ:
_debug("%s: status %d", cell->name, vllist->status);
if (vllist->source == DNS_RECORD_UNAVAILABLE) {
switch (vllist->status) {
case DNS_LOOKUP_GOT_NOT_FOUND:
/* The DNS said that the cell does not exist or there
* 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;
break;
case -EAGAIN:
case -ECONNREFUSED:
case DNS_LOOKUP_BAD:
case DNS_LOOKUP_GOT_LOCAL_FAILURE:
case DNS_LOOKUP_GOT_TEMP_FAILURE:
case DNS_LOOKUP_GOT_NS_FAILURE:
default:
set_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
cell->dns_expiry = now + 10;
break;
}
cell->error = -EDESTADDRREQ;
} else {
clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
clear_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
cell->dns_expiry = expiry;
}
/* Exclusion on changing vl_addrs is achieved by a
* non-reentrant work item.
/* Replace the VL server list if the new record has servers or the old
* record doesn't.
*/
old = rcu_dereference_protected(cell->vl_servers, true);
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_expiry = expiry;
if (old)
afs_put_vlserverlist(cell->net, old);
cell->dns_source = vllist->source;
old = p;
}
write_unlock(&cell->vl_servers_lock);
afs_put_vlserverlist(cell->net, old);
if (test_and_clear_bit(AFS_CELL_FL_NO_LOOKUP_YET, &cell->flags))
wake_up_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET);
now = ktime_get_real_seconds();
afs_set_cell_timer(cell->net, cell->dns_expiry - now);
_leave("");
out_wake:
smp_store_release(&cell->dns_lookup_count,
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)
now = ktime_get_real_seconds();
cell->last_inactive = now;
expire_delay = 0;
if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) &&
!test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags))
if (cell->vl_servers->nr_servers)
expire_delay = afs_cell_gc_delay;
if (atomic_dec_return(&cell->usage) > 1)
......@@ -623,11 +660,13 @@ static void afs_manage_cell(struct work_struct *work)
goto final_destruction;
if (cell->state == AFS_CELL_FAILED)
goto done;
cell->state = AFS_CELL_UNSET;
smp_store_release(&cell->state, AFS_CELL_UNSET);
wake_up_var(&cell->state);
goto again;
case AFS_CELL_UNSET:
cell->state = AFS_CELL_ACTIVATING;
smp_store_release(&cell->state, AFS_CELL_ACTIVATING);
wake_up_var(&cell->state);
goto again;
case AFS_CELL_ACTIVATING:
......@@ -635,28 +674,29 @@ static void afs_manage_cell(struct work_struct *work)
if (ret < 0)
goto activation_failed;
cell->state = AFS_CELL_ACTIVE;
smp_wmb();
clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
smp_store_release(&cell->state, AFS_CELL_ACTIVE);
wake_up_var(&cell->state);
goto again;
case AFS_CELL_ACTIVE:
if (atomic_read(&cell->usage) > 1) {
time64_t now = ktime_get_real_seconds();
if (cell->dns_expiry <= now && net->live)
afs_update_cell(cell);
if (test_and_clear_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) {
ret = afs_update_cell(cell);
if (ret < 0)
cell->error = ret;
}
goto done;
}
cell->state = AFS_CELL_DEACTIVATING;
smp_store_release(&cell->state, AFS_CELL_DEACTIVATING);
wake_up_var(&cell->state);
goto again;
case AFS_CELL_DEACTIVATING:
set_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
if (atomic_read(&cell->usage) > 1)
goto reverse_deactivation;
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;
default:
......@@ -669,17 +709,13 @@ static void afs_manage_cell(struct work_struct *work)
cell->error = ret;
afs_deactivate_cell(net, cell);
cell->state = AFS_CELL_FAILED;
smp_wmb();
if (test_and_clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags))
wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
smp_store_release(&cell->state, AFS_CELL_FAILED); /* vs error */
wake_up_var(&cell->state);
goto again;
reverse_deactivation:
cell->state = AFS_CELL_ACTIVE;
smp_wmb();
clear_bit(AFS_CELL_FL_NOT_READY, &cell->flags);
wake_up_bit(&cell->flags, AFS_CELL_FL_NOT_READY);
smp_store_release(&cell->state, AFS_CELL_ACTIVE);
wake_up_var(&cell->state);
_leave(" [deact->act]");
return;
......@@ -739,11 +775,16 @@ void afs_manage_cells(struct work_struct *work)
}
if (usage == 1) {
struct afs_vlserver_list *vllist;
time64_t expire_at = cell->last_inactive;
if (!test_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags) &&
!test_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags))
read_lock(&cell->vl_servers_lock);
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;
read_unlock(&cell->vl_servers_lock);
if (purging || expire_at <= now)
sched_cell = true;
else if (expire_at < next_manage)
......@@ -751,10 +792,8 @@ void afs_manage_cells(struct work_struct *work)
}
if (!purging) {
if (cell->dns_expiry <= now)
if (test_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags))
sched_cell = true;
else if (cell->dns_expiry <= next_manage)
next_manage = cell->dns_expiry;
}
if (sched_cell)
......
......@@ -704,7 +704,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
goto no_inline_bulk_status;
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)) {
if (test_bit(AFS_SERVER_FL_NO_IBULK,
&fc.cbi->server->flags)) {
......@@ -739,7 +739,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
*/
cookie->nr_fids = 1;
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)) {
afs_fs_fetch_status(&fc,
afs_v2net(dvnode),
......@@ -1166,7 +1166,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
}
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode);
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)
}
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_remove(&fc, vnode, dentry->d_name.name, true,
......@@ -1374,7 +1374,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
spin_unlock(&dentry->d_lock);
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) {
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,
}
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode);
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,
}
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) {
afs_end_vnode_operation(&fc);
goto error_key;
......@@ -1584,7 +1584,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
}
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, dvnode, key)) {
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_symlink(&fc, dentry->d_name.name,
......@@ -1696,7 +1696,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
}
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 (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) {
afs_end_vnode_operation(&fc);
......
......@@ -30,7 +30,7 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode
_enter("%pd,%pd", old, new);
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)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode);
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
_enter("");
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)) {
fc.cb_break = afs_calc_vnode_cb_break(dvnode);
......
......@@ -46,7 +46,7 @@ static int afs_probe_cell_name(struct dentry *dentry)
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)
ret = -EDESTADDRREQ;
return ret;
......@@ -261,8 +261,7 @@ int afs_dynroot_populate(struct super_block *sb)
struct afs_net *net = afs_sb2net(sb);
int ret;
if (mutex_lock_interruptible(&net->proc_cells_lock) < 0)
return -ERESTARTSYS;
mutex_lock(&net->proc_cells_lock);
net->dynroot_sb = sb;
hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
......
......@@ -170,11 +170,12 @@ int afs_release(struct inode *inode, struct file *file)
{
struct afs_vnode *vnode = AFS_FS_I(inode);
struct afs_file *af = file->private_data;
int ret = 0;
_enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode);
if ((file->f_mode & FMODE_WRITE))
return vfs_fsync(file, 0);
ret = vfs_fsync(file, 0);
file->private_data = NULL;
if (af->wb)
......@@ -182,8 +183,8 @@ int afs_release(struct inode *inode, struct file *file)
key_put(af->key);
kfree(af);
afs_prune_wb_keys(vnode);
_leave(" = 0");
return 0;
_leave(" = %d", ret);
return ret;
}
/*
......@@ -237,7 +238,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
key_serial(key));
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) {
if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_fetch_data(&fc, desc);
......
......@@ -41,9 +41,6 @@ void afs_lock_may_be_available(struct afs_vnode *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);
if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB)
afs_next_locker(vnode, 0);
......@@ -196,7 +193,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
key_serial(key), type);
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) {
if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_set_lock(&fc, type);
......@@ -227,7 +224,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key)
key_serial(key));
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)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_extend_lock(&fc);
......@@ -258,7 +255,7 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key)
key_serial(key));
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)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_release_lock(&fc);
......
......@@ -256,6 +256,23 @@ static int afs_decode_status(struct afs_call *call,
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
*/
......@@ -264,46 +281,26 @@ static void xdr_decode_AFSCallBack(struct afs_call *call,
const __be32 **_bp)
{
struct afs_cb_interest *old, *cbi = call->cbi;
const __be32 *bp = *_bp;
u32 cb_expiry;
struct afs_callback cb;
xdr_decode_AFSCallBack_raw(call, &cb, _bp);
write_seqlock(&vnode->cb_lock);
if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) {
vnode->cb_version = ntohl(*bp++);
cb_expiry = ntohl(*bp++);
vnode->cb_type = ntohl(*bp++);
vnode->cb_expires_at = cb_expiry + ktime_get_real_seconds();
vnode->cb_version = cb.version;
vnode->cb_type = cb.type;
vnode->cb_expires_at = cb.expires_at;
old = vnode->cb_interest;
if (old != call->cbi) {
vnode->cb_interest = cbi;
cbi = old;
}
set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
} else {
bp += 3;
}
write_sequnlock(&vnode->cb_lock);
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
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
&call->expected_version, NULL);
if (ret < 0)
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]); */
_leave(" = 0 [done]");
......@@ -833,6 +833,7 @@ int afs_fs_create(struct afs_fs_cursor *fc,
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call1(call, &vnode->fid, name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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,
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call1(call, &dvnode->fid, name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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,
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call1(call, &vnode->fid, name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac);
}
......@@ -1138,6 +1141,7 @@ int afs_fs_symlink(struct afs_fs_cursor *fc,
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call1(call, &vnode->fid, name);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac);
}
......@@ -1257,6 +1261,7 @@ int afs_fs_rename(struct afs_fs_cursor *fc,
afs_use_fs_server(call, fc->cbi);
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);
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,
*bp++ = htonl((u32) i_size);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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,
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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,
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_calli(call, &vnode->fid, type);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac);
}
......@@ -1942,6 +1954,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc)
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
return afs_wait_for_call_to_complete(call, &fc->ac);
}
......@@ -1977,6 +1990,7 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc)
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &vnode->fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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,
call->upgrade = true;
call->want_reply_time = true;
call->async = true;
call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
/* marshall the parameters */
bp = call->request;
......@@ -2150,7 +2165,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call)
&call->expected_version, NULL);
if (ret < 0)
return ret;
xdr_decode_AFSCallBack_raw(call, &bp, callback);
xdr_decode_AFSCallBack_raw(call, callback, &bp);
xdr_decode_AFSVolSync(&bp, volsync);
_leave(" = 0 [done]");
......@@ -2210,6 +2225,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc,
call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, fid);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
_debug("unmarshall CB array");
bp = call->buffer;
callbacks = call->reply[2];
callbacks[call->count].version = ntohl(bp[0]);
callbacks[call->count].expires_at = xdr_decode_expiry(call, ntohl(bp[1]));
callbacks[call->count].type = ntohl(bp[2]);
xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp);
statuses = call->reply[1];
if (call->count == 0 && vnode && statuses[0].abort_code == 0)
xdr_decode_AFSCallBack(call, vnode, &bp);
......@@ -2396,6 +2410,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &fids[0]);
afs_set_fc_call(call, fc);
afs_make_call(&fc->ac, call, GFP_NOFS);
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)
vnode->flags);
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) {
if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_fetch_file_status(&fc, NULL, new_inode);
......@@ -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_v_break = vnode->volume->cb_v_break;
valid = false;
} else if (vnode->status.type == AFS_FTYPE_DIR &&
(!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) ||
vnode->cb_expires_at - 10 <= now)) {
} else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
valid = false;
} else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) ||
vnode->cb_expires_at - 10 <= now) {
} else if (vnode->cb_expires_at - 10 <= now) {
valid = false;
} else {
valid = true;
......@@ -573,6 +570,7 @@ void afs_evict_inode(struct inode *inode)
}
#endif
afs_prune_wb_keys(vnode);
afs_put_permits(rcu_access_pointer(vnode->permit_cache));
key_put(vnode->silly_key);
vnode->silly_key = NULL;
......@@ -616,7 +614,7 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
}
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) {
if (afs_begin_vnode_operation(&fc, vnode, key, false)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_setattr(&fc, attr);
......
......@@ -131,6 +131,7 @@ struct afs_call {
int error; /* error code */
u32 abort_code; /* Remote abort ID or 0 */
u32 epoch;
unsigned int max_lifespan; /* Maximum lifespan to set if not 0 */
unsigned request_size; /* size of request data */
unsigned reply_max; /* maximum size of reply */
unsigned first_offset; /* offset into mapping[first] */
......@@ -148,6 +149,7 @@ struct afs_call {
bool ret_reply0; /* T if should return reply[0] on success */
bool upgrade; /* T to request service upgrade */
bool want_reply_time; /* T if want reply_time */
bool intr; /* T if interruptible */
u16 service_id; /* Actual service ID (after upgrade) */
unsigned int debug_id; /* Trace ID */
u32 operation_ID; /* operation ID for an incoming call */
......@@ -367,13 +369,13 @@ struct afs_cell {
time64_t last_inactive; /* Time of last drop of usage count */
atomic_t usage;
unsigned long flags;
#define AFS_CELL_FL_NOT_READY 0 /* The cell record is not ready for use */
#define AFS_CELL_FL_NO_GC 1 /* The cell was added manually, don't auto-gc */
#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 */
#define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */
#define AFS_CELL_FL_DO_LOOKUP 1 /* DNS lookup requested */
enum afs_cell_state state;
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. */
struct list_head proc_volumes; /* procfs volume list */
......@@ -772,6 +774,7 @@ struct afs_fs_cursor {
#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_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 */
};
......@@ -1096,7 +1099,7 @@ static inline void afs_put_sysnames(struct afs_sysnames *sysnames) {}
* rotate.c
*/
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_current_fileserver(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);
extern int afs_extract_data(struct afs_call *, bool);
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)
{
call->kvec[0].iov_base = buf;
......@@ -1382,7 +1390,7 @@ 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 *);
/*
......
......@@ -53,7 +53,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
seq_printf(m, "%3u %6lld %2u %s\n",
atomic_read(&cell->usage),
cell->dns_expiry - ktime_get_real_seconds(),
vllist ? vllist->nr_servers : 0,
vllist->nr_servers,
cell->name);
return 0;
}
......@@ -296,8 +296,8 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
if (v == SEQ_START_TOKEN) {
seq_printf(m, "# source %s, status %s\n",
dns_record_sources[vllist->source],
dns_lookup_statuses[vllist->status]);
dns_record_sources[vllist ? vllist->source : 0],
dns_lookup_statuses[vllist ? vllist->status : 0]);
return 0;
}
......@@ -336,7 +336,7 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
if (pos == 0)
return SEQ_START_TOKEN;
if (!vllist || pos - 1 >= vllist->nr_servers)
if (pos - 1 >= vllist->nr_servers)
return NULL;
return &vllist->servers[pos - 1];
......
......@@ -25,7 +25,7 @@
* them here also using the io_lock.
*/
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));
fc->vnode = vnode;
......@@ -33,11 +33,16 @@ bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode
fc->ac.error = SHRT_MAX;
fc->error = -EDESTADDRREQ;
if (intr) {
fc->flags |= AFS_FS_CURSOR_INTR;
if (mutex_lock_interruptible(&vnode->io_lock) < 0) {
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)
fc->flags |= AFS_FS_CURSOR_CUR_ONLY;
......@@ -118,11 +123,15 @@ static void afs_busy(struct afs_volume *volume, u32 abort_code)
*/
static bool afs_sleep_and_retry(struct afs_fs_cursor *fc)
{
if (fc->flags & AFS_FS_CURSOR_INTR) {
msleep_interruptible(1000);
if (signal_pending(current)) {
fc->error = -ERESTARTSYS;
return false;
}
} else {
msleep(1000);
}
return true;
}
......@@ -459,6 +468,8 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
s->probe.abort_code);
}
error = e.error;
failed_set_error:
fc->error = error;
failed:
......
......@@ -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_call_waiter),
call->upgrade,
call->intr,
call->debug_id);
if (IS_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)
call->rxcall = rxcall;
if (call->max_lifespan)
rxrpc_kernel_set_max_life(call->net->socket, rxcall,
call->max_lifespan);
/* send the request */
iov[0].iov_base = call->request;
iov[0].iov_len = call->request_size;
......@@ -648,7 +653,7 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
break;
}
if (timeout == 0 &&
if (call->intr && timeout == 0 &&
life == last_life && signal_pending(current)) {
if (stalled)
break;
......
......@@ -87,10 +87,8 @@ void afs_clear_permits(struct afs_vnode *vnode)
permits = rcu_dereference_protected(vnode->permit_cache,
lockdep_is_held(&vnode->lock));
RCU_INIT_POINTER(vnode->permit_cache, NULL);
vnode->cb_break++;
spin_unlock(&vnode->lock);
if (permits)
afs_put_permits(permits);
}
......
......@@ -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,
&server->uuid);
if (IS_ERR(alist)) {
fc->ac.error = PTR_ERR(alist);
_leave(" = f [%d]", fc->ac.error);
if ((PTR_ERR(alist) == -ERESTARTSYS ||
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;
}
......@@ -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,
TASK_INTERRUPTIBLE);
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]");
return false;
}
......
......@@ -741,7 +741,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
return PTR_ERR(key);
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;
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
......
......@@ -232,9 +232,8 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
if (bs.status > NR__dns_lookup_status)
bs.status = NR__dns_lookup_status;
server = NULL;
if (previous) {
/* See if we can update an old server record */
server = NULL;
for (i = 0; i < previous->nr_servers; i++) {
struct afs_vlserver *p = previous->servers[i].server;
......@@ -245,7 +244,6 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
break;
}
}
}
if (!server) {
ret = -ENOMEM;
......
......@@ -43,19 +43,37 @@ 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)
{
struct afs_cell *cell = vc->cell;
if (wait_on_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET,
TASK_INTERRUPTIBLE)) {
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;
}
}
/* Status load is ordered after lookup counter load */
if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
vc->error = -EDESTADDRREQ;
return false;
}
}
read_lock(&cell->vl_servers_lock);
vc->server_list = afs_get_vlserverlist(
rcu_dereference_protected(cell->vl_servers,
lockdep_is_held(&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;
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,
call->key = vc->key;
call->reply[0] = entry;
call->ret_reply0 = true;
call->max_lifespan = AFS_VL_MAX_LIFESPAN;
/* Marshall the parameters */
bp = call->request;
......@@ -289,6 +290,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
call->key = vc->key;
call->reply[0] = NULL;
call->ret_reply0 = true;
call->max_lifespan = AFS_VL_MAX_LIFESPAN;
/* Marshall the parameters */
bp = call->request;
......@@ -403,6 +405,7 @@ struct afs_call *afs_vl_get_capabilities(struct afs_net *net,
call->upgrade = true;
call->want_reply_time = true;
call->async = true;
call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
/* marshall the parameters */
bp = call->request;
......@@ -646,6 +649,7 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
call->key = vc->key;
call->reply[0] = NULL;
call->ret_reply0 = true;
call->max_lifespan = AFS_VL_MAX_LIFESPAN;
/* Marshall the parameters */
bp = call->request;
......
......@@ -361,7 +361,7 @@ static int afs_store_data(struct address_space *mapping,
_debug("USE WB KEY %u", key_serial(wbk->key));
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)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
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,
return PTR_ERR(key);
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) {
if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
acl = afs_fs_fetch_acl(&fc);
......@@ -71,11 +71,10 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler,
if (ret == 0) {
ret = acl->size;
if (size > 0) {
ret = -ERANGE;
if (acl->size > size)
return -ERANGE;
if (acl->size <= size)
memcpy(buffer, acl->data, acl->size);
ret = acl->size;
else
ret = -ERANGE;
}
kfree(acl);
}
......@@ -115,7 +114,7 @@ static int afs_xattr_set_acl(const struct xattr_handler *handler,
memcpy(acl->data, buffer, size);
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) {
if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_store_acl(&fc, acl);
......@@ -149,9 +148,8 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
struct afs_vnode *vnode = AFS_FS_I(inode);
struct yfs_acl *yacl = NULL;
struct key *key;
unsigned int flags = 0;
char buf[16], *data;
int which = 0, dsize, ret;
int which = 0, dsize, ret = -ENOMEM;
if (strcmp(name, "acl") == 0)
which = 0;
......@@ -164,20 +162,26 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
else
return -EOPNOTSUPP;
yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
if (!yacl)
goto error;
if (which == 0)
flags |= YFS_ACL_WANT_ACL;
yacl->flags |= YFS_ACL_WANT_ACL;
else if (which == 3)
flags |= YFS_ACL_WANT_VOL_ACL;
yacl->flags |= YFS_ACL_WANT_VOL_ACL;
key = afs_request_key(vnode->volume->cell);
if (IS_ERR(key))
return PTR_ERR(key);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error_yacl;
}
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) {
if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) {
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);
......@@ -185,7 +189,9 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
ret = afs_end_vnode_operation(&fc);
}
if (ret == 0) {
if (ret < 0)
goto error_key;
switch (which) {
case 0:
data = yacl->acl->data;
......@@ -193,13 +199,11 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
break;
case 1:
data = buf;
dsize = snprintf(buf, sizeof(buf), "%u",
yacl->inherit_flag);
dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
break;
case 2:
data = buf;
dsize = snprintf(buf, sizeof(buf), "%u",
yacl->num_cleaned);
dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
break;
case 3:
data = yacl->vol_acl->data;
......@@ -207,22 +211,23 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
break;
default:
ret = -EOPNOTSUPP;
goto out;
goto error_key;
}
ret = dsize;
if (size > 0) {
if (dsize > size) {
ret = -ERANGE;
goto out;
goto error_key;
}
memcpy(buffer, data, dsize);
}
}
out:
yfs_free_opaque_acl(yacl);
error_key:
key_put(key);
error_yacl:
yfs_free_opaque_acl(yacl);
error:
return ret;
}
......@@ -258,7 +263,7 @@ static int afs_xattr_set_yfs(const struct xattr_handler *handler,
memcpy(acl->data, buffer, size);
ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) {
if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = afs_calc_vnode_cb_break(vnode);
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)
goto name_is_IP_address;
/* 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)
cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
__func__, len, len, hostname);
......
......@@ -22,7 +22,7 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
char *ip_addr = NULL;
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)
ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
else
......
......@@ -27,6 +27,7 @@
#include <uapi/linux/dns_resolver.h>
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 */
......@@ -305,6 +305,19 @@ do { \
__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
*
......
......@@ -45,6 +45,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
gfp_t,
rxrpc_notify_rx_t,
bool,
bool,
unsigned int);
int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
struct msghdr *, size_t,
......@@ -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 *,
ktime_t *);
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 */
......@@ -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
......
......@@ -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);
......
......@@ -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
......
......@@ -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 {
......
......@@ -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);
......
......@@ -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 (;;) {
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;
}
......
......@@ -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,
......
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