Loading fs/afs/addr_list.c +15 −10 Original line number Original line Diff line number Diff line Loading @@ -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++; Loading @@ -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 == '+') { Loading fs/afs/callback.c +61 −23 Original line number Original line Diff line number Diff line Loading @@ -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; } } } } Loading @@ -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); Loading @@ -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; } } Loading Loading @@ -171,15 +196,26 @@ static void afs_break_one_callback(struct afs_server *server, if (cbi->vid != fid->vid) if (cbi->vid != fid->vid) continue; continue; if (fid->vnode == 0 && fid->unique == 0) { /* The callback break applies to an entire volume. */ struct afs_super_info *as = AFS_FS_S(cbi->sb); struct afs_volume *volume = as->volume; write_lock(&volume->cb_break_lock); volume->cb_v_break++; write_unlock(&volume->cb_break_lock); } else { data.volume = NULL; data.volume = NULL; data.fid = *fid; data.fid = *fid; inode = ilookup5_nowait(cbi->sb, fid->vnode, afs_iget5_test, &data); inode = ilookup5_nowait(cbi->sb, fid->vnode, afs_iget5_test, &data); if (inode) { if (inode) { vnode = AFS_FS_I(inode); vnode = AFS_FS_I(inode); afs_break_callback(vnode); afs_break_callback(vnode); iput(inode); iput(inode); } } } } } read_unlock(&server->cb_break_lock); read_unlock(&server->cb_break_lock); } } Loading @@ -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, Loading fs/afs/cmservice.c +21 −46 Original line number Original line Diff line number Diff line Loading @@ -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; } } Loading @@ -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(""); } } Loading @@ -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; Loading Loading @@ -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; } } Loading @@ -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); } } Loading @@ -303,6 +281,7 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) _enter("{%p}", call->cm_server); _enter("{%p}", call->cm_server); if (call->cm_server) afs_init_callback_state(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); Loading @@ -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(""); Loading @@ -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); } } Loading @@ -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; Loading Loading @@ -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); } } Loading fs/afs/dir.c +26 −28 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; for (i = 0; i < req->nr_pages; i++) if (down_read_killable(&dvnode->validate_lock) < 0) if (lock_page_killable(req->pages[i]) < 0) goto error; 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); Loading @@ -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; } } Loading Loading @@ -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; Loading Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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); Loading Loading @@ -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); Loading fs/afs/file.c +1 −1 Original line number Original line Diff line number Diff line Loading @@ -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); } } Loading Loading
fs/afs/addr_list.c +15 −10 Original line number Original line Diff line number Diff line Loading @@ -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++; Loading @@ -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 == '+') { Loading
fs/afs/callback.c +61 −23 Original line number Original line Diff line number Diff line Loading @@ -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; } } } } Loading @@ -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); Loading @@ -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; } } Loading Loading @@ -171,15 +196,26 @@ static void afs_break_one_callback(struct afs_server *server, if (cbi->vid != fid->vid) if (cbi->vid != fid->vid) continue; continue; if (fid->vnode == 0 && fid->unique == 0) { /* The callback break applies to an entire volume. */ struct afs_super_info *as = AFS_FS_S(cbi->sb); struct afs_volume *volume = as->volume; write_lock(&volume->cb_break_lock); volume->cb_v_break++; write_unlock(&volume->cb_break_lock); } else { data.volume = NULL; data.volume = NULL; data.fid = *fid; data.fid = *fid; inode = ilookup5_nowait(cbi->sb, fid->vnode, afs_iget5_test, &data); inode = ilookup5_nowait(cbi->sb, fid->vnode, afs_iget5_test, &data); if (inode) { if (inode) { vnode = AFS_FS_I(inode); vnode = AFS_FS_I(inode); afs_break_callback(vnode); afs_break_callback(vnode); iput(inode); iput(inode); } } } } } read_unlock(&server->cb_break_lock); read_unlock(&server->cb_break_lock); } } Loading @@ -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, Loading
fs/afs/cmservice.c +21 −46 Original line number Original line Diff line number Diff line Loading @@ -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; } } Loading @@ -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(""); } } Loading @@ -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; Loading Loading @@ -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; } } Loading @@ -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); } } Loading @@ -303,6 +281,7 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) _enter("{%p}", call->cm_server); _enter("{%p}", call->cm_server); if (call->cm_server) afs_init_callback_state(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); Loading @@ -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(""); Loading @@ -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); } } Loading @@ -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; Loading Loading @@ -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); } } Loading
fs/afs/dir.c +26 −28 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; for (i = 0; i < req->nr_pages; i++) if (down_read_killable(&dvnode->validate_lock) < 0) if (lock_page_killable(req->pages[i]) < 0) goto error; 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); Loading @@ -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; } } Loading Loading @@ -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; Loading Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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); } } Loading Loading @@ -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); Loading Loading @@ -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); Loading
fs/afs/file.c +1 −1 Original line number Original line Diff line number Diff line Loading @@ -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); } } Loading