From 196ee9cd2d04728d0ec0038a2856b86142615b11 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Jan 2017 10:38:34 +0000 Subject: afs: Make afs_fs_fetch_data() take a list of pages Make afs_fs_fetch_data() take a list of pages for bulk data transfer. This will allow afs_readpages() to be made more efficient. Signed-off-by: David Howells --- fs/afs/file.c | 37 ++++++++++++++--- fs/afs/fsclient.c | 117 +++++++++++++++++++++++++++++++++++------------------- fs/afs/internal.h | 21 +++++++++- fs/afs/vnode.c | 6 +-- fs/afs/write.c | 19 +++++++-- 5 files changed, 145 insertions(+), 55 deletions(-) (limited to 'fs') diff --git a/fs/afs/file.c b/fs/afs/file.c index 6344aee4ac4b..6c262ceef32d 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -101,6 +101,21 @@ int afs_release(struct inode *inode, struct file *file) return 0; } +/* + * Dispose of a ref to a read record. + */ +void afs_put_read(struct afs_read *req) +{ + int i; + + if (atomic_dec_and_test(&req->usage)) { + for (i = 0; i < req->nr_pages; i++) + if (req->pages[i]) + put_page(req->pages[i]); + kfree(req); + } +} + #ifdef CONFIG_AFS_FSCACHE /* * deal with notification that a page was read from the cache @@ -126,9 +141,8 @@ int afs_page_filler(void *data, struct page *page) { struct inode *inode = page->mapping->host; struct afs_vnode *vnode = AFS_FS_I(inode); + struct afs_read *req; struct key *key = data; - size_t len; - off_t offset; int ret; _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); @@ -164,12 +178,23 @@ int afs_page_filler(void *data, struct page *page) _debug("cache said ENOBUFS"); default: go_on: - offset = page->index << PAGE_SHIFT; - len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); + req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *), + GFP_KERNEL); + if (!req) + goto enomem; + + atomic_set(&req->usage, 1); + req->pos = (loff_t)page->index << PAGE_SHIFT; + req->len = min_t(size_t, i_size_read(inode) - req->pos, + PAGE_SIZE); + req->nr_pages = 1; + req->pages[0] = page; + get_page(page); /* read the contents of the file from the server into the * page */ - ret = afs_vnode_fetch_data(vnode, key, offset, len, page); + ret = afs_vnode_fetch_data(vnode, key, req); + afs_put_read(req); if (ret < 0) { if (ret == -ENOENT) { _debug("got NOENT from server" @@ -201,6 +226,8 @@ int afs_page_filler(void *data, struct page *page) _leave(" = 0"); return 0; +enomem: + ret = -ENOMEM; error: SetPageError(page); unlock_page(page); diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 31c616ab9b40..7dc1f6fb3661 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -309,15 +309,19 @@ int afs_fs_fetch_file_status(struct afs_server *server, static int afs_deliver_fs_fetch_data(struct afs_call *call) { struct afs_vnode *vnode = call->reply; + struct afs_read *req = call->reply3; const __be32 *bp; - struct page *page; + unsigned int size; void *buffer; int ret; - _enter("{%u}", call->unmarshall); + _enter("{%u,%zu/%u;%u/%llu}", + call->unmarshall, call->offset, call->count, + req->remain, req->actual_len); switch (call->unmarshall) { case 0: + req->actual_len = 0; call->offset = 0; call->unmarshall++; if (call->operation_ID != FSFETCHDATA64) { @@ -334,10 +338,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) if (ret < 0) return ret; - call->count = ntohl(call->tmp); - _debug("DATA length MSW: %u", call->count); - if (call->count > 0) - return -EBADMSG; + req->actual_len = ntohl(call->tmp); + req->actual_len <<= 32; call->offset = 0; call->unmarshall++; @@ -349,26 +351,52 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) if (ret < 0) return ret; - call->count = ntohl(call->tmp); - _debug("DATA length: %u", call->count); - if (call->count > PAGE_SIZE) + req->actual_len |= ntohl(call->tmp); + _debug("DATA length: %llu", req->actual_len); + /* Check that the server didn't want to send us extra. We + * might want to just discard instead, but that requires + * cooperation from AF_RXRPC. + */ + if (req->actual_len > req->len) return -EBADMSG; - call->offset = 0; + + req->remain = req->actual_len; + call->offset = req->pos & (PAGE_SIZE - 1); + req->index = 0; + if (req->actual_len == 0) + goto no_more_data; call->unmarshall++; + begin_page: + if (req->remain > PAGE_SIZE - call->offset) + size = PAGE_SIZE - call->offset; + else + size = req->remain; + call->count = call->offset + size; + ASSERTCMP(call->count, <=, PAGE_SIZE); + req->remain -= size; + /* extract the returned data */ case 3: - _debug("extract data"); - if (call->count > 0) { - page = call->reply3; - buffer = kmap(page); - ret = afs_extract_data(call, buffer, - call->count, true); - kunmap(page); - if (ret < 0) - return ret; + _debug("extract data %u/%llu %zu/%u", + req->remain, req->actual_len, call->offset, call->count); + + buffer = kmap(req->pages[req->index]); + ret = afs_extract_data(call, buffer, call->count, true); + kunmap(req->pages[req->index]); + if (ret < 0) + return ret; + if (call->offset == PAGE_SIZE) { + if (req->page_done) + req->page_done(call, req); + if (req->remain > 0) { + req->index++; + call->offset = 0; + goto begin_page; + } } + no_more_data: call->offset = 0; call->unmarshall++; @@ -393,17 +421,25 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) } if (call->count < PAGE_SIZE) { - _debug("clear"); - page = call->reply3; - buffer = kmap(page); + buffer = kmap(req->pages[req->index]); memset(buffer + call->count, 0, PAGE_SIZE - call->count); - kunmap(page); + kunmap(req->pages[req->index]); + if (req->page_done) + req->page_done(call, req); } _leave(" = 0 [done]"); return 0; } +static void afs_fetch_data_destructor(struct afs_call *call) +{ + struct afs_read *req = call->reply3; + + afs_put_read(req); + afs_flat_call_destructor(call); +} + /* * FS.FetchData operation type */ @@ -411,14 +447,14 @@ static const struct afs_call_type afs_RXFSFetchData = { .name = "FS.FetchData", .deliver = afs_deliver_fs_fetch_data, .abort_to_error = afs_abort_to_error, - .destructor = afs_flat_call_destructor, + .destructor = afs_fetch_data_destructor, }; static const struct afs_call_type afs_RXFSFetchData64 = { .name = "FS.FetchData64", .deliver = afs_deliver_fs_fetch_data, .abort_to_error = afs_abort_to_error, - .destructor = afs_flat_call_destructor, + .destructor = afs_fetch_data_destructor, }; /* @@ -427,8 +463,7 @@ static const struct afs_call_type afs_RXFSFetchData64 = { static int afs_fs_fetch_data64(struct afs_server *server, struct key *key, struct afs_vnode *vnode, - off_t offset, size_t length, - struct page *buffer, + struct afs_read *req, const struct afs_wait_mode *wait_mode) { struct afs_call *call; @@ -436,8 +471,6 @@ static int afs_fs_fetch_data64(struct afs_server *server, _enter(""); - ASSERTCMP(length, <, ULONG_MAX); - call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); if (!call) return -ENOMEM; @@ -445,7 +478,7 @@ static int afs_fs_fetch_data64(struct afs_server *server, call->key = key; call->reply = vnode; call->reply2 = NULL; /* volsync */ - call->reply3 = buffer; + call->reply3 = req; call->service_id = FS_SERVICE; call->port = htons(AFS_FS_PORT); call->operation_ID = FSFETCHDATA64; @@ -456,11 +489,12 @@ static int afs_fs_fetch_data64(struct afs_server *server, bp[1] = htonl(vnode->fid.vid); bp[2] = htonl(vnode->fid.vnode); bp[3] = htonl(vnode->fid.unique); - bp[4] = htonl(upper_32_bits(offset)); - bp[5] = htonl((u32) offset); + bp[4] = htonl(upper_32_bits(req->pos)); + bp[5] = htonl(lower_32_bits(req->pos)); bp[6] = 0; - bp[7] = htonl((u32) length); + bp[7] = htonl(lower_32_bits(req->len)); + atomic_inc(&req->usage); return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); } @@ -470,16 +504,16 @@ static int afs_fs_fetch_data64(struct afs_server *server, int afs_fs_fetch_data(struct afs_server *server, struct key *key, struct afs_vnode *vnode, - off_t offset, size_t length, - struct page *buffer, + struct afs_read *req, const struct afs_wait_mode *wait_mode) { struct afs_call *call; __be32 *bp; - if (upper_32_bits(offset) || upper_32_bits(offset + length)) - return afs_fs_fetch_data64(server, key, vnode, offset, length, - buffer, wait_mode); + if (upper_32_bits(req->pos) || + upper_32_bits(req->len) || + upper_32_bits(req->pos + req->len)) + return afs_fs_fetch_data64(server, key, vnode, req, wait_mode); _enter(""); @@ -490,7 +524,7 @@ int afs_fs_fetch_data(struct afs_server *server, call->key = key; call->reply = vnode; call->reply2 = NULL; /* volsync */ - call->reply3 = buffer; + call->reply3 = req; call->service_id = FS_SERVICE; call->port = htons(AFS_FS_PORT); call->operation_ID = FSFETCHDATA; @@ -501,9 +535,10 @@ int afs_fs_fetch_data(struct afs_server *server, bp[1] = htonl(vnode->fid.vid); bp[2] = htonl(vnode->fid.vnode); bp[3] = htonl(vnode->fid.unique); - bp[4] = htonl(offset); - bp[5] = htonl(length); + bp[4] = htonl(lower_32_bits(req->pos)); + bp[5] = htonl(lower_32_bits(req->len)); + atomic_inc(&req->usage); return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); } diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 535a38d2c1d0..6f7a9638ba1a 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -133,6 +133,22 @@ struct afs_call_type { void (*destructor)(struct afs_call *call); }; +/* + * Record of an outstanding read operation on a vnode. + */ +struct afs_read { + loff_t pos; /* Where to start reading */ + loff_t len; /* How much to read */ + loff_t actual_len; /* How much we're actually getting */ + atomic_t usage; + unsigned int remain; /* Amount remaining */ + unsigned int index; /* Which page we're reading into */ + unsigned int pg_offset; /* Offset in page we're at */ + unsigned int nr_pages; + void (*page_done)(struct afs_call *, struct afs_read *); + struct page *pages[]; +}; + /* * record of an outstanding writeback on a vnode */ @@ -494,6 +510,7 @@ extern const struct file_operations afs_file_operations; extern int afs_open(struct inode *, struct file *); extern int afs_release(struct inode *, struct file *); extern int afs_page_filler(void *, struct page *); +extern void afs_put_read(struct afs_read *); /* * flock.c @@ -513,7 +530,7 @@ extern int afs_fs_fetch_file_status(struct afs_server *, struct key *, extern int afs_fs_give_up_callbacks(struct afs_server *, const struct afs_wait_mode *); extern int afs_fs_fetch_data(struct afs_server *, struct key *, - struct afs_vnode *, off_t, size_t, struct page *, + struct afs_vnode *, struct afs_read *, const struct afs_wait_mode *); extern int afs_fs_create(struct afs_server *, struct key *, struct afs_vnode *, const char *, umode_t, @@ -699,7 +716,7 @@ extern void afs_vnode_finalise_status_update(struct afs_vnode *, extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *, struct key *); extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *, - off_t, size_t, struct page *); + struct afs_read *); extern int afs_vnode_create(struct afs_vnode *, struct key *, const char *, umode_t, struct afs_fid *, struct afs_file_status *, struct afs_callback *, struct afs_server **); diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index 25cf4c3f4ff7..45aa874f5d32 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c @@ -393,7 +393,7 @@ no_server: * - TODO implement caching */ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, - off_t offset, size_t length, struct page *page) + struct afs_read *desc) { struct afs_server *server; int ret; @@ -420,8 +420,8 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); - ret = afs_fs_fetch_data(server, key, vnode, offset, length, - page, &afs_sync_call); + ret = afs_fs_fetch_data(server, key, vnode, desc, + &afs_sync_call); } while (!afs_volume_release_fileserver(vnode, server, ret)); diff --git a/fs/afs/write.c b/fs/afs/write.c index f865c3f05bea..c83c1a0e851f 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -86,19 +86,30 @@ void afs_put_writeback(struct afs_writeback *wb) static int afs_fill_page(struct afs_vnode *vnode, struct key *key, loff_t pos, struct page *page) { + struct afs_read *req; loff_t i_size; int ret; - int len; _enter(",,%llu", (unsigned long long)pos); + req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *), + GFP_KERNEL); + if (!req) + return -ENOMEM; + + atomic_set(&req->usage, 1); + req->pos = pos; + req->nr_pages = 1; + req->pages[0] = page; + i_size = i_size_read(&vnode->vfs_inode); if (pos + PAGE_SIZE > i_size) - len = i_size - pos; + req->len = i_size - pos; else - len = PAGE_SIZE; + req->len = PAGE_SIZE; - ret = afs_vnode_fetch_data(vnode, key, pos, len, page); + ret = afs_vnode_fetch_data(vnode, key, req); + afs_put_read(req); if (ret < 0) { if (ret == -ENOENT) { _debug("got NOENT from server" -- cgit v1.2.3-59-g8ed1b From 91b467e0a3f5fa861265eda94640b7d4c0290551 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Jan 2017 10:38:35 +0000 Subject: afs: Make afs_readpages() fetch data in bulk Make afs_readpages() use afs_vnode_fetch_data()'s new ability to take a list of pages and do a bulk fetch. Signed-off-by: David Howells --- fs/afs/file.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/afs/volume.c | 1 + 2 files changed, 130 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/afs/file.c b/fs/afs/file.c index 6c262ceef32d..82897a78abc7 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "internal.h" static int afs_readpage(struct file *file, struct page *page); @@ -261,6 +262,129 @@ static int afs_readpage(struct file *file, struct page *page) return ret; } +/* + * Make pages available as they're filled. + */ +static void afs_readpages_page_done(struct afs_call *call, struct afs_read *req) +{ + struct afs_vnode *vnode = call->reply; + struct page *page = req->pages[req->index]; + + req->pages[req->index] = NULL; + SetPageUptodate(page); + + /* send the page to the cache */ +#ifdef CONFIG_AFS_FSCACHE + if (PageFsCache(page) && + fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) { + fscache_uncache_page(vnode->cache, page); + BUG_ON(PageFsCache(page)); + } +#endif + unlock_page(page); + put_page(page); +} + +/* + * Read a contiguous set of pages. + */ +static int afs_readpages_one(struct file *file, struct address_space *mapping, + struct list_head *pages) +{ + struct afs_vnode *vnode = AFS_FS_I(mapping->host); + struct afs_read *req; + struct list_head *p; + struct page *first, *page; + struct key *key = file->private_data; + pgoff_t index; + int ret, n, i; + + /* Count the number of contiguous pages at the front of the list. Note + * that the list goes prev-wards rather than next-wards. + */ + first = list_entry(pages->prev, struct page, lru); + index = first->index + 1; + n = 1; + for (p = first->lru.prev; p != pages; p = p->prev) { + page = list_entry(p, struct page, lru); + if (page->index != index) + break; + index++; + n++; + } + + req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *) * n, + GFP_NOFS); + if (!req) + return -ENOMEM; + + atomic_set(&req->usage, 1); + req->page_done = afs_readpages_page_done; + req->pos = first->index; + req->pos <<= PAGE_SHIFT; + + /* Transfer the pages to the request. We add them in until one fails + * to add to the LRU and then we stop (as that'll make a hole in the + * contiguous run. + * + * Note that it's possible for the file size to change whilst we're + * doing this, but we rely on the server returning less than we asked + * for if the file shrank. We also rely on this to deal with a partial + * page at the end of the file. + */ + do { + page = list_entry(pages->prev, struct page, lru); + list_del(&page->lru); + index = page->index; + if (add_to_page_cache_lru(page, mapping, index, + readahead_gfp_mask(mapping))) { +#ifdef CONFIG_AFS_FSCACHE + fscache_uncache_page(vnode->cache, page); +#endif + put_page(page); + break; + } + + req->pages[req->nr_pages++] = page; + req->len += PAGE_SIZE; + } while (req->nr_pages < n); + + if (req->nr_pages == 0) { + kfree(req); + return 0; + } + + ret = afs_vnode_fetch_data(vnode, key, req); + if (ret < 0) + goto error; + + task_io_account_read(PAGE_SIZE * req->nr_pages); + afs_put_read(req); + return 0; + +error: + if (ret == -ENOENT) { + _debug("got NOENT from server" + " - marking file deleted and stale"); + set_bit(AFS_VNODE_DELETED, &vnode->flags); + ret = -ESTALE; + } + + for (i = 0; i < req->nr_pages; i++) { + page = req->pages[i]; + if (page) { +#ifdef CONFIG_AFS_FSCACHE + fscache_uncache_page(vnode->cache, page); +#endif + SetPageError(page); + unlock_page(page); + } + } + + afs_put_read(req); + return ret; +} + /* * read a set of pages */ @@ -314,8 +438,11 @@ static int afs_readpages(struct file *file, struct address_space *mapping, return ret; } - /* load the missing pages from the network */ - ret = read_cache_pages(mapping, pages, afs_page_filler, key); + while (!list_empty(pages)) { + ret = afs_readpages_one(file, mapping, pages); + if (ret < 0) + break; + } _leave(" = %d [netting]", ret); return ret; diff --git a/fs/afs/volume.c b/fs/afs/volume.c index d142a2449e65..546f9d01710b 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c @@ -106,6 +106,7 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params) volume->cell = params->cell; volume->vid = vlocation->vldb.vid[params->type]; + volume->bdi.ra_pages = VM_MAX_READAHEAD*1024/PAGE_SIZE; ret = bdi_setup_and_register(&volume->bdi, "afs"); if (ret) goto error_bdi; -- cgit v1.2.3-59-g8ed1b From 8e8d7f13b6d5a93b3d2cf9a4ceaaf923809fd5ac Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Jan 2017 10:38:34 +0000 Subject: afs: Add some tracepoints Add three tracepoints to the AFS filesystem: (1) The afs_recv_data tracepoint logs data segments that are extracted from the data received from the peer through afs_extract_data(). (2) The afs_notify_call tracepoint logs notification from AF_RXRPC of data coming in to an asynchronous call. (3) The afs_cb_call tracepoint logs incoming calls that have had their operation ID extracted and mapped into a supported cache manager service call. To make (3) work, the name strings in the afs_call_type struct objects have to be annotated with __tracepoint_string. This is done with the CM_NAME() macro. Further, the AFS call state enum needs a name so that it can be used to declare parameter types. Signed-off-by: David Howells --- fs/afs/cmservice.c | 22 ++++++--- fs/afs/internal.h | 21 +++++---- fs/afs/main.c | 1 + fs/afs/rxrpc.c | 6 +++ include/trace/events/afs.h | 109 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 144 insertions(+), 15 deletions(-) create mode 100644 include/trace/events/afs.h (limited to 'fs') diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index d764236072b1..a2e1e02005f6 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -25,11 +25,16 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *); static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *); static void afs_cm_destructor(struct afs_call *); +#define CM_NAME(name) \ + const char afs_SRXCB##name##_name[] __tracepoint_string = \ + "CB." #name + /* * CB.CallBack operation type */ +static CM_NAME(CallBack); static const struct afs_call_type afs_SRXCBCallBack = { - .name = "CB.CallBack", + .name = afs_SRXCBCallBack_name, .deliver = afs_deliver_cb_callback, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, @@ -38,8 +43,9 @@ static const struct afs_call_type afs_SRXCBCallBack = { /* * CB.InitCallBackState operation type */ +static CM_NAME(InitCallBackState); static const struct afs_call_type afs_SRXCBInitCallBackState = { - .name = "CB.InitCallBackState", + .name = afs_SRXCBInitCallBackState_name, .deliver = afs_deliver_cb_init_call_back_state, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, @@ -48,8 +54,9 @@ static const struct afs_call_type afs_SRXCBInitCallBackState = { /* * CB.InitCallBackState3 operation type */ +static CM_NAME(InitCallBackState3); static const struct afs_call_type afs_SRXCBInitCallBackState3 = { - .name = "CB.InitCallBackState3", + .name = afs_SRXCBInitCallBackState3_name, .deliver = afs_deliver_cb_init_call_back_state3, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, @@ -58,8 +65,9 @@ static const struct afs_call_type afs_SRXCBInitCallBackState3 = { /* * CB.Probe operation type */ +static CM_NAME(Probe); static const struct afs_call_type afs_SRXCBProbe = { - .name = "CB.Probe", + .name = afs_SRXCBProbe_name, .deliver = afs_deliver_cb_probe, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, @@ -68,8 +76,9 @@ static const struct afs_call_type afs_SRXCBProbe = { /* * CB.ProbeUuid operation type */ +static CM_NAME(ProbeUuid); static const struct afs_call_type afs_SRXCBProbeUuid = { - .name = "CB.ProbeUuid", + .name = afs_SRXCBProbeUuid_name, .deliver = afs_deliver_cb_probe_uuid, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, @@ -78,8 +87,9 @@ static const struct afs_call_type afs_SRXCBProbeUuid = { /* * CB.TellMeAboutYourself operation type */ +static CM_NAME(TellMeAboutYourself); static const struct afs_call_type afs_SRXCBTellMeAboutYourself = { - .name = "CB.TellMeAboutYourself", + .name = afs_SRXCBTellMeAboutYourself_name, .deliver = afs_deliver_cb_tell_me_about_yourself, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 6f7a9638ba1a..f71e58fcc2f2 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -68,6 +68,15 @@ struct afs_wait_mode { extern const struct afs_wait_mode afs_sync_call; extern const struct afs_wait_mode afs_async_call; +enum afs_call_state { + AFS_CALL_REQUESTING, /* request is being sent for outgoing call */ + AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */ + AFS_CALL_AWAIT_OP_ID, /* awaiting op ID on incoming call */ + AFS_CALL_AWAIT_REQUEST, /* awaiting request data on incoming call */ + AFS_CALL_REPLYING, /* replying to incoming call */ + AFS_CALL_AWAIT_ACK, /* awaiting final ACK of incoming call */ + AFS_CALL_COMPLETE, /* Completed or failed */ +}; /* * a record of an in-progress RxRPC call */ @@ -91,15 +100,7 @@ struct afs_call { pgoff_t first; /* first page in mapping to deal with */ pgoff_t last; /* last page in mapping to deal with */ size_t offset; /* offset into received data store */ - enum { /* call state */ - AFS_CALL_REQUESTING, /* request is being sent for outgoing call */ - AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */ - AFS_CALL_AWAIT_OP_ID, /* awaiting op ID on incoming call */ - AFS_CALL_AWAIT_REQUEST, /* awaiting request data on incoming call */ - AFS_CALL_REPLYING, /* replying to incoming call */ - AFS_CALL_AWAIT_ACK, /* awaiting final ACK of incoming call */ - AFS_CALL_COMPLETE, /* Completed or failed */ - } state; + enum afs_call_state state; int error; /* error code */ u32 abort_code; /* Remote abort ID or 0 */ unsigned request_size; /* size of request data */ @@ -773,6 +774,8 @@ extern int afs_fsync(struct file *, loff_t, loff_t, int); /* * debug tracing */ +#include + extern unsigned afs_debug; #define dbgprintk(FMT,...) \ diff --git a/fs/afs/main.c b/fs/afs/main.c index 0b187ef3b5b7..f8188feb03ad 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c @@ -15,6 +15,7 @@ #include #include #include +#define CREATE_TRACE_POINTS #include "internal.h" MODULE_DESCRIPTION("AFS Client File System"); diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 25f05a8d21b1..f26344a8c029 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -416,6 +416,8 @@ static void afs_deliver_to_call(struct afs_call *call) ret = rxrpc_kernel_recv_data(afs_socket, call->rxcall, NULL, 0, &offset, false, &call->abort_code); + trace_afs_recv_data(call, 0, offset, false, ret); + if (ret == -EINPROGRESS || ret == -EAGAIN) return; if (ret == 1 || ret < 0) { @@ -541,6 +543,7 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, { struct afs_call *call = (struct afs_call *)call_user_ID; + trace_afs_notify_call(rxcall, call); call->need_attention = true; queue_work(afs_async_calls, &call->async_work); } @@ -689,6 +692,8 @@ static int afs_deliver_cm_op_id(struct afs_call *call) if (!afs_cm_incoming_call(call)) return -ENOTSUPP; + trace_afs_cb_call(call); + /* pass responsibility for the remainer of this message off to the * cache manager op */ return call->type->deliver(call); @@ -780,6 +785,7 @@ int afs_extract_data(struct afs_call *call, void *buf, size_t count, ret = rxrpc_kernel_recv_data(afs_socket, call->rxcall, buf, count, &call->offset, want_more, &call->abort_code); + trace_afs_recv_data(call, count, call->offset, want_more, ret); if (ret == 0 || ret == -EAGAIN) return ret; diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h new file mode 100644 index 000000000000..845907b04ff4 --- /dev/null +++ b/include/trace/events/afs.h @@ -0,0 +1,109 @@ +/* AFS tracepoints + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM afs + +#if !defined(_TRACE_AFS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_AFS_H + +#include + +TRACE_EVENT(afs_recv_data, + TP_PROTO(struct afs_call *call, unsigned count, unsigned offset, + bool want_more, int ret), + + TP_ARGS(call, count, offset, want_more, ret), + + TP_STRUCT__entry( + __field(struct rxrpc_call *, rxcall ) + __field(struct afs_call *, call ) + __field(enum afs_call_state, state ) + __field(unsigned int, count ) + __field(unsigned int, offset ) + __field(unsigned short, unmarshall ) + __field(bool, want_more ) + __field(int, ret ) + ), + + TP_fast_assign( + __entry->rxcall = call->rxcall; + __entry->call = call; + __entry->state = call->state; + __entry->unmarshall = call->unmarshall; + __entry->count = count; + __entry->offset = offset; + __entry->want_more = want_more; + __entry->ret = ret; + ), + + TP_printk("c=%p ac=%p s=%u u=%u %u/%u wm=%u ret=%d", + __entry->rxcall, + __entry->call, + __entry->state, __entry->unmarshall, + __entry->offset, __entry->count, + __entry->want_more, __entry->ret) + ); + +TRACE_EVENT(afs_notify_call, + TP_PROTO(struct rxrpc_call *rxcall, struct afs_call *call), + + TP_ARGS(rxcall, call), + + TP_STRUCT__entry( + __field(struct rxrpc_call *, rxcall ) + __field(struct afs_call *, call ) + __field(enum afs_call_state, state ) + __field(unsigned short, unmarshall ) + ), + + TP_fast_assign( + __entry->rxcall = rxcall; + __entry->call = call; + __entry->state = call->state; + __entry->unmarshall = call->unmarshall; + ), + + TP_printk("c=%p ac=%p s=%u u=%u", + __entry->rxcall, + __entry->call, + __entry->state, __entry->unmarshall) + ); + +TRACE_EVENT(afs_cb_call, + TP_PROTO(struct afs_call *call), + + TP_ARGS(call), + + TP_STRUCT__entry( + __field(struct rxrpc_call *, rxcall ) + __field(struct afs_call *, call ) + __field(const char *, name ) + __field(u32, op ) + ), + + TP_fast_assign( + __entry->rxcall = call->rxcall; + __entry->call = call; + __entry->name = call->type->name; + __entry->op = call->operation_ID; + ), + + TP_printk("c=%p ac=%p %s o=%u", + __entry->rxcall, + __entry->call, + __entry->name, + __entry->op) + ); + +#endif /* _TRACE_AFS_H */ + +/* This part must be outside protection */ +#include -- cgit v1.2.3-59-g8ed1b From 56ff9c837778ba2cf76f29c966856a9341e5939d Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Jan 2017 10:38:36 +0000 Subject: afs: Kill afs_wait_mode The afs_wait_mode struct isn't really necessary. Client calls only use one of a choice of two (synchronous or the asynchronous) and incoming calls don't use the wait at all. Replace with a boolean parameter. Signed-off-by: David Howells --- fs/afs/callback.c | 2 +- fs/afs/fsclient.c | 80 +++++++++++++++++++++++++++--------------------------- fs/afs/internal.h | 68 ++++++++++++---------------------------------- fs/afs/rxrpc.c | 51 ++++++++-------------------------- fs/afs/vlclient.c | 8 +++--- fs/afs/vlocation.c | 4 +-- fs/afs/vnode.c | 26 +++++++++--------- 7 files changed, 90 insertions(+), 149 deletions(-) (limited to 'fs') diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 1e9d2f84e5b5..b29447e03ede 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -343,7 +343,7 @@ void afs_dispatch_give_up_callbacks(struct work_struct *work) * had callbacks entirely, and the server will call us later to break * them */ - afs_fs_give_up_callbacks(server, &afs_async_call); + afs_fs_give_up_callbacks(server, true); } /* diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 7dc1f6fb3661..ac8e766978dc 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -275,7 +275,7 @@ int afs_fs_fetch_file_status(struct afs_server *server, struct key *key, struct afs_vnode *vnode, struct afs_volsync *volsync, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -300,7 +300,7 @@ int afs_fs_fetch_file_status(struct afs_server *server, bp[2] = htonl(vnode->fid.vnode); bp[3] = htonl(vnode->fid.unique); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -464,7 +464,7 @@ static int afs_fs_fetch_data64(struct afs_server *server, struct key *key, struct afs_vnode *vnode, struct afs_read *req, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -495,7 +495,7 @@ static int afs_fs_fetch_data64(struct afs_server *server, bp[7] = htonl(lower_32_bits(req->len)); atomic_inc(&req->usage); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -505,7 +505,7 @@ int afs_fs_fetch_data(struct afs_server *server, struct key *key, struct afs_vnode *vnode, struct afs_read *req, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -513,7 +513,7 @@ int afs_fs_fetch_data(struct afs_server *server, if (upper_32_bits(req->pos) || upper_32_bits(req->len) || upper_32_bits(req->pos + req->len)) - return afs_fs_fetch_data64(server, key, vnode, req, wait_mode); + return afs_fs_fetch_data64(server, key, vnode, req, async); _enter(""); @@ -539,7 +539,7 @@ int afs_fs_fetch_data(struct afs_server *server, bp[5] = htonl(lower_32_bits(req->len)); atomic_inc(&req->usage); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -568,7 +568,7 @@ static const struct afs_call_type afs_RXFSGiveUpCallBacks = { * - the callbacks are held in the server->cb_break ring */ int afs_fs_give_up_callbacks(struct afs_server *server, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; size_t ncallbacks; @@ -622,7 +622,7 @@ int afs_fs_give_up_callbacks(struct afs_server *server, ASSERT(ncallbacks > 0); wake_up_nr(&server->cb_break_waitq, ncallbacks); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -673,7 +673,7 @@ int afs_fs_create(struct afs_server *server, struct afs_fid *newfid, struct afs_file_status *newstatus, struct afs_callback *newcb, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; size_t namesz, reqsz, padsz; @@ -718,7 +718,7 @@ int afs_fs_create(struct afs_server *server, *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ *bp++ = 0; /* segment size */ - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -763,7 +763,7 @@ int afs_fs_remove(struct afs_server *server, struct afs_vnode *vnode, const char *name, bool isdir, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; size_t namesz, reqsz, padsz; @@ -798,7 +798,7 @@ int afs_fs_remove(struct afs_server *server, bp = (void *) bp + padsz; } - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -844,7 +844,7 @@ int afs_fs_link(struct afs_server *server, struct afs_vnode *dvnode, struct afs_vnode *vnode, const char *name, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; size_t namesz, reqsz, padsz; @@ -883,7 +883,7 @@ int afs_fs_link(struct afs_server *server, *bp++ = htonl(vnode->fid.vnode); *bp++ = htonl(vnode->fid.unique); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -932,7 +932,7 @@ int afs_fs_symlink(struct afs_server *server, const char *contents, struct afs_fid *newfid, struct afs_file_status *newstatus, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; size_t namesz, reqsz, padsz, c_namesz, c_padsz; @@ -987,7 +987,7 @@ int afs_fs_symlink(struct afs_server *server, *bp++ = htonl(S_IRWXUGO); /* unix mode */ *bp++ = 0; /* segment size */ - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1036,7 +1036,7 @@ int afs_fs_rename(struct afs_server *server, const char *orig_name, struct afs_vnode *new_dvnode, const char *new_name, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; @@ -1090,7 +1090,7 @@ int afs_fs_rename(struct afs_server *server, bp = (void *) bp + n_padsz; } - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1145,7 +1145,7 @@ static int afs_fs_store_data64(struct afs_server *server, pgoff_t first, pgoff_t last, unsigned offset, unsigned to, loff_t size, loff_t pos, loff_t i_size, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_vnode *vnode = wb->vnode; struct afs_call *call; @@ -1194,7 +1194,7 @@ static int afs_fs_store_data64(struct afs_server *server, *bp++ = htonl(i_size >> 32); *bp++ = htonl((u32) i_size); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1203,7 +1203,7 @@ static int afs_fs_store_data64(struct afs_server *server, int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, pgoff_t first, pgoff_t last, unsigned offset, unsigned to, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_vnode *vnode = wb->vnode; struct afs_call *call; @@ -1229,7 +1229,7 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) return afs_fs_store_data64(server, wb, first, last, offset, to, - size, pos, i_size, wait_mode); + size, pos, i_size, async); call = afs_alloc_flat_call(&afs_RXFSStoreData, (4 + 6 + 3) * 4, @@ -1268,7 +1268,7 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, *bp++ = htonl(size); *bp++ = htonl(i_size); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1330,7 +1330,7 @@ static const struct afs_call_type afs_RXFSStoreData64_as_Status = { */ static int afs_fs_setattr_size64(struct afs_server *server, struct key *key, struct afs_vnode *vnode, struct iattr *attr, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -1369,7 +1369,7 @@ static int afs_fs_setattr_size64(struct afs_server *server, struct key *key, *bp++ = htonl(attr->ia_size >> 32); /* new file length */ *bp++ = htonl((u32) attr->ia_size); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1378,7 +1378,7 @@ static int afs_fs_setattr_size64(struct afs_server *server, struct key *key, */ static int afs_fs_setattr_size(struct afs_server *server, struct key *key, struct afs_vnode *vnode, struct iattr *attr, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -1389,7 +1389,7 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key, ASSERT(attr->ia_valid & ATTR_SIZE); if (attr->ia_size >> 32) return afs_fs_setattr_size64(server, key, vnode, attr, - wait_mode); + async); call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status, (4 + 6 + 3) * 4, @@ -1417,7 +1417,7 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key, *bp++ = 0; /* size of write */ *bp++ = htonl(attr->ia_size); /* new file length */ - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1426,14 +1426,14 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key, */ int afs_fs_setattr(struct afs_server *server, struct key *key, struct afs_vnode *vnode, struct iattr *attr, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; if (attr->ia_valid & ATTR_SIZE) return afs_fs_setattr_size(server, key, vnode, attr, - wait_mode); + async); _enter(",%x,{%x:%u},,", key_serial(key), vnode->fid.vid, vnode->fid.vnode); @@ -1459,7 +1459,7 @@ int afs_fs_setattr(struct afs_server *server, struct key *key, xdr_encode_AFS_StoreStatus(&bp, attr); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1661,7 +1661,7 @@ int afs_fs_get_volume_status(struct afs_server *server, struct key *key, struct afs_vnode *vnode, struct afs_volume_status *vs, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -1691,7 +1691,7 @@ int afs_fs_get_volume_status(struct afs_server *server, bp[0] = htonl(FSGETVOLUMESTATUS); bp[1] = htonl(vnode->fid.vid); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1753,7 +1753,7 @@ int afs_fs_set_lock(struct afs_server *server, struct key *key, struct afs_vnode *vnode, afs_lock_type_t type, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -1777,7 +1777,7 @@ int afs_fs_set_lock(struct afs_server *server, *bp++ = htonl(vnode->fid.unique); *bp++ = htonl(type); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1786,7 +1786,7 @@ int afs_fs_set_lock(struct afs_server *server, int afs_fs_extend_lock(struct afs_server *server, struct key *key, struct afs_vnode *vnode, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -1809,7 +1809,7 @@ int afs_fs_extend_lock(struct afs_server *server, *bp++ = htonl(vnode->fid.vnode); *bp++ = htonl(vnode->fid.unique); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } /* @@ -1818,7 +1818,7 @@ int afs_fs_extend_lock(struct afs_server *server, int afs_fs_release_lock(struct afs_server *server, struct key *key, struct afs_vnode *vnode, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -1841,5 +1841,5 @@ int afs_fs_release_lock(struct afs_server *server, *bp++ = htonl(vnode->fid.vnode); *bp++ = htonl(vnode->fid.unique); - return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); + return afs_make_call(&server->addr, call, GFP_NOFS, async); } diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f71e58fcc2f2..b411670d5f67 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -51,23 +51,6 @@ struct afs_mount_params { struct key *key; /* key to use for secure mounting */ }; -/* - * definition of how to wait for the completion of an operation - */ -struct afs_wait_mode { - /* RxRPC received message notification */ - rxrpc_notify_rx_t notify_rx; - - /* synchronous call waiter and call dispatched notification */ - int (*wait)(struct afs_call *call); - - /* asynchronous call completion */ - void (*async_complete)(void *reply, int error); -}; - -extern const struct afs_wait_mode afs_sync_call; -extern const struct afs_wait_mode afs_async_call; - enum afs_call_state { AFS_CALL_REQUESTING, /* request is being sent for outgoing call */ AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */ @@ -82,7 +65,6 @@ enum afs_call_state { */ struct afs_call { const struct afs_call_type *type; /* type of call */ - const struct afs_wait_mode *wait_mode; /* completion wait mode */ wait_queue_head_t waitq; /* processes awaiting completion */ struct work_struct async_work; /* asynchronous work processor */ struct work_struct work; /* actual work processor */ @@ -111,6 +93,7 @@ struct afs_call { bool incoming; /* T if incoming call */ bool send_pages; /* T if data from mapping should be sent */ bool need_attention; /* T if RxRPC poked us */ + bool async; /* T if asynchronous */ u16 service_id; /* RxRPC service ID to call */ __be16 port; /* target UDP port */ u32 operation_ID; /* operation ID for an incoming call */ @@ -527,50 +510,37 @@ extern int afs_flock(struct file *, int, struct file_lock *); */ extern int afs_fs_fetch_file_status(struct afs_server *, struct key *, struct afs_vnode *, struct afs_volsync *, - const struct afs_wait_mode *); -extern int afs_fs_give_up_callbacks(struct afs_server *, - const struct afs_wait_mode *); + bool); +extern int afs_fs_give_up_callbacks(struct afs_server *, bool); extern int afs_fs_fetch_data(struct afs_server *, struct key *, - struct afs_vnode *, struct afs_read *, - const struct afs_wait_mode *); + struct afs_vnode *, struct afs_read *, bool); extern int afs_fs_create(struct afs_server *, struct key *, struct afs_vnode *, const char *, umode_t, struct afs_fid *, struct afs_file_status *, - struct afs_callback *, - const struct afs_wait_mode *); + struct afs_callback *, bool); extern int afs_fs_remove(struct afs_server *, struct key *, - struct afs_vnode *, const char *, bool, - const struct afs_wait_mode *); + struct afs_vnode *, const char *, bool, bool); extern int afs_fs_link(struct afs_server *, struct key *, struct afs_vnode *, - struct afs_vnode *, const char *, - const struct afs_wait_mode *); + struct afs_vnode *, const char *, bool); extern int afs_fs_symlink(struct afs_server *, struct key *, struct afs_vnode *, const char *, const char *, - struct afs_fid *, struct afs_file_status *, - const struct afs_wait_mode *); + struct afs_fid *, struct afs_file_status *, bool); extern int afs_fs_rename(struct afs_server *, struct key *, struct afs_vnode *, const char *, - struct afs_vnode *, const char *, - const struct afs_wait_mode *); + struct afs_vnode *, const char *, bool); extern int afs_fs_store_data(struct afs_server *, struct afs_writeback *, - pgoff_t, pgoff_t, unsigned, unsigned, - const struct afs_wait_mode *); + pgoff_t, pgoff_t, unsigned, unsigned, bool); extern int afs_fs_setattr(struct afs_server *, struct key *, - struct afs_vnode *, struct iattr *, - const struct afs_wait_mode *); + struct afs_vnode *, struct iattr *, bool); extern int afs_fs_get_volume_status(struct afs_server *, struct key *, struct afs_vnode *, - struct afs_volume_status *, - const struct afs_wait_mode *); + struct afs_volume_status *, bool); extern int afs_fs_set_lock(struct afs_server *, struct key *, - struct afs_vnode *, afs_lock_type_t, - const struct afs_wait_mode *); + struct afs_vnode *, afs_lock_type_t, bool); extern int afs_fs_extend_lock(struct afs_server *, struct key *, - struct afs_vnode *, - const struct afs_wait_mode *); + struct afs_vnode *, bool); extern int afs_fs_release_lock(struct afs_server *, struct key *, - struct afs_vnode *, - const struct afs_wait_mode *); + struct afs_vnode *, bool); /* * inode.c @@ -624,8 +594,7 @@ extern struct socket *afs_socket; extern int afs_open_socket(void); extern void afs_close_socket(void); -extern int afs_make_call(struct in_addr *, struct afs_call *, gfp_t, - const struct afs_wait_mode *); +extern int afs_make_call(struct in_addr *, struct afs_call *, gfp_t, bool); extern struct afs_call *afs_alloc_flat_call(const struct afs_call_type *, size_t, size_t); extern void afs_flat_call_destructor(struct afs_call *); @@ -681,11 +650,10 @@ extern int afs_get_MAC_address(u8 *, size_t); */ extern int afs_vl_get_entry_by_name(struct in_addr *, struct key *, const char *, struct afs_cache_vlocation *, - const struct afs_wait_mode *); + bool); extern int afs_vl_get_entry_by_id(struct in_addr *, struct key *, afs_volid_t, afs_voltype_t, - struct afs_cache_vlocation *, - const struct afs_wait_mode *); + struct afs_cache_vlocation *, bool); /* * vlocation.c diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index f26344a8c029..ec1e41f929d1 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -25,29 +25,11 @@ static void afs_free_call(struct afs_call *); static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); static int afs_wait_for_call_to_complete(struct afs_call *); static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); -static int afs_dont_wait_for_call_to_complete(struct afs_call *); static void afs_process_async_call(struct work_struct *); static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); static int afs_deliver_cm_op_id(struct afs_call *); -/* synchronous call management */ -const struct afs_wait_mode afs_sync_call = { - .notify_rx = afs_wake_up_call_waiter, - .wait = afs_wait_for_call_to_complete, -}; - -/* asynchronous call management */ -const struct afs_wait_mode afs_async_call = { - .notify_rx = afs_wake_up_async_call, - .wait = afs_dont_wait_for_call_to_complete, -}; - -/* asynchronous incoming call management */ -static const struct afs_wait_mode afs_async_incoming_call = { - .notify_rx = afs_wake_up_async_call, -}; - /* asynchronous incoming call initial processing */ static const struct afs_call_type afs_RXCMxxxx = { .name = "CB.xxxx", @@ -315,7 +297,7 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg, * initiate a call */ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, - const struct afs_wait_mode *wait_mode) + bool async) { struct sockaddr_rxrpc srx; struct rxrpc_call *rxcall; @@ -332,7 +314,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, call, call->type->name, key_serial(call->key), atomic_read(&afs_outstanding_calls)); - call->wait_mode = wait_mode; + call->async = async; INIT_WORK(&call->async_work, afs_process_async_call); memset(&srx, 0, sizeof(srx)); @@ -347,7 +329,9 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, /* create a call */ rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, (unsigned long) call, gfp, - wait_mode->notify_rx); + (async ? + afs_wake_up_async_call : + afs_wake_up_call_waiter)); call->key = NULL; if (IS_ERR(rxcall)) { ret = PTR_ERR(rxcall); @@ -386,7 +370,10 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, /* at this point, an async call may no longer exist as it may have * already completed */ - return wait_mode->wait(call); + if (call->async) + return -EINPROGRESS; + + return afs_wait_for_call_to_complete(call); error_do_abort: rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT, -ret, "KSD"); @@ -548,17 +535,6 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, queue_work(afs_async_calls, &call->async_work); } -/* - * put a call into asynchronous mode - * - mustn't touch the call descriptor as the call my have completed by the - * time we get here - */ -static int afs_dont_wait_for_call_to_complete(struct afs_call *call) -{ - _enter(""); - return -EINPROGRESS; -} - /* * delete an asynchronous call */ @@ -587,10 +563,7 @@ static void afs_process_async_call(struct work_struct *work) afs_deliver_to_call(call); } - if (call->state == AFS_CALL_COMPLETE && call->wait_mode) { - if (call->wait_mode->async_complete) - call->wait_mode->async_complete(call->reply, - call->error); + if (call->state == AFS_CALL_COMPLETE) { call->reply = NULL; /* kill the call */ @@ -626,10 +599,10 @@ static void afs_charge_preallocation(struct work_struct *work) break; INIT_WORK(&call->async_work, afs_process_async_call); - call->wait_mode = &afs_async_incoming_call; call->type = &afs_RXCMxxxx; - init_waitqueue_head(&call->waitq); + call->async = true; call->state = AFS_CALL_AWAIT_OP_ID; + init_waitqueue_head(&call->waitq); } if (rxrpc_kernel_charge_accept(afs_socket, diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c index 94bcd97d22b8..a5e4cc561b6c 100644 --- a/fs/afs/vlclient.c +++ b/fs/afs/vlclient.c @@ -147,7 +147,7 @@ int afs_vl_get_entry_by_name(struct in_addr *addr, struct key *key, const char *volname, struct afs_cache_vlocation *entry, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; size_t volnamesz, reqsz, padsz; @@ -177,7 +177,7 @@ int afs_vl_get_entry_by_name(struct in_addr *addr, memset((void *) bp + volnamesz, 0, padsz); /* initiate the call */ - return afs_make_call(addr, call, GFP_KERNEL, wait_mode); + return afs_make_call(addr, call, GFP_KERNEL, async); } /* @@ -188,7 +188,7 @@ int afs_vl_get_entry_by_id(struct in_addr *addr, afs_volid_t volid, afs_voltype_t voltype, struct afs_cache_vlocation *entry, - const struct afs_wait_mode *wait_mode) + bool async) { struct afs_call *call; __be32 *bp; @@ -211,5 +211,5 @@ int afs_vl_get_entry_by_id(struct in_addr *addr, *bp = htonl(voltype); /* initiate the call */ - return afs_make_call(addr, call, GFP_KERNEL, wait_mode); + return afs_make_call(addr, call, GFP_KERNEL, async); } diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index 45a86396fd2d..d7d8dd8c0b31 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c @@ -53,7 +53,7 @@ static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, /* attempt to access the VL server */ ret = afs_vl_get_entry_by_name(&addr, key, vl->vldb.name, vldb, - &afs_sync_call); + false); switch (ret) { case 0: goto out; @@ -111,7 +111,7 @@ static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl, /* attempt to access the VL server */ ret = afs_vl_get_entry_by_id(&addr, key, volid, voltype, vldb, - &afs_sync_call); + false); switch (ret) { case 0: goto out; diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index 45aa874f5d32..dcb956143c86 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c @@ -358,7 +358,7 @@ get_anyway: server, ntohl(server->addr.s_addr)); ret = afs_fs_fetch_file_status(server, key, vnode, NULL, - &afs_sync_call); + false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -421,7 +421,7 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); ret = afs_fs_fetch_data(server, key, vnode, desc, - &afs_sync_call); + false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -477,7 +477,7 @@ int afs_vnode_create(struct afs_vnode *vnode, struct key *key, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); ret = afs_fs_create(server, key, vnode, name, mode, newfid, - newstatus, newcb, &afs_sync_call); + newstatus, newcb, false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -533,7 +533,7 @@ int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); ret = afs_fs_remove(server, key, vnode, name, isdir, - &afs_sync_call); + false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -595,7 +595,7 @@ int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); ret = afs_fs_link(server, key, dvnode, vnode, name, - &afs_sync_call); + false); } while (!afs_volume_release_fileserver(dvnode, server, ret)); @@ -659,7 +659,7 @@ int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); ret = afs_fs_symlink(server, key, vnode, name, content, - newfid, newstatus, &afs_sync_call); + newfid, newstatus, false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -729,7 +729,7 @@ int afs_vnode_rename(struct afs_vnode *orig_dvnode, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); ret = afs_fs_rename(server, key, orig_dvnode, orig_name, - new_dvnode, new_name, &afs_sync_call); + new_dvnode, new_name, false); } while (!afs_volume_release_fileserver(orig_dvnode, server, ret)); @@ -795,7 +795,7 @@ int afs_vnode_store_data(struct afs_writeback *wb, pgoff_t first, pgoff_t last, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); ret = afs_fs_store_data(server, wb, first, last, offset, to, - &afs_sync_call); + false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -847,7 +847,7 @@ int afs_vnode_setattr(struct afs_vnode *vnode, struct key *key, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); - ret = afs_fs_setattr(server, key, vnode, attr, &afs_sync_call); + ret = afs_fs_setattr(server, key, vnode, attr, false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -894,7 +894,7 @@ int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); - ret = afs_fs_get_volume_status(server, key, vnode, vs, &afs_sync_call); + ret = afs_fs_get_volume_status(server, key, vnode, vs, false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -933,7 +933,7 @@ int afs_vnode_set_lock(struct afs_vnode *vnode, struct key *key, _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); - ret = afs_fs_set_lock(server, key, vnode, type, &afs_sync_call); + ret = afs_fs_set_lock(server, key, vnode, type, false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -971,7 +971,7 @@ int afs_vnode_extend_lock(struct afs_vnode *vnode, struct key *key) _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); - ret = afs_fs_extend_lock(server, key, vnode, &afs_sync_call); + ret = afs_fs_extend_lock(server, key, vnode, false); } while (!afs_volume_release_fileserver(vnode, server, ret)); @@ -1009,7 +1009,7 @@ int afs_vnode_release_lock(struct afs_vnode *vnode, struct key *key) _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); - ret = afs_fs_release_lock(server, key, vnode, &afs_sync_call); + ret = afs_fs_release_lock(server, key, vnode, false); } while (!afs_volume_release_fileserver(vnode, server, ret)); -- cgit v1.2.3-59-g8ed1b From 341f741f04beceebcb30daa12ae2e5e52e64e532 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 5 Jan 2017 10:38:36 +0000 Subject: afs: Refcount the afs_call struct A static checker warning occurs in the AFS filesystem: fs/afs/cmservice.c:155 SRXAFSCB_CallBack() error: dereferencing freed memory 'call' due to the reply being sent before we access the server it points to. The act of sending the reply causes the call to be freed if an error occurs (but not if it doesn't). On top of this, the lifetime handling of afs_call structs is fragile because they get passed around through workqueues without any sort of refcounting. Deal with the issues by: (1) Fix the maybe/maybe not nature of the reply sending functions with regards to whether they release the call struct. (2) Refcount the afs_call struct and sort out places that need to get/put references. (3) Pass a ref through the work queue and release (or pass on) that ref in the work function. Care has to be taken because a work queue may already own a ref to the call. (4) Do the cleaning up in the put function only. (5) Simplify module cleanup by always incrementing afs_outstanding_calls whenever a call is allocated. (6) Set the backlog to 0 with kernel_listen() at the beginning of the process of closing the socket to prevent new incoming calls from occurring and to remove the contribution of preallocated calls from afs_outstanding_calls before we wait on it. A tracepoint is also added to monitor the afs_call refcount and lifetime. Reported-by: Dan Carpenter Signed-off-by: David Howells Fixes: 08e0e7c82eea: "[AF_RXRPC]: Make the in-kernel AFS filesystem use AF_RXRPC." --- fs/afs/cmservice.c | 41 ++++++------ fs/afs/internal.h | 9 ++- fs/afs/rxrpc.c | 153 ++++++++++++++++++++++++++++----------------- include/trace/events/afs.h | 75 ++++++++++++++++++++++ 4 files changed, 199 insertions(+), 79 deletions(-) (limited to 'fs') diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index a2e1e02005f6..e349a3316303 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -24,6 +24,11 @@ static int afs_deliver_cb_callback(struct afs_call *); static int afs_deliver_cb_probe_uuid(struct afs_call *); static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *); static void afs_cm_destructor(struct afs_call *); +static void SRXAFSCB_CallBack(struct work_struct *); +static void SRXAFSCB_InitCallBackState(struct work_struct *); +static void SRXAFSCB_Probe(struct work_struct *); +static void SRXAFSCB_ProbeUuid(struct work_struct *); +static void SRXAFSCB_TellMeAboutYourself(struct work_struct *); #define CM_NAME(name) \ const char afs_SRXCB##name##_name[] __tracepoint_string = \ @@ -38,6 +43,7 @@ static const struct afs_call_type afs_SRXCBCallBack = { .deliver = afs_deliver_cb_callback, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, + .work = SRXAFSCB_CallBack, }; /* @@ -49,6 +55,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState = { .deliver = afs_deliver_cb_init_call_back_state, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, + .work = SRXAFSCB_InitCallBackState, }; /* @@ -60,6 +67,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState3 = { .deliver = afs_deliver_cb_init_call_back_state3, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, + .work = SRXAFSCB_InitCallBackState, }; /* @@ -71,6 +79,7 @@ static const struct afs_call_type afs_SRXCBProbe = { .deliver = afs_deliver_cb_probe, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, + .work = SRXAFSCB_Probe, }; /* @@ -82,6 +91,7 @@ static const struct afs_call_type afs_SRXCBProbeUuid = { .deliver = afs_deliver_cb_probe_uuid, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, + .work = SRXAFSCB_ProbeUuid, }; /* @@ -93,6 +103,7 @@ static const struct afs_call_type afs_SRXCBTellMeAboutYourself = { .deliver = afs_deliver_cb_tell_me_about_yourself, .abort_to_error = afs_abort_to_error, .destructor = afs_cm_destructor, + .work = SRXAFSCB_TellMeAboutYourself, }; /* @@ -163,6 +174,7 @@ static void SRXAFSCB_CallBack(struct work_struct *work) afs_send_empty_reply(call); afs_break_callbacks(call->server, call->count, call->request); + afs_put_call(call); _leave(""); } @@ -284,9 +296,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) return -ENOTCONN; call->server = server; - INIT_WORK(&call->work, SRXAFSCB_CallBack); - queue_work(afs_wq, &call->work); - return 0; + return afs_queue_call_work(call); } /* @@ -300,6 +310,7 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) afs_init_callback_state(call->server); afs_send_empty_reply(call); + afs_put_call(call); _leave(""); } @@ -330,9 +341,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call) return -ENOTCONN; call->server = server; - INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); - queue_work(afs_wq, &call->work); - return 0; + return afs_queue_call_work(call); } /* @@ -404,9 +413,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) return -ENOTCONN; call->server = server; - INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); - queue_work(afs_wq, &call->work); - return 0; + return afs_queue_call_work(call); } /* @@ -418,6 +425,7 @@ static void SRXAFSCB_Probe(struct work_struct *work) _enter(""); afs_send_empty_reply(call); + afs_put_call(call); _leave(""); } @@ -437,9 +445,7 @@ static int afs_deliver_cb_probe(struct afs_call *call) /* no unmarshalling required */ call->state = AFS_CALL_REPLYING; - INIT_WORK(&call->work, SRXAFSCB_Probe); - queue_work(afs_wq, &call->work); - return 0; + return afs_queue_call_work(call); } /* @@ -462,6 +468,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work) reply.match = htonl(1); afs_send_simple_reply(call, &reply, sizeof(reply)); + afs_put_call(call); _leave(""); } @@ -520,9 +527,7 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) call->state = AFS_CALL_REPLYING; - INIT_WORK(&call->work, SRXAFSCB_ProbeUuid); - queue_work(afs_wq, &call->work); - return 0; + return afs_queue_call_work(call); } /* @@ -584,7 +589,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) reply.cap.capcount = htonl(1); reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); afs_send_simple_reply(call, &reply, sizeof(reply)); - + afs_put_call(call); _leave(""); } @@ -604,7 +609,5 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call) /* no unmarshalling required */ call->state = AFS_CALL_REPLYING; - INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself); - queue_work(afs_wq, &call->work); - return 0; + return afs_queue_call_work(call); } diff --git a/fs/afs/internal.h b/fs/afs/internal.h index b411670d5f67..65504e218d35 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -66,7 +66,7 @@ enum afs_call_state { struct afs_call { const struct afs_call_type *type; /* type of call */ wait_queue_head_t waitq; /* processes awaiting completion */ - struct work_struct async_work; /* asynchronous work processor */ + struct work_struct async_work; /* async I/O processor */ struct work_struct work; /* actual work processor */ struct rxrpc_call *rxcall; /* RxRPC call handle */ struct key *key; /* security for this call */ @@ -82,6 +82,7 @@ struct afs_call { pgoff_t first; /* first page in mapping to deal with */ pgoff_t last; /* last page in mapping to deal with */ size_t offset; /* offset into received data store */ + atomic_t usage; enum afs_call_state state; int error; /* error code */ u32 abort_code; /* Remote abort ID or 0 */ @@ -115,6 +116,9 @@ struct afs_call_type { /* clean up a call */ void (*destructor)(struct afs_call *call); + + /* Work function */ + void (*work)(struct work_struct *work); }; /* @@ -591,9 +595,12 @@ extern void afs_proc_cell_remove(struct afs_cell *); * rxrpc.c */ extern struct socket *afs_socket; +extern atomic_t afs_outstanding_calls; extern int afs_open_socket(void); extern void afs_close_socket(void); +extern void afs_put_call(struct afs_call *); +extern int afs_queue_call_work(struct afs_call *); extern int afs_make_call(struct in_addr *, struct afs_call *, gfp_t, bool); extern struct afs_call *afs_alloc_flat_call(const struct afs_call_type *, size_t, size_t); diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index ec1e41f929d1..95f42872b787 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -19,9 +19,8 @@ struct socket *afs_socket; /* my RxRPC socket */ static struct workqueue_struct *afs_async_calls; static struct afs_call *afs_spare_incoming_call; -static atomic_t afs_outstanding_calls; +atomic_t afs_outstanding_calls; -static void afs_free_call(struct afs_call *); static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); static int afs_wait_for_call_to_complete(struct afs_call *); static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); @@ -112,9 +111,11 @@ void afs_close_socket(void) { _enter(""); + kernel_listen(afs_socket, 0); + flush_workqueue(afs_async_calls); + if (afs_spare_incoming_call) { - atomic_inc(&afs_outstanding_calls); - afs_free_call(afs_spare_incoming_call); + afs_put_call(afs_spare_incoming_call); afs_spare_incoming_call = NULL; } @@ -123,7 +124,6 @@ void afs_close_socket(void) TASK_UNINTERRUPTIBLE); _debug("no outstanding calls"); - flush_workqueue(afs_async_calls); kernel_sock_shutdown(afs_socket, SHUT_RDWR); flush_workqueue(afs_async_calls); sock_release(afs_socket); @@ -134,44 +134,79 @@ void afs_close_socket(void) } /* - * free a call + * Allocate a call. */ -static void afs_free_call(struct afs_call *call) +static struct afs_call *afs_alloc_call(const struct afs_call_type *type, + gfp_t gfp) { - _debug("DONE %p{%s} [%d]", - call, call->type->name, atomic_read(&afs_outstanding_calls)); + struct afs_call *call; + int o; - ASSERTCMP(call->rxcall, ==, NULL); - ASSERT(!work_pending(&call->async_work)); - ASSERT(call->type->name != NULL); + call = kzalloc(sizeof(*call), gfp); + if (!call) + return NULL; - kfree(call->request); - kfree(call); + call->type = type; + atomic_set(&call->usage, 1); + INIT_WORK(&call->async_work, afs_process_async_call); + init_waitqueue_head(&call->waitq); - if (atomic_dec_and_test(&afs_outstanding_calls)) - wake_up_atomic_t(&afs_outstanding_calls); + o = atomic_inc_return(&afs_outstanding_calls); + trace_afs_call(call, afs_call_trace_alloc, 1, o, + __builtin_return_address(0)); + return call; } /* - * End a call but do not free it + * Dispose of a reference on a call. */ -static void afs_end_call_nofree(struct afs_call *call) +void afs_put_call(struct afs_call *call) { - if (call->rxcall) { - rxrpc_kernel_end_call(afs_socket, call->rxcall); - call->rxcall = NULL; + int n = atomic_dec_return(&call->usage); + int o = atomic_read(&afs_outstanding_calls); + + trace_afs_call(call, afs_call_trace_put, n + 1, o, + __builtin_return_address(0)); + + ASSERTCMP(n, >=, 0); + if (n == 0) { + ASSERT(!work_pending(&call->async_work)); + ASSERT(call->type->name != NULL); + + if (call->rxcall) { + rxrpc_kernel_end_call(afs_socket, call->rxcall); + call->rxcall = NULL; + } + if (call->type->destructor) + call->type->destructor(call); + + kfree(call->request); + kfree(call); + + o = atomic_dec_return(&afs_outstanding_calls); + trace_afs_call(call, afs_call_trace_free, 0, o, + __builtin_return_address(0)); + if (o == 0) + wake_up_atomic_t(&afs_outstanding_calls); } - if (call->type->destructor) - call->type->destructor(call); } /* - * End a call and free it + * Queue the call for actual work. Returns 0 unconditionally for convenience. */ -static void afs_end_call(struct afs_call *call) +int afs_queue_call_work(struct afs_call *call) { - afs_end_call_nofree(call); - afs_free_call(call); + int u = atomic_inc_return(&call->usage); + + trace_afs_call(call, afs_call_trace_work, u, + atomic_read(&afs_outstanding_calls), + __builtin_return_address(0)); + + INIT_WORK(&call->work, call->type->work); + + if (!queue_work(afs_wq, &call->work)) + afs_put_call(call); + return 0; } /* @@ -182,25 +217,19 @@ struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, { struct afs_call *call; - call = kzalloc(sizeof(*call), GFP_NOFS); + call = afs_alloc_call(type, GFP_NOFS); if (!call) goto nomem_call; - _debug("CALL %p{%s} [%d]", - call, type->name, atomic_read(&afs_outstanding_calls)); - atomic_inc(&afs_outstanding_calls); - - call->type = type; - call->request_size = request_size; - call->reply_max = reply_max; - if (request_size) { + call->request_size = request_size; call->request = kmalloc(request_size, GFP_NOFS); if (!call->request) goto nomem_free; } if (reply_max) { + call->reply_max = reply_max; call->buffer = kmalloc(reply_max, GFP_NOFS); if (!call->buffer) goto nomem_free; @@ -210,7 +239,7 @@ struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, return call; nomem_free: - afs_free_call(call); + afs_put_call(call); nomem_call: return NULL; } @@ -315,7 +344,6 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, atomic_read(&afs_outstanding_calls)); call->async = async; - INIT_WORK(&call->async_work, afs_process_async_call); memset(&srx, 0, sizeof(srx)); srx.srx_family = AF_RXRPC; @@ -378,7 +406,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, error_do_abort: rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT, -ret, "KSD"); error_kill_call: - afs_end_call(call); + afs_put_call(call); _leave(" = %d", ret); return ret; } @@ -448,7 +476,7 @@ static void afs_deliver_to_call(struct afs_call *call) done: if (call->state == AFS_CALL_COMPLETE && call->incoming) - afs_end_call(call); + afs_put_call(call); out: _leave(""); return; @@ -505,7 +533,7 @@ static int afs_wait_for_call_to_complete(struct afs_call *call) } _debug("call complete"); - afs_end_call(call); + afs_put_call(call); _leave(" = %d", ret); return ret; } @@ -529,14 +557,25 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, unsigned long call_user_ID) { struct afs_call *call = (struct afs_call *)call_user_ID; + int u; trace_afs_notify_call(rxcall, call); call->need_attention = true; - queue_work(afs_async_calls, &call->async_work); + + u = __atomic_add_unless(&call->usage, 1, 0); + if (u != 0) { + trace_afs_call(call, afs_call_trace_wake, u, + atomic_read(&afs_outstanding_calls), + __builtin_return_address(0)); + + if (!queue_work(afs_async_calls, &call->async_work)) + afs_put_call(call); + } } /* - * delete an asynchronous call + * Delete an asynchronous call. The work item carries a ref to the call struct + * that we need to release. */ static void afs_delete_async_call(struct work_struct *work) { @@ -544,13 +583,14 @@ static void afs_delete_async_call(struct work_struct *work) _enter(""); - afs_free_call(call); + afs_put_call(call); _leave(""); } /* - * perform processing on an asynchronous call + * Perform I/O processing on an asynchronous call. The work item carries a ref + * to the call struct that we either need to release or to pass on. */ static void afs_process_async_call(struct work_struct *work) { @@ -566,15 +606,16 @@ static void afs_process_async_call(struct work_struct *work) if (call->state == AFS_CALL_COMPLETE) { call->reply = NULL; - /* kill the call */ - afs_end_call_nofree(call); - - /* we can't just delete the call because the work item may be - * queued */ + /* We have two refs to release - one from the alloc and one + * queued with the work item - and we can't just deallocate the + * call because the work item may be queued again. + */ call->async_work.func = afs_delete_async_call; - queue_work(afs_async_calls, &call->async_work); + if (!queue_work(afs_async_calls, &call->async_work)) + afs_put_call(call); } + afs_put_call(call); _leave(""); } @@ -594,12 +635,10 @@ static void afs_charge_preallocation(struct work_struct *work) for (;;) { if (!call) { - call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); + call = afs_alloc_call(&afs_RXCMxxxx, GFP_KERNEL); if (!call) break; - INIT_WORK(&call->async_work, afs_process_async_call); - call->type = &afs_RXCMxxxx; call->async = true; call->state = AFS_CALL_AWAIT_OP_ID; init_waitqueue_head(&call->waitq); @@ -624,9 +663,8 @@ static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, { struct afs_call *call = (struct afs_call *)user_call_ID; - atomic_inc(&afs_outstanding_calls); call->rxcall = NULL; - afs_free_call(call); + afs_put_call(call); } /* @@ -635,7 +673,6 @@ static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, unsigned long user_call_ID) { - atomic_inc(&afs_outstanding_calls); queue_work(afs_wq, &afs_charge_preallocation_work); } @@ -699,7 +736,6 @@ void afs_send_empty_reply(struct afs_call *call) rxrpc_kernel_abort_call(afs_socket, call->rxcall, RX_USER_ABORT, ENOMEM, "KOO"); default: - afs_end_call(call); _leave(" [error]"); return; } @@ -738,7 +774,6 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) rxrpc_kernel_abort_call(afs_socket, call->rxcall, RX_USER_ABORT, ENOMEM, "KOO"); } - afs_end_call(call); _leave(" [error]"); } diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 845907b04ff4..8b95c16b7045 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -16,6 +16,51 @@ #include +/* + * Define enums for tracing information. + */ +#ifndef __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY +#define __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY + +enum afs_call_trace { + afs_call_trace_alloc, + afs_call_trace_free, + afs_call_trace_put, + afs_call_trace_wake, + afs_call_trace_work, +}; + +#endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ + +/* + * Declare tracing information enums and their string mappings for display. + */ +#define afs_call_traces \ + EM(afs_call_trace_alloc, "ALLOC") \ + EM(afs_call_trace_free, "FREE ") \ + EM(afs_call_trace_put, "PUT ") \ + EM(afs_call_trace_wake, "WAKE ") \ + E_(afs_call_trace_work, "WORK ") + +/* + * Export enum symbols via userspace. + */ +#undef EM +#undef E_ +#define EM(a, b) TRACE_DEFINE_ENUM(a); +#define E_(a, b) TRACE_DEFINE_ENUM(a); + +afs_call_traces; + +/* + * Now redefine the EM() and E_() macros to map the enums to the strings that + * will be printed in the output. + */ +#undef EM +#undef E_ +#define EM(a, b) { a, b }, +#define E_(a, b) { a, b } + TRACE_EVENT(afs_recv_data, TP_PROTO(struct afs_call *call, unsigned count, unsigned offset, bool want_more, int ret), @@ -103,6 +148,36 @@ TRACE_EVENT(afs_cb_call, __entry->op) ); +TRACE_EVENT(afs_call, + TP_PROTO(struct afs_call *call, enum afs_call_trace op, + int usage, int outstanding, const void *where), + + TP_ARGS(call, op, usage, outstanding, where), + + TP_STRUCT__entry( + __field(struct afs_call *, call ) + __field(int, op ) + __field(int, usage ) + __field(int, outstanding ) + __field(const void *, where ) + ), + + TP_fast_assign( + __entry->call = call; + __entry->op = op; + __entry->usage = usage; + __entry->outstanding = outstanding; + __entry->where = where; + ), + + TP_printk("c=%p %s u=%d o=%d sp=%pSR", + __entry->call, + __print_symbolic(__entry->op, afs_call_traces), + __entry->usage, + __entry->outstanding, + __entry->where) + ); + #endif /* _TRACE_AFS_H */ /* This part must be outside protection */ -- cgit v1.2.3-59-g8ed1b From 51c89e6a3bf68d544e29b234c2cef6ffb73277a1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 13 Jan 2017 14:46:19 +0000 Subject: afs: Conditionalise a new unused variable The bulk readpages support introduced a harmless warning: fs/afs/file.c: In function 'afs_readpages_page_done': fs/afs/file.c:270:20: error: unused variable 'vnode' [-Werror=unused-variable] This adds an #ifdef to match the user of that variable. The user of the variable has to be conditional because it accesses a member of a struct that is also conditional. Fixes: 91b467e0a3f5 ("afs: Make afs_readpages() fetch data in bulk") Signed-off-by: Arnd Bergmann Signed-off-by: David Howells Signed-off-by: David S. Miller --- fs/afs/file.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/afs/file.c b/fs/afs/file.c index 82897a78abc7..ba7b71fba34b 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -267,7 +267,9 @@ static int afs_readpage(struct file *file, struct page *page) */ static void afs_readpages_page_done(struct afs_call *call, struct afs_read *req) { +#ifdef CONFIG_AFS_FSCACHE struct afs_vnode *vnode = call->reply; +#endif struct page *page = req->pages[req->index]; req->pages[req->index] = NULL; -- cgit v1.2.3-59-g8ed1b From ff548773106ec7f8031bc6172e0234bd2a02c19c Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 10 Feb 2017 16:34:07 +0000 Subject: afs: Move UUID struct to linux/uuid.h Move the afs_uuid struct to linux/uuid.h, rename it to uuid_v1 and change the u16/u32 fields to __be16/__be32 instead so that the structure can be cast to a 16-octet network-order buffer. Signed-off-by: David Howells Reviewed-by: Arnd Bergmann request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); + call->request = kmalloc(sizeof(struct uuid_v1), GFP_KERNEL); if (!call->request) return -ENOMEM; b = call->buffer; r = call->request; - r->time_low = ntohl(b[0]); - r->time_mid = ntohl(b[1]); - r->time_hi_and_version = ntohl(b[2]); + r->time_low = b[0]; + r->time_mid = htons(ntohl(b[1])); + r->time_hi_and_version = htons(ntohl(b[2])); r->clock_seq_hi_and_reserved = ntohl(b[3]); r->clock_seq_low = ntohl(b[4]); @@ -454,7 +454,7 @@ static int afs_deliver_cb_probe(struct afs_call *call) static void SRXAFSCB_ProbeUuid(struct work_struct *work) { struct afs_call *call = container_of(work, struct afs_call, work); - struct afs_uuid *r = call->request; + struct uuid_v1 *r = call->request; struct { __be32 match; @@ -477,7 +477,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work) */ static int afs_deliver_cb_probe_uuid(struct afs_call *call) { - struct afs_uuid *r; + struct uuid_v1 *r; unsigned loop; __be32 *b; int ret; @@ -503,15 +503,15 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) } _debug("unmarshall UUID"); - call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); + call->request = kmalloc(sizeof(struct uuid_v1), GFP_KERNEL); if (!call->request) return -ENOMEM; b = call->buffer; r = call->request; - r->time_low = ntohl(b[0]); - r->time_mid = ntohl(b[1]); - r->time_hi_and_version = ntohl(b[2]); + r->time_low = b[0]; + r->time_mid = htons(ntohl(b[1])); + r->time_hi_and_version = htons(ntohl(b[2])); r->clock_seq_hi_and_reserved = ntohl(b[3]); r->clock_seq_low = ntohl(b[4]); @@ -569,9 +569,9 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) memset(&reply, 0, sizeof(reply)); reply.ia.nifs = htonl(nifs); - reply.ia.uuid[0] = htonl(afs_uuid.time_low); - reply.ia.uuid[1] = htonl(afs_uuid.time_mid); - reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version); + reply.ia.uuid[0] = afs_uuid.time_low; + reply.ia.uuid[1] = htonl(ntohs(afs_uuid.time_mid)); + reply.ia.uuid[2] = htonl(ntohs(afs_uuid.time_hi_and_version)); reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved); reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low); for (loop = 0; loop < 6; loop++) diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 65504e218d35..79061fa17168 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "afs.h" @@ -407,30 +408,6 @@ struct afs_interface { unsigned mtu; /* MTU of interface */ }; -/* - * UUID definition [internet draft] - * - the timestamp is a 60-bit value, split 32/16/12, and goes in 100ns - * increments since midnight 15th October 1582 - * - add AFS_UUID_TO_UNIX_TIME to convert unix time in 100ns units to UUID - * time - * - the clock sequence is a 14-bit counter to avoid duplicate times - */ -struct afs_uuid { - u32 time_low; /* low part of timestamp */ - u16 time_mid; /* mid part of timestamp */ - u16 time_hi_and_version; /* high part of timestamp and version */ -#define AFS_UUID_TO_UNIX_TIME 0x01b21dd213814000ULL -#define AFS_UUID_TIMEHI_MASK 0x0fff -#define AFS_UUID_VERSION_TIME 0x1000 /* time-based UUID */ -#define AFS_UUID_VERSION_NAME 0x3000 /* name-based UUID */ -#define AFS_UUID_VERSION_RANDOM 0x4000 /* (pseudo-)random generated UUID */ - u8 clock_seq_hi_and_reserved; /* clock seq hi and variant */ -#define AFS_UUID_CLOCKHI_MASK 0x3f -#define AFS_UUID_VARIANT_STD 0x80 - u8 clock_seq_low; /* clock seq low */ - u8 node[6]; /* spatially unique node ID (MAC addr) */ -}; - /*****************************************************************************/ /* * cache.c @@ -565,7 +542,7 @@ extern int afs_drop_inode(struct inode *); * main.c */ extern struct workqueue_struct *afs_wq; -extern struct afs_uuid afs_uuid; +extern struct uuid_v1 afs_uuid; /* * misc.c diff --git a/fs/afs/main.c b/fs/afs/main.c index f8188feb03ad..a07c14df3fd1 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c @@ -31,7 +31,7 @@ static char *rootcell; module_param(rootcell, charp, 0); MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); -struct afs_uuid afs_uuid; +struct uuid_v1 afs_uuid; struct workqueue_struct *afs_wq; /* @@ -41,7 +41,7 @@ static int __init afs_get_client_UUID(void) { struct timespec ts; u64 uuidtime; - u16 clockseq; + u16 clockseq, hi_v; int ret; /* read the MAC address of one of the external interfaces and construct @@ -53,22 +53,23 @@ static int __init afs_get_client_UUID(void) getnstimeofday(&ts); uuidtime = (u64) ts.tv_sec * 1000 * 1000 * 10; uuidtime += ts.tv_nsec / 100; - uuidtime += AFS_UUID_TO_UNIX_TIME; - afs_uuid.time_low = uuidtime; - afs_uuid.time_mid = uuidtime >> 32; - afs_uuid.time_hi_and_version = (uuidtime >> 48) & AFS_UUID_TIMEHI_MASK; - afs_uuid.time_hi_and_version |= AFS_UUID_VERSION_TIME; + uuidtime += UUID_TO_UNIX_TIME; + afs_uuid.time_low = htonl(uuidtime); + afs_uuid.time_mid = htons(uuidtime >> 32); + hi_v = (uuidtime >> 48) & UUID_TIMEHI_MASK; + hi_v |= UUID_VERSION_TIME; + afs_uuid.time_hi_and_version = htons(hi_v); get_random_bytes(&clockseq, 2); afs_uuid.clock_seq_low = clockseq; afs_uuid.clock_seq_hi_and_reserved = - (clockseq >> 8) & AFS_UUID_CLOCKHI_MASK; - afs_uuid.clock_seq_hi_and_reserved |= AFS_UUID_VARIANT_STD; + (clockseq >> 8) & UUID_CLOCKHI_MASK; + afs_uuid.clock_seq_hi_and_reserved |= UUID_VARIANT_STD; _debug("AFS UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - afs_uuid.time_low, - afs_uuid.time_mid, - afs_uuid.time_hi_and_version, + ntohl(afs_uuid.time_low), + ntohs(afs_uuid.time_mid), + ntohs(afs_uuid.time_hi_and_version), afs_uuid.clock_seq_hi_and_reserved, afs_uuid.clock_seq_low, afs_uuid.node[0], afs_uuid.node[1], afs_uuid.node[2], diff --git a/include/linux/uuid.h b/include/linux/uuid.h index 2d095fc60204..4dff73a89758 100644 --- a/include/linux/uuid.h +++ b/include/linux/uuid.h @@ -18,6 +18,30 @@ #include +/* + * V1 (time-based) UUID definition [RFC 4122]. + * - the timestamp is a 60-bit value, split 32/16/12, and goes in 100ns + * increments since midnight 15th October 1582 + * - add AFS_UUID_TO_UNIX_TIME to convert unix time in 100ns units to UUID + * time + * - the clock sequence is a 14-bit counter to avoid duplicate times + */ +struct uuid_v1 { + __be32 time_low; /* low part of timestamp */ + __be16 time_mid; /* mid part of timestamp */ + __be16 time_hi_and_version; /* high part of timestamp and version */ +#define UUID_TO_UNIX_TIME 0x01b21dd213814000ULL +#define UUID_TIMEHI_MASK 0x0fff +#define UUID_VERSION_TIME 0x1000 /* time-based UUID */ +#define UUID_VERSION_NAME 0x3000 /* name-based UUID */ +#define UUID_VERSION_RANDOM 0x4000 /* (pseudo-)random generated UUID */ + u8 clock_seq_hi_and_reserved; /* clock seq hi and variant */ +#define UUID_CLOCKHI_MASK 0x3f +#define UUID_VARIANT_STD 0x80 + u8 clock_seq_low; /* clock seq low */ + u8 node[6]; /* spatially unique node ID (MAC addr) */ +}; + /* * The length of a UUID string ("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee") * not including trailing NUL. -- cgit v1.2.3-59-g8ed1b From b4db2b35fc444409daf483006111a2a705550fff Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 10 Feb 2017 16:34:07 +0000 Subject: afs: Use core kernel UUID generation AFS uses a time based UUID to identify the host itself. This requires getting a timestamp which is currently done through the getnstimeofday() interface that we want to eventually get rid of. Instead of replacing it with a ktime-based interface, simply remove the entire function and use generate_random_uuid() instead, which has a v4 ("completely random") UUID instead of the time-based one. Signed-off-by: Arnd Bergmann Signed-off-by: David Howells --- fs/afs/internal.h | 11 +++++------ fs/afs/main.c | 48 +----------------------------------------------- fs/afs/netdevices.c | 21 --------------------- 3 files changed, 6 insertions(+), 74 deletions(-) (limited to 'fs') diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 79061fa17168..8acf3670e756 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -560,6 +560,11 @@ extern struct vfsmount *afs_d_automount(struct path *); extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); extern void afs_mntpt_kill_timer(void); +/* + * netdevices.c + */ +extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool); + /* * proc.c */ @@ -623,12 +628,6 @@ extern void __exit afs_purge_servers(void); extern int afs_fs_init(void); extern void afs_fs_exit(void); -/* - * use-rtnetlink.c - */ -extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool); -extern int afs_get_MAC_address(u8 *, size_t); - /* * vlclient.c */ diff --git a/fs/afs/main.c b/fs/afs/main.c index a07c14df3fd1..51d7d17bca57 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c @@ -34,50 +34,6 @@ MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); struct uuid_v1 afs_uuid; struct workqueue_struct *afs_wq; -/* - * get a client UUID - */ -static int __init afs_get_client_UUID(void) -{ - struct timespec ts; - u64 uuidtime; - u16 clockseq, hi_v; - int ret; - - /* read the MAC address of one of the external interfaces and construct - * a UUID from it */ - ret = afs_get_MAC_address(afs_uuid.node, sizeof(afs_uuid.node)); - if (ret < 0) - return ret; - - getnstimeofday(&ts); - uuidtime = (u64) ts.tv_sec * 1000 * 1000 * 10; - uuidtime += ts.tv_nsec / 100; - uuidtime += UUID_TO_UNIX_TIME; - afs_uuid.time_low = htonl(uuidtime); - afs_uuid.time_mid = htons(uuidtime >> 32); - hi_v = (uuidtime >> 48) & UUID_TIMEHI_MASK; - hi_v |= UUID_VERSION_TIME; - afs_uuid.time_hi_and_version = htons(hi_v); - - get_random_bytes(&clockseq, 2); - afs_uuid.clock_seq_low = clockseq; - afs_uuid.clock_seq_hi_and_reserved = - (clockseq >> 8) & UUID_CLOCKHI_MASK; - afs_uuid.clock_seq_hi_and_reserved |= UUID_VARIANT_STD; - - _debug("AFS UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - ntohl(afs_uuid.time_low), - ntohs(afs_uuid.time_mid), - ntohs(afs_uuid.time_hi_and_version), - afs_uuid.clock_seq_hi_and_reserved, - afs_uuid.clock_seq_low, - afs_uuid.node[0], afs_uuid.node[1], afs_uuid.node[2], - afs_uuid.node[3], afs_uuid.node[4], afs_uuid.node[5]); - - return 0; -} - /* * initialise the AFS client FS module */ @@ -87,9 +43,7 @@ static int __init afs_init(void) printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n"); - ret = afs_get_client_UUID(); - if (ret < 0) - return ret; + generate_random_uuid((unsigned char *)&afs_uuid); /* create workqueue */ ret = -ENOMEM; diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c index 7ad36506c256..40b2bab3e401 100644 --- a/fs/afs/netdevices.c +++ b/fs/afs/netdevices.c @@ -11,27 +11,6 @@ #include #include "internal.h" -/* - * get a MAC address from a random ethernet interface that has a real one - * - the buffer will normally be 6 bytes in size - */ -int afs_get_MAC_address(u8 *mac, size_t maclen) -{ - struct net_device *dev; - int ret = -ENODEV; - - BUG_ON(maclen != ETH_ALEN); - - rtnl_lock(); - dev = __dev_getfirstbyhwtype(&init_net, ARPHRD_ETHER); - if (dev) { - memcpy(mac, dev->dev_addr, maclen); - ret = 0; - } - rtnl_unlock(); - return ret; -} - /* * get a list of this system's interface IPv4 addresses, netmasks and MTUs * - maxbufs must be at least 1 -- cgit v1.2.3-59-g8ed1b From 98687f426bb3e93b9dbbfb614ba331192beae482 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 11 Feb 2017 19:26:45 +0800 Subject: gfs2: Use rhashtable walk interface in glock_hash_walk The function glock_hash_walk walks the rhashtable by hand. This is broken because if it catches the hash table in the middle of a rehash, then it will miss entries. This patch replaces the manual walk by using the rhashtable walk interface. Fixes: 88ffbf3e037e ("GFS2: Use resizable hash table for glocks") Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- fs/gfs2/glock.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 94f50cac91c6..70e94170af85 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1420,26 +1420,32 @@ static struct shrinker glock_shrinker = { * @sdp: the filesystem * @bucket: the bucket * + * Note that the function can be called multiple times on the same + * object. So the user must ensure that the function can cope with + * that. */ static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp) { struct gfs2_glock *gl; - struct rhash_head *pos; - const struct bucket_table *tbl; - int i; + struct rhashtable_iter iter; - rcu_read_lock(); - tbl = rht_dereference_rcu(gl_hash_table.tbl, &gl_hash_table); - for (i = 0; i < tbl->size; i++) { - rht_for_each_entry_rcu(gl, pos, tbl, i, gl_node) { + rhashtable_walk_enter(&gl_hash_table, &iter); + + do { + gl = ERR_PTR(rhashtable_walk_start(&iter)); + if (gl) + continue; + + while ((gl = rhashtable_walk_next(&iter)) && !IS_ERR(gl)) if ((gl->gl_name.ln_sbd == sdp) && lockref_get_not_dead(&gl->gl_lockref)) examiner(gl); - } - } - rcu_read_unlock(); - cond_resched(); + + rhashtable_walk_stop(&iter); + } while (cond_resched(), gl == ERR_PTR(-EAGAIN)); + + rhashtable_walk_exit(&iter); } /** -- cgit v1.2.3-59-g8ed1b