Commit 4343d008 authored by David Howells's avatar David Howells

afs: Get rid of the afs_writeback record

Get rid of the afs_writeback record that kAFS is using to match keys with
writes made by that key.

Instead, keep a list of keys that have a file open for writing and/or
sync'ing and iterate through those.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 215804a9
...@@ -23,7 +23,6 @@ static int afs_readpage(struct file *file, struct page *page); ...@@ -23,7 +23,6 @@ static int afs_readpage(struct file *file, struct page *page);
static void afs_invalidatepage(struct page *page, unsigned int offset, static void afs_invalidatepage(struct page *page, unsigned int offset,
unsigned int length); unsigned int length);
static int afs_releasepage(struct page *page, gfp_t gfp_flags); static int afs_releasepage(struct page *page, gfp_t gfp_flags);
static int afs_launder_page(struct page *page);
static int afs_readpages(struct file *filp, struct address_space *mapping, static int afs_readpages(struct file *filp, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages); struct list_head *pages, unsigned nr_pages);
...@@ -62,6 +61,50 @@ const struct address_space_operations afs_fs_aops = { ...@@ -62,6 +61,50 @@ const struct address_space_operations afs_fs_aops = {
.writepages = afs_writepages, .writepages = afs_writepages,
}; };
/*
* Discard a pin on a writeback key.
*/
void afs_put_wb_key(struct afs_wb_key *wbk)
{
if (refcount_dec_and_test(&wbk->usage)) {
key_put(wbk->key);
kfree(wbk);
}
}
/*
* Cache key for writeback.
*/
int afs_cache_wb_key(struct afs_vnode *vnode, struct afs_file *af)
{
struct afs_wb_key *wbk, *p;
wbk = kzalloc(sizeof(struct afs_wb_key), GFP_KERNEL);
if (!wbk)
return -ENOMEM;
refcount_set(&wbk->usage, 2);
wbk->key = af->key;
spin_lock(&vnode->wb_lock);
list_for_each_entry(p, &vnode->wb_keys, vnode_link) {
if (p->key == wbk->key)
goto found;
}
key_get(wbk->key);
list_add_tail(&wbk->vnode_link, &vnode->wb_keys);
spin_unlock(&vnode->wb_lock);
af->wb = wbk;
return 0;
found:
refcount_inc(&p->usage);
spin_unlock(&vnode->wb_lock);
af->wb = p;
kfree(wbk);
return 0;
}
/* /*
* open an AFS file or directory and attach a key to it * open an AFS file or directory and attach a key to it
*/ */
...@@ -85,12 +128,18 @@ int afs_open(struct inode *inode, struct file *file) ...@@ -85,12 +128,18 @@ int afs_open(struct inode *inode, struct file *file)
ret = -ENOMEM; ret = -ENOMEM;
goto error_key; goto error_key;
} }
af->key = key;
ret = afs_validate(vnode, key); ret = afs_validate(vnode, key);
if (ret < 0) if (ret < 0)
goto error_af; goto error_af;
af->key = key; if (file->f_mode & FMODE_WRITE) {
ret = afs_cache_wb_key(vnode, af);
if (ret < 0)
goto error_af;
}
file->private_data = af; file->private_data = af;
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -115,8 +164,11 @@ int afs_release(struct inode *inode, struct file *file) ...@@ -115,8 +164,11 @@ int afs_release(struct inode *inode, struct file *file)
_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
file->private_data = NULL; file->private_data = NULL;
if (af->wb)
afs_put_wb_key(af->wb);
key_put(af->key); key_put(af->key);
kfree(af); kfree(af);
afs_prune_wb_keys(vnode);
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
} }
...@@ -516,16 +568,6 @@ static int afs_readpages(struct file *file, struct address_space *mapping, ...@@ -516,16 +568,6 @@ static int afs_readpages(struct file *file, struct address_space *mapping,
return ret; return ret;
} }
/*
* write back a dirty page
*/
static int afs_launder_page(struct page *page)
{
_enter("{%lu}", page->index);
return 0;
}
/* /*
* invalidate part or all of a page * invalidate part or all of a page
* - release a page and clean up its private data if offset is 0 (indicating * - release a page and clean up its private data if offset is 0 (indicating
...@@ -534,8 +576,6 @@ static int afs_launder_page(struct page *page) ...@@ -534,8 +576,6 @@ static int afs_launder_page(struct page *page)
static void afs_invalidatepage(struct page *page, unsigned int offset, static void afs_invalidatepage(struct page *page, unsigned int offset,
unsigned int length) unsigned int length)
{ {
struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
_enter("{%lu},%u,%u", page->index, offset, length); _enter("{%lu},%u,%u", page->index, offset, length);
BUG_ON(!PageLocked(page)); BUG_ON(!PageLocked(page));
...@@ -551,13 +591,8 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, ...@@ -551,13 +591,8 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
#endif #endif
if (PagePrivate(page)) { if (PagePrivate(page)) {
if (wb && !PageWriteback(page)) { set_page_private(page, 0);
set_page_private(page, 0); ClearPagePrivate(page);
afs_put_writeback(wb);
}
if (!page_private(page))
ClearPagePrivate(page);
} }
} }
...@@ -570,7 +605,6 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, ...@@ -570,7 +605,6 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
*/ */
static int afs_releasepage(struct page *page, gfp_t gfp_flags) static int afs_releasepage(struct page *page, gfp_t gfp_flags)
{ {
struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
_enter("{{%x:%u}[%lu],%lx},%x", _enter("{{%x:%u}[%lu],%lx},%x",
...@@ -587,10 +621,7 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags) ...@@ -587,10 +621,7 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
#endif #endif
if (PagePrivate(page)) { if (PagePrivate(page)) {
if (wb) { set_page_private(page, 0);
set_page_private(page, 0);
afs_put_writeback(wb);
}
ClearPagePrivate(page); ClearPagePrivate(page);
} }
......
...@@ -1119,18 +1119,18 @@ static const struct afs_call_type afs_RXFSStoreData64 = { ...@@ -1119,18 +1119,18 @@ static const struct afs_call_type afs_RXFSStoreData64 = {
* store a set of pages to a very large file * store a set of pages to a very large file
*/ */
static int afs_fs_store_data64(struct afs_fs_cursor *fc, static int afs_fs_store_data64(struct afs_fs_cursor *fc,
struct afs_writeback *wb, struct address_space *mapping,
pgoff_t first, pgoff_t last, pgoff_t first, pgoff_t last,
unsigned offset, unsigned to, unsigned offset, unsigned to,
loff_t size, loff_t pos, loff_t i_size) loff_t size, loff_t pos, loff_t i_size)
{ {
struct afs_vnode *vnode = wb->vnode; struct afs_vnode *vnode = fc->vnode;
struct afs_call *call; struct afs_call *call;
struct afs_net *net = afs_v2net(vnode); struct afs_net *net = afs_v2net(vnode);
__be32 *bp; __be32 *bp;
_enter(",%x,{%x:%u},,", _enter(",%x,{%x:%u},,",
key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
call = afs_alloc_flat_call(net, &afs_RXFSStoreData64, call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
(4 + 6 + 3 * 2) * 4, (4 + 6 + 3 * 2) * 4,
...@@ -1138,10 +1138,9 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, ...@@ -1138,10 +1138,9 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
if (!call) if (!call)
return -ENOMEM; return -ENOMEM;
call->wb = wb; call->key = fc->key;
call->key = wb->key; call->mapping = mapping;
call->reply[0] = vnode; call->reply[0] = vnode;
call->mapping = vnode->vfs_inode.i_mapping;
call->first = first; call->first = first;
call->last = last; call->last = last;
call->first_offset = offset; call->first_offset = offset;
...@@ -1177,18 +1176,18 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, ...@@ -1177,18 +1176,18 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
/* /*
* store a set of pages * store a set of pages
*/ */
int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb, int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
pgoff_t first, pgoff_t last, pgoff_t first, pgoff_t last,
unsigned offset, unsigned to) unsigned offset, unsigned to)
{ {
struct afs_vnode *vnode = wb->vnode; struct afs_vnode *vnode = fc->vnode;
struct afs_call *call; struct afs_call *call;
struct afs_net *net = afs_v2net(vnode); struct afs_net *net = afs_v2net(vnode);
loff_t size, pos, i_size; loff_t size, pos, i_size;
__be32 *bp; __be32 *bp;
_enter(",%x,{%x:%u},,", _enter(",%x,{%x:%u},,",
key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
size = (loff_t)to - (loff_t)offset; size = (loff_t)to - (loff_t)offset;
if (first != last) if (first != last)
...@@ -1205,7 +1204,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb, ...@@ -1205,7 +1204,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb,
(unsigned long long) i_size); (unsigned long long) i_size);
if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
return afs_fs_store_data64(fc, wb, first, last, offset, to, return afs_fs_store_data64(fc, mapping, first, last, offset, to,
size, pos, i_size); size, pos, i_size);
call = afs_alloc_flat_call(net, &afs_RXFSStoreData, call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
...@@ -1214,10 +1213,9 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb, ...@@ -1214,10 +1213,9 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb,
if (!call) if (!call)
return -ENOMEM; return -ENOMEM;
call->wb = wb; call->key = fc->key;
call->key = wb->key; call->mapping = mapping;
call->reply[0] = vnode; call->reply[0] = vnode;
call->mapping = vnode->vfs_inode.i_mapping;
call->first = first; call->first = first;
call->last = last; call->last = last;
call->first_offset = offset; call->first_offset = offset;
......
...@@ -482,7 +482,12 @@ void afs_evict_inode(struct inode *inode) ...@@ -482,7 +482,12 @@ void afs_evict_inode(struct inode *inode)
vnode->cb_interest = NULL; vnode->cb_interest = NULL;
} }
ASSERT(list_empty(&vnode->writebacks)); while (!list_empty(&vnode->wb_keys)) {
struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next,
struct afs_wb_key, vnode_link);
list_del(&wbk->vnode_link);
afs_put_wb_key(wbk);
}
#ifdef CONFIG_AFS_FSCACHE #ifdef CONFIG_AFS_FSCACHE
fscache_relinquish_cookie(vnode->cache, 0); fscache_relinquish_cookie(vnode->cache, 0);
...@@ -514,10 +519,8 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -514,10 +519,8 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
} }
/* flush any dirty data outstanding on a regular file */ /* flush any dirty data outstanding on a regular file */
if (S_ISREG(vnode->vfs_inode.i_mode)) { if (S_ISREG(vnode->vfs_inode.i_mode))
filemap_write_and_wait(vnode->vfs_inode.i_mapping); filemap_write_and_wait(vnode->vfs_inode.i_mapping);
afs_writeback_all(vnode);
}
if (attr->ia_valid & ATTR_FILE) { if (attr->ia_valid & ATTR_FILE) {
key = afs_file_key(attr->ia_file); key = afs_file_key(attr->ia_file);
......
...@@ -89,8 +89,7 @@ struct afs_call { ...@@ -89,8 +89,7 @@ struct afs_call {
struct afs_server *cm_server; /* Server affected by incoming CM call */ struct afs_server *cm_server; /* Server affected by incoming CM call */
struct afs_cb_interest *cbi; /* Callback interest for server used */ struct afs_cb_interest *cbi; /* Callback interest for server used */
void *request; /* request data (first part) */ void *request; /* request data (first part) */
struct address_space *mapping; /* page set */ struct address_space *mapping; /* Pages being written from */
struct afs_writeback *wb; /* writeback being performed */
void *buffer; /* reply receive buffer */ void *buffer; /* reply receive buffer */
void *reply[4]; /* Where to put the reply */ void *reply[4]; /* Where to put the reply */
pgoff_t first; /* first page in mapping to deal with */ pgoff_t first; /* first page in mapping to deal with */
...@@ -138,11 +137,21 @@ struct afs_call_type { ...@@ -138,11 +137,21 @@ struct afs_call_type {
void (*work)(struct work_struct *work); void (*work)(struct work_struct *work);
}; };
/*
* Key available for writeback on a file.
*/
struct afs_wb_key {
refcount_t usage;
struct key *key;
struct list_head vnode_link; /* Link in vnode->wb_keys */
};
/* /*
* AFS open file information record. Pointed to by file->private_data. * AFS open file information record. Pointed to by file->private_data.
*/ */
struct afs_file { struct afs_file {
struct key *key; /* The key this file was opened with */ struct key *key; /* The key this file was opened with */
struct afs_wb_key *wb; /* Writeback key record for this file */
}; };
static inline struct key *afs_file_key(struct file *file) static inline struct key *afs_file_key(struct file *file)
...@@ -167,32 +176,6 @@ struct afs_read { ...@@ -167,32 +176,6 @@ struct afs_read {
struct page *pages[]; struct page *pages[];
}; };
/*
* record of an outstanding writeback on a vnode
*/
struct afs_writeback {
struct list_head link; /* link in vnode->writebacks */
struct work_struct writer; /* work item to perform the writeback */
struct afs_vnode *vnode; /* vnode to which this write applies */
struct key *key; /* owner of this write */
wait_queue_head_t waitq; /* completion and ready wait queue */
pgoff_t first; /* first page in batch */
pgoff_t point; /* last page in current store op */
pgoff_t last; /* last page in batch (inclusive) */
unsigned offset_first; /* offset into first page of start of write */
unsigned to_last; /* offset into last page of end of write */
int num_conflicts; /* count of conflicting writes in list */
int usage;
bool conflicts; /* T if has dependent conflicts */
enum {
AFS_WBACK_SYNCING, /* synchronisation being performed */
AFS_WBACK_PENDING, /* write pending */
AFS_WBACK_CONFLICTING, /* conflicting writes posted */
AFS_WBACK_WRITING, /* writing back */
AFS_WBACK_COMPLETE /* the writeback record has been unlinked */
} state __attribute__((packed));
};
/* /*
* AFS superblock private data * AFS superblock private data
* - there's one superblock per volume * - there's one superblock per volume
...@@ -460,7 +443,7 @@ struct afs_vnode { ...@@ -460,7 +443,7 @@ struct afs_vnode {
struct afs_permits *permit_cache; /* cache of permits so far obtained */ struct afs_permits *permit_cache; /* cache of permits so far obtained */
struct mutex io_lock; /* Lock for serialising I/O on this mutex */ struct mutex io_lock; /* Lock for serialising I/O on this mutex */
struct mutex validate_lock; /* lock for validating this vnode */ struct mutex validate_lock; /* lock for validating this vnode */
spinlock_t writeback_lock; /* lock for writebacks */ spinlock_t wb_lock; /* lock for wb_keys */
spinlock_t lock; /* waitqueue/flags lock */ spinlock_t lock; /* waitqueue/flags lock */
unsigned long flags; unsigned long flags;
#define AFS_VNODE_CB_PROMISED 0 /* Set if vnode has a callback promise */ #define AFS_VNODE_CB_PROMISED 0 /* Set if vnode has a callback promise */
...@@ -476,7 +459,7 @@ struct afs_vnode { ...@@ -476,7 +459,7 @@ struct afs_vnode {
#define AFS_VNODE_AUTOCELL 10 /* set if Vnode is an auto mount point */ #define AFS_VNODE_AUTOCELL 10 /* set if Vnode is an auto mount point */
#define AFS_VNODE_PSEUDODIR 11 /* set if Vnode is a pseudo directory */ #define AFS_VNODE_PSEUDODIR 11 /* set if Vnode is a pseudo directory */
struct list_head writebacks; /* alterations in pagecache that need writing */ struct list_head wb_keys; /* List of keys available for writeback */
struct list_head pending_locks; /* locks waiting to be granted */ struct list_head pending_locks; /* locks waiting to be granted */
struct list_head granted_locks; /* locks granted on this file */ struct list_head granted_locks; /* locks granted on this file */
struct delayed_work lock_work; /* work to be done in locking */ struct delayed_work lock_work; /* work to be done in locking */
...@@ -648,6 +631,8 @@ extern const struct address_space_operations afs_fs_aops; ...@@ -648,6 +631,8 @@ extern const struct address_space_operations afs_fs_aops;
extern const struct inode_operations afs_file_inode_operations; extern const struct inode_operations afs_file_inode_operations;
extern const struct file_operations afs_file_operations; extern const struct file_operations afs_file_operations;
extern int afs_cache_wb_key(struct afs_vnode *, struct afs_file *);
extern void afs_put_wb_key(struct afs_wb_key *);
extern int afs_open(struct inode *, struct file *); extern int afs_open(struct inode *, struct file *);
extern int afs_release(struct inode *, struct file *); extern int afs_release(struct inode *, struct file *);
extern int afs_fetch_data(struct afs_vnode *, struct key *, struct afs_read *); extern int afs_fetch_data(struct afs_vnode *, struct key *, struct afs_read *);
...@@ -678,7 +663,7 @@ extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, ...@@ -678,7 +663,7 @@ extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *,
struct afs_fid *, struct afs_file_status *); struct afs_fid *, struct afs_file_status *);
extern int afs_fs_rename(struct afs_fs_cursor *, const char *, extern int afs_fs_rename(struct afs_fs_cursor *, const char *,
struct afs_vnode *, const char *); struct afs_vnode *, const char *);
extern int afs_fs_store_data(struct afs_fs_cursor *, struct afs_writeback *, extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *,
pgoff_t, pgoff_t, unsigned, unsigned); pgoff_t, pgoff_t, unsigned, unsigned);
extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *); extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *);
extern int afs_fs_get_volume_status(struct afs_fs_cursor *, struct afs_volume_status *); extern int afs_fs_get_volume_status(struct afs_fs_cursor *, struct afs_volume_status *);
...@@ -889,7 +874,6 @@ extern int afs_check_volume_status(struct afs_volume *, struct key *); ...@@ -889,7 +874,6 @@ extern int afs_check_volume_status(struct afs_volume *, struct key *);
* write.c * write.c
*/ */
extern int afs_set_page_dirty(struct page *); extern int afs_set_page_dirty(struct page *);
extern void afs_put_writeback(struct afs_writeback *);
extern int afs_write_begin(struct file *file, struct address_space *mapping, extern int afs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata); struct page **pagep, void **fsdata);
...@@ -900,9 +884,10 @@ extern int afs_writepage(struct page *, struct writeback_control *); ...@@ -900,9 +884,10 @@ extern int afs_writepage(struct page *, struct writeback_control *);
extern int afs_writepages(struct address_space *, struct writeback_control *); extern int afs_writepages(struct address_space *, struct writeback_control *);
extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *); extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *);
extern int afs_writeback_all(struct afs_vnode *);
extern int afs_flush(struct file *, fl_owner_t); extern int afs_flush(struct file *, fl_owner_t);
extern int afs_fsync(struct file *, loff_t, loff_t, int); extern int afs_fsync(struct file *, loff_t, loff_t, int);
extern void afs_prune_wb_keys(struct afs_vnode *);
extern int afs_launder_page(struct page *);
/* /*
* xattr.c * xattr.c
......
...@@ -546,9 +546,9 @@ static void afs_i_init_once(void *_vnode) ...@@ -546,9 +546,9 @@ static void afs_i_init_once(void *_vnode)
inode_init_once(&vnode->vfs_inode); inode_init_once(&vnode->vfs_inode);
mutex_init(&vnode->io_lock); mutex_init(&vnode->io_lock);
mutex_init(&vnode->validate_lock); mutex_init(&vnode->validate_lock);
spin_lock_init(&vnode->writeback_lock); spin_lock_init(&vnode->wb_lock);
spin_lock_init(&vnode->lock); spin_lock_init(&vnode->lock);
INIT_LIST_HEAD(&vnode->writebacks); INIT_LIST_HEAD(&vnode->wb_keys);
INIT_LIST_HEAD(&vnode->pending_locks); INIT_LIST_HEAD(&vnode->pending_locks);
INIT_LIST_HEAD(&vnode->granted_locks); INIT_LIST_HEAD(&vnode->granted_locks);
INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
......
This diff is collapsed.
...@@ -1041,6 +1041,7 @@ int wait_on_page_bit_killable(struct page *page, int bit_nr) ...@@ -1041,6 +1041,7 @@ int wait_on_page_bit_killable(struct page *page, int bit_nr)
wait_queue_head_t *q = page_waitqueue(page); wait_queue_head_t *q = page_waitqueue(page);
return wait_on_page_bit_common(q, page, bit_nr, TASK_KILLABLE, false); return wait_on_page_bit_common(q, page, bit_nr, TASK_KILLABLE, false);
} }
EXPORT_SYMBOL(wait_on_page_bit_killable);
/** /**
* add_page_wait_queue - Add an arbitrary waiter to a page's wait queue * add_page_wait_queue - Add an arbitrary waiter to a page's wait queue
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment