Commit 21b9f1c7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'afs-fixes-20180514' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull AFS fixes from David Howells:
 "Here's a set of patches that fix a number of bugs in the in-kernel AFS
  client, including:

   - Fix directory locking to not use individual page locks for
     directory reading/scanning but rather to use a semaphore on the
     afs_vnode struct as the directory contents must be read in a single
     blob and data from different reads must not be mixed as the entire
     contents may be shuffled about between reads.

   - Fix address list parsing to handle port specifiers correctly.

   - Only give up callback records on a server if we actually talked to
     that server (we might not be able to access a server).

   - Fix some callback handling bugs, including refcounting,
     whole-volume callbacks and when callbacks actually get broken in
     response to a CB.CallBack op.

   - Fix some server/address rotation bugs, including giving up if we
     can't probe a server; giving up if a server says it doesn't have a
     volume, but there are more servers to try.

   - Fix the decoding of fetched statuses to be OpenAFS compatible.

   - Fix the handling of server lookups in Cache Manager ops (such as
     CB.InitCallBackState3) to use a UUID if possible and to handle no
     server being found.

   - Fix a bug in server lookup where not all addresses are compared.

   - Fix the non-encryption of calls that prevents some servers from
     being accessed (this also requires an AF_RXRPC patch that has
     already gone in through the net tree).

  There's also a patch that adds tracepoints to log Cache Manager ops
  that don't find a matching server, either by UUID or by address"

* tag 'afs-fixes-20180514' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  afs: Fix the non-encryption of calls
  afs: Fix CB.CallBack handling
  afs: Fix whole-volume callback handling
  afs: Fix afs_find_server search loop
  afs: Fix the handling of an unfound server in CM operations
  afs: Add a tracepoint to record callbacks from unlisted servers
  afs: Fix the handling of CB.InitCallBackState3 to find the server by UUID
  afs: Fix VNOVOL handling in address rotation
  afs: Fix AFSFetchStatus decoder to provide OpenAFS compatibility
  afs: Fix server rotation's handling of fileserver probe failure
  afs: Fix refcounting in callback registration
  afs: Fix giving up callbacks on server destruction
  afs: Fix address list parsing
  afs: Fix directory page locking
parents eeba2dfa 4776cab4
...@@ -121,7 +121,7 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, ...@@ -121,7 +121,7 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
p = text; p = text;
do { do {
struct sockaddr_rxrpc *srx = &alist->addrs[alist->nr_addrs]; struct sockaddr_rxrpc *srx = &alist->addrs[alist->nr_addrs];
char tdelim = delim; const char *q, *stop;
if (*p == delim) { if (*p == delim) {
p++; p++;
...@@ -130,28 +130,33 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, ...@@ -130,28 +130,33 @@ struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len,
if (*p == '[') { if (*p == '[') {
p++; p++;
tdelim = ']'; q = memchr(p, ']', end - p);
} else {
for (q = p; q < end; q++)
if (*q == '+' || *q == delim)
break;
} }
if (in4_pton(p, end - p, if (in4_pton(p, q - p,
(u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3], (u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3],
tdelim, &p)) { -1, &stop)) {
srx->transport.sin6.sin6_addr.s6_addr32[0] = 0; srx->transport.sin6.sin6_addr.s6_addr32[0] = 0;
srx->transport.sin6.sin6_addr.s6_addr32[1] = 0; srx->transport.sin6.sin6_addr.s6_addr32[1] = 0;
srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
} else if (in6_pton(p, end - p, } else if (in6_pton(p, q - p,
srx->transport.sin6.sin6_addr.s6_addr, srx->transport.sin6.sin6_addr.s6_addr,
tdelim, &p)) { -1, &stop)) {
/* Nothing to do */ /* Nothing to do */
} else { } else {
goto bad_address; goto bad_address;
} }
if (tdelim == ']') { if (stop != q)
if (p == end || *p != ']') goto bad_address;
goto bad_address;
p = q;
if (q < end && *q == ']')
p++; p++;
}
if (p < end) { if (p < end) {
if (*p == '+') { if (*p == '+') {
......
...@@ -23,36 +23,55 @@ ...@@ -23,36 +23,55 @@
/* /*
* Set up an interest-in-callbacks record for a volume on a server and * Set up an interest-in-callbacks record for a volume on a server and
* register it with the server. * register it with the server.
* - Called with volume->server_sem held. * - Called with vnode->io_lock held.
*/ */
int afs_register_server_cb_interest(struct afs_vnode *vnode, int afs_register_server_cb_interest(struct afs_vnode *vnode,
struct afs_server_entry *entry) struct afs_server_list *slist,
unsigned int index)
{ {
struct afs_cb_interest *cbi = entry->cb_interest, *vcbi, *new, *x; struct afs_server_entry *entry = &slist->servers[index];
struct afs_cb_interest *cbi, *vcbi, *new, *old;
struct afs_server *server = entry->server; struct afs_server *server = entry->server;
again: again:
if (vnode->cb_interest &&
likely(vnode->cb_interest == entry->cb_interest))
return 0;
read_lock(&slist->lock);
cbi = afs_get_cb_interest(entry->cb_interest);
read_unlock(&slist->lock);
vcbi = vnode->cb_interest; vcbi = vnode->cb_interest;
if (vcbi) { if (vcbi) {
if (vcbi == cbi) if (vcbi == cbi) {
afs_put_cb_interest(afs_v2net(vnode), cbi);
return 0; return 0;
}
/* Use a new interest in the server list for the same server
* rather than an old one that's still attached to a vnode.
*/
if (cbi && vcbi->server == cbi->server) { if (cbi && vcbi->server == cbi->server) {
write_seqlock(&vnode->cb_lock); write_seqlock(&vnode->cb_lock);
vnode->cb_interest = afs_get_cb_interest(cbi); old = vnode->cb_interest;
vnode->cb_interest = cbi;
write_sequnlock(&vnode->cb_lock); write_sequnlock(&vnode->cb_lock);
afs_put_cb_interest(afs_v2net(vnode), cbi); afs_put_cb_interest(afs_v2net(vnode), old);
return 0; return 0;
} }
/* Re-use the one attached to the vnode. */
if (!cbi && vcbi->server == server) { if (!cbi && vcbi->server == server) {
afs_get_cb_interest(vcbi); write_lock(&slist->lock);
x = cmpxchg(&entry->cb_interest, cbi, vcbi); if (entry->cb_interest) {
if (x != cbi) { write_unlock(&slist->lock);
cbi = x; afs_put_cb_interest(afs_v2net(vnode), cbi);
afs_put_cb_interest(afs_v2net(vnode), vcbi);
goto again; goto again;
} }
entry->cb_interest = cbi;
write_unlock(&slist->lock);
return 0; return 0;
} }
} }
...@@ -72,13 +91,16 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode, ...@@ -72,13 +91,16 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode,
list_add_tail(&new->cb_link, &server->cb_interests); list_add_tail(&new->cb_link, &server->cb_interests);
write_unlock(&server->cb_break_lock); write_unlock(&server->cb_break_lock);
x = cmpxchg(&entry->cb_interest, cbi, new); write_lock(&slist->lock);
if (x == cbi) { if (!entry->cb_interest) {
entry->cb_interest = afs_get_cb_interest(new);
cbi = new; cbi = new;
new = NULL;
} else { } else {
cbi = x; cbi = afs_get_cb_interest(entry->cb_interest);
afs_put_cb_interest(afs_v2net(vnode), new);
} }
write_unlock(&slist->lock);
afs_put_cb_interest(afs_v2net(vnode), new);
} }
ASSERT(cbi); ASSERT(cbi);
...@@ -88,11 +110,14 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode, ...@@ -88,11 +110,14 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode,
*/ */
write_seqlock(&vnode->cb_lock); write_seqlock(&vnode->cb_lock);
vnode->cb_interest = afs_get_cb_interest(cbi); old = vnode->cb_interest;
vnode->cb_interest = cbi;
vnode->cb_s_break = cbi->server->cb_s_break; vnode->cb_s_break = cbi->server->cb_s_break;
vnode->cb_v_break = vnode->volume->cb_v_break;
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
write_sequnlock(&vnode->cb_lock); write_sequnlock(&vnode->cb_lock);
afs_put_cb_interest(afs_v2net(vnode), old);
return 0; return 0;
} }
...@@ -171,13 +196,24 @@ static void afs_break_one_callback(struct afs_server *server, ...@@ -171,13 +196,24 @@ static void afs_break_one_callback(struct afs_server *server,
if (cbi->vid != fid->vid) if (cbi->vid != fid->vid)
continue; continue;
data.volume = NULL; if (fid->vnode == 0 && fid->unique == 0) {
data.fid = *fid; /* The callback break applies to an entire volume. */
inode = ilookup5_nowait(cbi->sb, fid->vnode, afs_iget5_test, &data); struct afs_super_info *as = AFS_FS_S(cbi->sb);
if (inode) { struct afs_volume *volume = as->volume;
vnode = AFS_FS_I(inode);
afs_break_callback(vnode); write_lock(&volume->cb_break_lock);
iput(inode); volume->cb_v_break++;
write_unlock(&volume->cb_break_lock);
} else {
data.volume = NULL;
data.fid = *fid;
inode = ilookup5_nowait(cbi->sb, fid->vnode,
afs_iget5_test, &data);
if (inode) {
vnode = AFS_FS_I(inode);
afs_break_callback(vnode);
iput(inode);
}
} }
} }
...@@ -195,6 +231,8 @@ void afs_break_callbacks(struct afs_server *server, size_t count, ...@@ -195,6 +231,8 @@ void afs_break_callbacks(struct afs_server *server, size_t count,
ASSERT(server != NULL); ASSERT(server != NULL);
ASSERTCMP(count, <=, AFSCBMAX); ASSERTCMP(count, <=, AFSCBMAX);
/* TODO: Sort the callback break list by volume ID */
for (; count > 0; callbacks++, count--) { for (; count > 0; callbacks++, count--) {
_debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }",
callbacks->fid.vid, callbacks->fid.vid,
......
...@@ -133,21 +133,10 @@ bool afs_cm_incoming_call(struct afs_call *call) ...@@ -133,21 +133,10 @@ bool afs_cm_incoming_call(struct afs_call *call)
} }
/* /*
* clean up a cache manager call * Clean up a cache manager call.
*/ */
static void afs_cm_destructor(struct afs_call *call) static void afs_cm_destructor(struct afs_call *call)
{ {
_enter("");
/* Break the callbacks here so that we do it after the final ACK is
* received. The step number here must match the final number in
* afs_deliver_cb_callback().
*/
if (call->unmarshall == 5) {
ASSERT(call->cm_server && call->count && call->request);
afs_break_callbacks(call->cm_server, call->count, call->request);
}
kfree(call->buffer); kfree(call->buffer);
call->buffer = NULL; call->buffer = NULL;
} }
...@@ -161,14 +150,14 @@ static void SRXAFSCB_CallBack(struct work_struct *work) ...@@ -161,14 +150,14 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
_enter(""); _enter("");
/* be sure to send the reply *before* attempting to spam the AFS server /* We need to break the callbacks before sending the reply as the
* with FSFetchStatus requests on the vnodes with broken callbacks lest * server holds up change visibility till it receives our reply so as
* the AFS server get into a vicious cycle of trying to break further * to maintain cache coherency.
* callbacks because it hadn't received completion of the CBCallBack op */
* yet */ if (call->cm_server)
afs_send_empty_reply(call); afs_break_callbacks(call->cm_server, call->count, call->request);
afs_break_callbacks(call->cm_server, call->count, call->request); afs_send_empty_reply(call);
afs_put_call(call); afs_put_call(call);
_leave(""); _leave("");
} }
...@@ -180,7 +169,6 @@ static int afs_deliver_cb_callback(struct afs_call *call) ...@@ -180,7 +169,6 @@ static int afs_deliver_cb_callback(struct afs_call *call)
{ {
struct afs_callback_break *cb; struct afs_callback_break *cb;
struct sockaddr_rxrpc srx; struct sockaddr_rxrpc srx;
struct afs_server *server;
__be32 *bp; __be32 *bp;
int ret, loop; int ret, loop;
...@@ -267,15 +255,6 @@ static int afs_deliver_cb_callback(struct afs_call *call) ...@@ -267,15 +255,6 @@ static int afs_deliver_cb_callback(struct afs_call *call)
call->offset = 0; call->offset = 0;
call->unmarshall++; call->unmarshall++;
/* Record that the message was unmarshalled successfully so
* that the call destructor can know do the callback breaking
* work, even if the final ACK isn't received.
*
* If the step number changes, then afs_cm_destructor() must be
* updated also.
*/
call->unmarshall++;
case 5: case 5:
break; break;
} }
...@@ -286,10 +265,9 @@ static int afs_deliver_cb_callback(struct afs_call *call) ...@@ -286,10 +265,9 @@ static int afs_deliver_cb_callback(struct afs_call *call)
/* we'll need the file server record as that tells us which set of /* we'll need the file server record as that tells us which set of
* vnodes to operate upon */ * vnodes to operate upon */
rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx);
server = afs_find_server(call->net, &srx); call->cm_server = afs_find_server(call->net, &srx);
if (!server) if (!call->cm_server)
return -ENOTCONN; trace_afs_cm_no_server(call, &srx);
call->cm_server = server;
return afs_queue_call_work(call); return afs_queue_call_work(call);
} }
...@@ -303,7 +281,8 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) ...@@ -303,7 +281,8 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work)
_enter("{%p}", call->cm_server); _enter("{%p}", call->cm_server);
afs_init_callback_state(call->cm_server); if (call->cm_server)
afs_init_callback_state(call->cm_server);
afs_send_empty_reply(call); afs_send_empty_reply(call);
afs_put_call(call); afs_put_call(call);
_leave(""); _leave("");
...@@ -315,7 +294,6 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) ...@@ -315,7 +294,6 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work)
static int afs_deliver_cb_init_call_back_state(struct afs_call *call) static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
{ {
struct sockaddr_rxrpc srx; struct sockaddr_rxrpc srx;
struct afs_server *server;
int ret; int ret;
_enter(""); _enter("");
...@@ -328,10 +306,9 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call) ...@@ -328,10 +306,9 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
/* we'll need the file server record as that tells us which set of /* we'll need the file server record as that tells us which set of
* vnodes to operate upon */ * vnodes to operate upon */
server = afs_find_server(call->net, &srx); call->cm_server = afs_find_server(call->net, &srx);
if (!server) if (!call->cm_server)
return -ENOTCONN; trace_afs_cm_no_server(call, &srx);
call->cm_server = server;
return afs_queue_call_work(call); return afs_queue_call_work(call);
} }
...@@ -341,8 +318,6 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call) ...@@ -341,8 +318,6 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
*/ */
static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
{ {
struct sockaddr_rxrpc srx;
struct afs_server *server;
struct afs_uuid *r; struct afs_uuid *r;
unsigned loop; unsigned loop;
__be32 *b; __be32 *b;
...@@ -398,11 +373,11 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) ...@@ -398,11 +373,11 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
/* we'll need the file server record as that tells us which set of /* we'll need the file server record as that tells us which set of
* vnodes to operate upon */ * vnodes to operate upon */
rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); rcu_read_lock();
server = afs_find_server(call->net, &srx); call->cm_server = afs_find_server_by_uuid(call->net, call->request);
if (!server) rcu_read_unlock();
return -ENOTCONN; if (!call->cm_server)
call->cm_server = server; trace_afs_cm_no_server_u(call, call->request);
return afs_queue_call_work(call); return afs_queue_call_work(call);
} }
......
...@@ -180,6 +180,7 @@ static int afs_dir_open(struct inode *inode, struct file *file) ...@@ -180,6 +180,7 @@ static int afs_dir_open(struct inode *inode, struct file *file)
* get reclaimed during the iteration. * get reclaimed during the iteration.
*/ */
static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
__acquires(&dvnode->validate_lock)
{ {
struct afs_read *req; struct afs_read *req;
loff_t i_size; loff_t i_size;
...@@ -261,18 +262,21 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) ...@@ -261,18 +262,21 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
/* If we're going to reload, we need to lock all the pages to prevent /* If we're going to reload, we need to lock all the pages to prevent
* races. * races.
*/ */
if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { ret = -ERESTARTSYS;
ret = -ERESTARTSYS; if (down_read_killable(&dvnode->validate_lock) < 0)
for (i = 0; i < req->nr_pages; i++) goto error;
if (lock_page_killable(req->pages[i]) < 0)
goto error_unlock;
if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
goto success; goto success;
up_read(&dvnode->validate_lock);
if (down_write_killable(&dvnode->validate_lock) < 0)
goto error;
if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
ret = afs_fetch_data(dvnode, key, req); ret = afs_fetch_data(dvnode, key, req);
if (ret < 0) if (ret < 0)
goto error_unlock_all; goto error_unlock;
task_io_account_read(PAGE_SIZE * req->nr_pages); task_io_account_read(PAGE_SIZE * req->nr_pages);
...@@ -284,33 +288,26 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) ...@@ -284,33 +288,26 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
for (i = 0; i < req->nr_pages; i++) for (i = 0; i < req->nr_pages; i++)
if (!afs_dir_check_page(dvnode, req->pages[i], if (!afs_dir_check_page(dvnode, req->pages[i],
req->actual_len)) req->actual_len))
goto error_unlock_all; goto error_unlock;
// TODO: Trim excess pages // TODO: Trim excess pages
set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags);
} }
downgrade_write(&dvnode->validate_lock);
success: success:
i = req->nr_pages;
while (i > 0)
unlock_page(req->pages[--i]);
return req; return req;
error_unlock_all:
i = req->nr_pages;
error_unlock: error_unlock:
while (i > 0) up_write(&dvnode->validate_lock);
unlock_page(req->pages[--i]);
error: error:
afs_put_read(req); afs_put_read(req);
_leave(" = %d", ret); _leave(" = %d", ret);
return ERR_PTR(ret); return ERR_PTR(ret);
content_has_grown: content_has_grown:
i = req->nr_pages; up_write(&dvnode->validate_lock);
while (i > 0)
unlock_page(req->pages[--i]);
afs_put_read(req); afs_put_read(req);
goto retry; goto retry;
} }
...@@ -473,6 +470,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, ...@@ -473,6 +470,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
} }
out: out:
up_read(&dvnode->validate_lock);
afs_put_read(req); afs_put_read(req);
_leave(" = %d", ret); _leave(" = %d", ret);
return ret; return ret;
...@@ -1143,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -1143,7 +1141,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)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 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,
&newfid, &newstatus, &newcb); &newfid, &newstatus, &newcb);
} }
...@@ -1213,7 +1211,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1213,7 +1211,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)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_remove(&fc, dentry->d_name.name, true, afs_fs_remove(&fc, dentry->d_name.name, true,
data_version); data_version);
} }
...@@ -1316,7 +1314,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1316,7 +1314,7 @@ static int afs_unlink(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)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(dvnode);
afs_fs_remove(&fc, dentry->d_name.name, false, afs_fs_remove(&fc, dentry->d_name.name, false,
data_version); data_version);
} }
...@@ -1373,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -1373,7 +1371,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)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 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,
&newfid, &newstatus, &newcb); &newfid, &newstatus, &newcb);
} }
...@@ -1443,8 +1441,8 @@ static int afs_link(struct dentry *from, struct inode *dir, ...@@ -1443,8 +1441,8 @@ static int afs_link(struct dentry *from, struct inode *dir,
} }
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(dvnode);
fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break; fc.cb_break_2 = afs_calc_vnode_cb_break(vnode);
afs_fs_link(&fc, vnode, dentry->d_name.name, data_version); afs_fs_link(&fc, vnode, dentry->d_name.name, data_version);
} }
...@@ -1512,7 +1510,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1512,7 +1510,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)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 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,
content, data_version, content, data_version,
&newfid, &newstatus); &newfid, &newstatus);
...@@ -1588,8 +1586,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1588,8 +1586,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
} }
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(orig_dvnode);
fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break; fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode);
afs_fs_rename(&fc, old_dentry->d_name.name, afs_fs_rename(&fc, old_dentry->d_name.name,
new_dvnode, new_dentry->d_name.name, new_dvnode, new_dentry->d_name.name,
orig_data_version, new_data_version); orig_data_version, new_data_version);
......
...@@ -238,7 +238,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de ...@@ -238,7 +238,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_fetch_data(&fc, desc); afs_fs_fetch_data(&fc, desc);
} }
......
...@@ -86,7 +86,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key, ...@@ -86,7 +86,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_set_lock(&fc, type); afs_fs_set_lock(&fc, type);
} }
...@@ -117,7 +117,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key) ...@@ -117,7 +117,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key)
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key)) {
while (afs_select_current_fileserver(&fc)) { while (afs_select_current_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_extend_lock(&fc); afs_fs_extend_lock(&fc);
} }
...@@ -148,7 +148,7 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key) ...@@ -148,7 +148,7 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key)
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key)) {
while (afs_select_current_fileserver(&fc)) { while (afs_select_current_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_release_lock(&fc); afs_fs_release_lock(&fc);
} }
......
...@@ -134,6 +134,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, ...@@ -134,6 +134,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
struct afs_read *read_req) struct afs_read *read_req)
{ {
const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
u64 data_version, size; u64 data_version, size;
u32 type, abort_code; u32 type, abort_code;
u8 flags = 0; u8 flags = 0;
...@@ -142,13 +143,32 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, ...@@ -142,13 +143,32 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
if (vnode) if (vnode)
write_seqlock(&vnode->cb_lock); write_seqlock(&vnode->cb_lock);
abort_code = ntohl(xdr->abort_code);
if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
if (xdr->if_version == htonl(0) &&
abort_code != 0 &&
inline_error) {
/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
* whereby it doesn't set the interface version in the error
* case.
*/
status->abort_code = abort_code;
ret = 0;
goto out;
}
pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
goto bad; goto bad;
} }
if (abort_code != 0 && inline_error) {
status->abort_code = abort_code;
ret = 0;
goto out;
}
type = ntohl(xdr->type); type = ntohl(xdr->type);
abort_code = ntohl(xdr->abort_code);
switch (type) { switch (type) {
case AFS_FTYPE_FILE: case AFS_FTYPE_FILE:
case AFS_FTYPE_DIR: case AFS_FTYPE_DIR:
...@@ -165,13 +185,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, ...@@ -165,13 +185,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
} }
status->type = type; status->type = type;
break; break;
case AFS_FTYPE_INVALID:
if (abort_code != 0) {
status->abort_code = abort_code;
ret = 0;
goto out;
}
/* Fall through */
default: default:
goto bad; goto bad;
} }
...@@ -248,7 +261,7 @@ static void xdr_decode_AFSCallBack(struct afs_call *call, ...@@ -248,7 +261,7 @@ static void xdr_decode_AFSCallBack(struct afs_call *call,
write_seqlock(&vnode->cb_lock); write_seqlock(&vnode->cb_lock);
if (call->cb_break == (vnode->cb_break + cbi->server->cb_s_break)) { if (call->cb_break == afs_cb_break_sum(vnode, cbi)) {
vnode->cb_version = ntohl(*bp++); vnode->cb_version = ntohl(*bp++);
cb_expiry = ntohl(*bp++); cb_expiry = ntohl(*bp++);
vnode->cb_type = ntohl(*bp++); vnode->cb_type = ntohl(*bp++);
......
...@@ -108,7 +108,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode) ...@@ -108,7 +108,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break; 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);
} }
...@@ -393,15 +393,18 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) ...@@ -393,15 +393,18 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
read_seqlock_excl(&vnode->cb_lock); read_seqlock_excl(&vnode->cb_lock);
if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break ||
vnode->cb_v_break != vnode->volume->cb_v_break) {
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;
valid = false;
} else if (vnode->status.type == AFS_FTYPE_DIR && } else if (vnode->status.type == AFS_FTYPE_DIR &&
test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) && test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) &&
vnode->cb_expires_at - 10 > now) { vnode->cb_expires_at - 10 > now) {
valid = true; valid = true;
} else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && } else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
vnode->cb_expires_at - 10 > now) { vnode->cb_expires_at - 10 > now) {
valid = true; valid = true;
} }
} else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
valid = true; valid = true;
...@@ -415,7 +418,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) ...@@ -415,7 +418,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
if (valid) if (valid)
goto valid; goto valid;
mutex_lock(&vnode->validate_lock); down_write(&vnode->validate_lock);
/* if the promise has expired, we need to check the server again to get /* if the promise has expired, we need to check the server again to get
* a new promise - note that if the (parent) directory's metadata was * a new promise - note that if the (parent) directory's metadata was
...@@ -444,13 +447,13 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) ...@@ -444,13 +447,13 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
* different */ * different */
if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
afs_zap_data(vnode); afs_zap_data(vnode);
mutex_unlock(&vnode->validate_lock); up_write(&vnode->validate_lock);
valid: valid:
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
error_unlock: error_unlock:
mutex_unlock(&vnode->validate_lock); up_write(&vnode->validate_lock);
_leave(" = %d", ret); _leave(" = %d", ret);
return ret; return ret;
} }
...@@ -574,7 +577,7 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -574,7 +577,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)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_setattr(&fc, attr); afs_fs_setattr(&fc, attr);
} }
......
...@@ -396,6 +396,7 @@ struct afs_server { ...@@ -396,6 +396,7 @@ struct afs_server {
#define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */ #define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */
#define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */ #define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */
#define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */ #define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */
#define AFS_SERVER_FL_MAY_HAVE_CB 8 /* May have callbacks on this fileserver */
atomic_t usage; atomic_t usage;
u32 addr_version; /* Address list version */ u32 addr_version; /* Address list version */
...@@ -433,6 +434,7 @@ struct afs_server_list { ...@@ -433,6 +434,7 @@ struct afs_server_list {
unsigned short index; /* Server currently in use */ unsigned short index; /* Server currently in use */
unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */ unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */
unsigned int seq; /* Set to ->servers_seq when installed */ unsigned int seq; /* Set to ->servers_seq when installed */
rwlock_t lock;
struct afs_server_entry servers[]; struct afs_server_entry servers[];
}; };
...@@ -459,6 +461,9 @@ struct afs_volume { ...@@ -459,6 +461,9 @@ struct afs_volume {
rwlock_t servers_lock; /* Lock for ->servers */ rwlock_t servers_lock; /* Lock for ->servers */
unsigned int servers_seq; /* Incremented each time ->servers changes */ unsigned int servers_seq; /* Incremented each time ->servers changes */
unsigned cb_v_break; /* Break-everything counter. */
rwlock_t cb_break_lock;
afs_voltype_t type; /* type of volume */ afs_voltype_t type; /* type of volume */
short error; short error;
char type_force; /* force volume type (suppress R/O -> R/W) */ char type_force; /* force volume type (suppress R/O -> R/W) */
...@@ -494,7 +499,7 @@ struct afs_vnode { ...@@ -494,7 +499,7 @@ struct afs_vnode {
#endif #endif
struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */ struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */
struct mutex io_lock; /* Lock for serialising I/O on this mutex */ struct mutex io_lock; /* Lock for serialising I/O on this mutex */
struct mutex validate_lock; /* lock for validating this vnode */ struct rw_semaphore validate_lock; /* lock for validating this vnode */
spinlock_t wb_lock; /* lock for wb_keys */ spinlock_t wb_lock; /* lock for wb_keys */
spinlock_t lock; /* waitqueue/flags lock */ spinlock_t lock; /* waitqueue/flags lock */
unsigned long flags; unsigned long flags;
...@@ -519,6 +524,7 @@ struct afs_vnode { ...@@ -519,6 +524,7 @@ struct afs_vnode {
/* outstanding callback notification on this file */ /* outstanding callback notification on this file */
struct afs_cb_interest *cb_interest; /* Server on which this resides */ struct afs_cb_interest *cb_interest; /* Server on which this resides */
unsigned int cb_s_break; /* Mass break counter on ->server */ unsigned int cb_s_break; /* Mass break counter on ->server */
unsigned int cb_v_break; /* Mass break counter on ->volume */
unsigned int cb_break; /* Break counter on vnode */ unsigned int cb_break; /* Break counter on vnode */
seqlock_t cb_lock; /* Lock for ->cb_interest, ->status, ->cb_*break */ seqlock_t cb_lock; /* Lock for ->cb_interest, ->status, ->cb_*break */
...@@ -648,16 +654,29 @@ extern void afs_init_callback_state(struct afs_server *); ...@@ -648,16 +654,29 @@ extern void afs_init_callback_state(struct afs_server *);
extern void afs_break_callback(struct afs_vnode *); extern void afs_break_callback(struct afs_vnode *);
extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*); extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*);
extern int afs_register_server_cb_interest(struct afs_vnode *, struct afs_server_entry *); extern int afs_register_server_cb_interest(struct afs_vnode *,
struct afs_server_list *, unsigned int);
extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *); extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *);
extern void afs_clear_callback_interests(struct afs_net *, struct afs_server_list *); extern void afs_clear_callback_interests(struct afs_net *, struct afs_server_list *);
static inline struct afs_cb_interest *afs_get_cb_interest(struct afs_cb_interest *cbi) static inline struct afs_cb_interest *afs_get_cb_interest(struct afs_cb_interest *cbi)
{ {
refcount_inc(&cbi->usage); if (cbi)
refcount_inc(&cbi->usage);
return cbi; return cbi;
} }
static inline unsigned int afs_calc_vnode_cb_break(struct afs_vnode *vnode)
{
return vnode->cb_break + vnode->cb_s_break + vnode->cb_v_break;
}
static inline unsigned int afs_cb_break_sum(struct afs_vnode *vnode,
struct afs_cb_interest *cbi)
{
return vnode->cb_break + cbi->server->cb_s_break + vnode->volume->cb_v_break;
}
/* /*
* cell.c * cell.c
*/ */
......
...@@ -179,7 +179,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc) ...@@ -179,7 +179,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
*/ */
if (fc->flags & AFS_FS_CURSOR_VNOVOL) { if (fc->flags & AFS_FS_CURSOR_VNOVOL) {
fc->ac.error = -EREMOTEIO; fc->ac.error = -EREMOTEIO;
goto failed; goto next_server;
} }
write_lock(&vnode->volume->servers_lock); write_lock(&vnode->volume->servers_lock);
...@@ -201,7 +201,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc) ...@@ -201,7 +201,7 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
*/ */
if (vnode->volume->servers == fc->server_list) { if (vnode->volume->servers == fc->server_list) {
fc->ac.error = -EREMOTEIO; fc->ac.error = -EREMOTEIO;
goto failed; goto next_server;
} }
/* Try again */ /* Try again */
...@@ -350,8 +350,8 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc) ...@@ -350,8 +350,8 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
* break request before we've finished decoding the reply and * break request before we've finished decoding the reply and
* installing the vnode. * installing the vnode.
*/ */
fc->ac.error = afs_register_server_cb_interest( fc->ac.error = afs_register_server_cb_interest(vnode, fc->server_list,
vnode, &fc->server_list->servers[fc->index]); fc->index);
if (fc->ac.error < 0) if (fc->ac.error < 0)
goto failed; goto failed;
...@@ -369,8 +369,16 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc) ...@@ -369,8 +369,16 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
if (!test_bit(AFS_SERVER_FL_PROBED, &server->flags)) { if (!test_bit(AFS_SERVER_FL_PROBED, &server->flags)) {
fc->ac.alist = afs_get_addrlist(alist); fc->ac.alist = afs_get_addrlist(alist);
if (!afs_probe_fileserver(fc)) if (!afs_probe_fileserver(fc)) {
goto failed; switch (fc->ac.error) {
case -ENOMEM:
case -ERESTARTSYS:
case -EINTR:
goto failed;
default:
goto next_server;
}
}
} }
if (!fc->ac.alist) if (!fc->ac.alist)
......
...@@ -41,6 +41,7 @@ int afs_open_socket(struct afs_net *net) ...@@ -41,6 +41,7 @@ int afs_open_socket(struct afs_net *net)
{ {
struct sockaddr_rxrpc srx; struct sockaddr_rxrpc srx;
struct socket *socket; struct socket *socket;
unsigned int min_level;
int ret; int ret;
_enter(""); _enter("");
...@@ -60,6 +61,12 @@ int afs_open_socket(struct afs_net *net) ...@@ -60,6 +61,12 @@ int afs_open_socket(struct afs_net *net)
srx.transport.sin6.sin6_family = AF_INET6; srx.transport.sin6.sin6_family = AF_INET6;
srx.transport.sin6.sin6_port = htons(AFS_CM_PORT); srx.transport.sin6.sin6_port = htons(AFS_CM_PORT);
min_level = RXRPC_SECURITY_ENCRYPT;
ret = kernel_setsockopt(socket, SOL_RXRPC, RXRPC_MIN_SECURITY_LEVEL,
(void *)&min_level, sizeof(min_level));
if (ret < 0)
goto error_2;
ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
if (ret == -EADDRINUSE) { if (ret == -EADDRINUSE) {
srx.transport.sin6.sin6_port = 0; srx.transport.sin6.sin6_port = 0;
...@@ -482,8 +489,12 @@ static void afs_deliver_to_call(struct afs_call *call) ...@@ -482,8 +489,12 @@ static void afs_deliver_to_call(struct afs_call *call)
state = READ_ONCE(call->state); state = READ_ONCE(call->state);
switch (ret) { switch (ret) {
case 0: case 0:
if (state == AFS_CALL_CL_PROC_REPLY) if (state == AFS_CALL_CL_PROC_REPLY) {
if (call->cbi)
set_bit(AFS_SERVER_FL_MAY_HAVE_CB,
&call->cbi->server->flags);
goto call_complete; goto call_complete;
}
ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY); ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY);
goto done; goto done;
case -EINPROGRESS: case -EINPROGRESS:
...@@ -493,11 +504,6 @@ static void afs_deliver_to_call(struct afs_call *call) ...@@ -493,11 +504,6 @@ static void afs_deliver_to_call(struct afs_call *call)
case -ECONNABORTED: case -ECONNABORTED:
ASSERTCMP(state, ==, AFS_CALL_COMPLETE); ASSERTCMP(state, ==, AFS_CALL_COMPLETE);
goto done; goto done;
case -ENOTCONN:
abort_code = RX_CALL_DEAD;
rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
abort_code, ret, "KNC");
goto local_abort;
case -ENOTSUPP: case -ENOTSUPP:
abort_code = RXGEN_OPCODE; abort_code = RXGEN_OPCODE;
rxrpc_kernel_abort_call(call->net->socket, call->rxcall, rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
......
...@@ -147,8 +147,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, ...@@ -147,8 +147,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
break; break;
} }
if (cb_break != (vnode->cb_break + if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest)) {
vnode->cb_interest->server->cb_s_break)) {
changed = true; changed = true;
break; break;
} }
...@@ -178,7 +177,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, ...@@ -178,7 +177,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
} }
} }
if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break)) if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest))
goto someone_else_changed_it; goto someone_else_changed_it;
/* We need a ref on any permits list we want to copy as we'll have to /* We need a ref on any permits list we want to copy as we'll have to
...@@ -257,7 +256,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, ...@@ -257,7 +256,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
spin_lock(&vnode->lock); spin_lock(&vnode->lock);
zap = rcu_access_pointer(vnode->permit_cache); zap = rcu_access_pointer(vnode->permit_cache);
if (cb_break == (vnode->cb_break + vnode->cb_interest->server->cb_s_break) && if (cb_break == afs_cb_break_sum(vnode, vnode->cb_interest) &&
zap == permits) zap == permits)
rcu_assign_pointer(vnode->permit_cache, replacement); rcu_assign_pointer(vnode->permit_cache, replacement);
else else
......
...@@ -67,12 +67,6 @@ struct afs_server *afs_find_server(struct afs_net *net, ...@@ -67,12 +67,6 @@ struct afs_server *afs_find_server(struct afs_net *net,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
if (diff == 0) if (diff == 0)
goto found; goto found;
if (diff < 0) {
// TODO: Sort the list
//if (i == alist->nr_ipv4)
// goto not_found;
break;
}
} }
} }
} else { } else {
...@@ -87,17 +81,10 @@ struct afs_server *afs_find_server(struct afs_net *net, ...@@ -87,17 +81,10 @@ struct afs_server *afs_find_server(struct afs_net *net,
(u32 __force)b->sin6_addr.s6_addr32[3]); (u32 __force)b->sin6_addr.s6_addr32[3]);
if (diff == 0) if (diff == 0)
goto found; goto found;
if (diff < 0) {
// TODO: Sort the list
//if (i == 0)
// goto not_found;
break;
}
} }
} }
} }
//not_found:
server = NULL; server = NULL;
found: found:
if (server && !atomic_inc_not_zero(&server->usage)) if (server && !atomic_inc_not_zero(&server->usage))
...@@ -395,14 +382,16 @@ static void afs_destroy_server(struct afs_net *net, struct afs_server *server) ...@@ -395,14 +382,16 @@ static void afs_destroy_server(struct afs_net *net, struct afs_server *server)
struct afs_addr_list *alist = rcu_access_pointer(server->addresses); struct afs_addr_list *alist = rcu_access_pointer(server->addresses);
struct afs_addr_cursor ac = { struct afs_addr_cursor ac = {
.alist = alist, .alist = alist,
.addr = &alist->addrs[0],
.start = alist->index, .start = alist->index,
.index = alist->index, .index = 0,
.addr = &alist->addrs[alist->index],
.error = 0, .error = 0,
}; };
_enter("%p", server); _enter("%p", server);
afs_fs_give_up_all_callbacks(net, server, &ac, NULL); if (test_bit(AFS_SERVER_FL_MAY_HAVE_CB, &server->flags))
afs_fs_give_up_all_callbacks(net, server, &ac, NULL);
call_rcu(&server->rcu, afs_server_rcu); call_rcu(&server->rcu, afs_server_rcu);
afs_dec_servers_outstanding(net); afs_dec_servers_outstanding(net);
} }
......
...@@ -49,6 +49,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell, ...@@ -49,6 +49,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
goto error; goto error;
refcount_set(&slist->usage, 1); refcount_set(&slist->usage, 1);
rwlock_init(&slist->lock);
/* Make sure a records exists for each server in the list. */ /* Make sure a records exists for each server in the list. */
for (i = 0; i < vldb->nr_servers; i++) { for (i = 0; i < vldb->nr_servers; i++) {
...@@ -64,9 +65,11 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell, ...@@ -64,9 +65,11 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
goto error_2; goto error_2;
} }
/* Insertion-sort by server pointer */ /* Insertion-sort by UUID */
for (j = 0; j < slist->nr_servers; j++) for (j = 0; j < slist->nr_servers; j++)
if (slist->servers[j].server >= server) if (memcmp(&slist->servers[j].server->uuid,
&server->uuid,
sizeof(server->uuid)) >= 0)
break; break;
if (j < slist->nr_servers) { if (j < slist->nr_servers) {
if (slist->servers[j].server == server) { if (slist->servers[j].server == server) {
......
...@@ -590,7 +590,7 @@ static void afs_i_init_once(void *_vnode) ...@@ -590,7 +590,7 @@ static void afs_i_init_once(void *_vnode)
memset(vnode, 0, sizeof(*vnode)); memset(vnode, 0, sizeof(*vnode));
inode_init_once(&vnode->vfs_inode); inode_init_once(&vnode->vfs_inode);
mutex_init(&vnode->io_lock); mutex_init(&vnode->io_lock);
mutex_init(&vnode->validate_lock); init_rwsem(&vnode->validate_lock);
spin_lock_init(&vnode->wb_lock); spin_lock_init(&vnode->wb_lock);
spin_lock_init(&vnode->lock); spin_lock_init(&vnode->lock);
INIT_LIST_HEAD(&vnode->wb_keys); INIT_LIST_HEAD(&vnode->wb_keys);
...@@ -688,7 +688,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -688,7 +688,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key)) {
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 = vnode->cb_break + vnode->cb_s_break; fc.cb_break = afs_calc_vnode_cb_break(vnode);
afs_fs_get_volume_status(&fc, &vs); afs_fs_get_volume_status(&fc, &vs);
} }
......
...@@ -351,7 +351,7 @@ static int afs_store_data(struct address_space *mapping, ...@@ -351,7 +351,7 @@ static int afs_store_data(struct address_space *mapping,
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
if (afs_begin_vnode_operation(&fc, vnode, wbk->key)) { if (afs_begin_vnode_operation(&fc, vnode, wbk->key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break; 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);
} }
......
...@@ -575,6 +575,48 @@ TRACE_EVENT(afs_protocol_error, ...@@ -575,6 +575,48 @@ TRACE_EVENT(afs_protocol_error,
__entry->call, __entry->error, __entry->where) __entry->call, __entry->error, __entry->where)
); );
TRACE_EVENT(afs_cm_no_server,
TP_PROTO(struct afs_call *call, struct sockaddr_rxrpc *srx),
TP_ARGS(call, srx),
TP_STRUCT__entry(
__field(unsigned int, call )
__field(unsigned int, op_id )
__field_struct(struct sockaddr_rxrpc, srx )
),
TP_fast_assign(
__entry->call = call->debug_id;
__entry->op_id = call->operation_ID;
memcpy(&__entry->srx, srx, sizeof(__entry->srx));
),
TP_printk("c=%08x op=%u %pISpc",
__entry->call, __entry->op_id, &__entry->srx.transport)
);
TRACE_EVENT(afs_cm_no_server_u,
TP_PROTO(struct afs_call *call, const uuid_t *uuid),
TP_ARGS(call, uuid),
TP_STRUCT__entry(
__field(unsigned int, call )
__field(unsigned int, op_id )
__field_struct(uuid_t, uuid )
),
TP_fast_assign(
__entry->call = call->debug_id;
__entry->op_id = call->operation_ID;
memcpy(&__entry->uuid, uuid, sizeof(__entry->uuid));
),
TP_printk("c=%08x op=%u %pU",
__entry->call, __entry->op_id, &__entry->uuid)
);
#endif /* _TRACE_AFS_H */ #endif /* _TRACE_AFS_H */
/* This part must be outside protection */ /* This part must be outside protection */
......
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