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);
static void afs_invalidatepage(struct page *page, unsigned int offset,
unsigned int length);
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,
struct list_head *pages, unsigned nr_pages);
......@@ -62,6 +61,50 @@ const struct address_space_operations afs_fs_aops = {
.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
*/
......@@ -85,12 +128,18 @@ int afs_open(struct inode *inode, struct file *file)
ret = -ENOMEM;
goto error_key;
}
af->key = key;
ret = afs_validate(vnode, key);
if (ret < 0)
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;
_leave(" = 0");
return 0;
......@@ -115,8 +164,11 @@ int afs_release(struct inode *inode, struct file *file)
_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
file->private_data = NULL;
if (af->wb)
afs_put_wb_key(af->wb);
key_put(af->key);
kfree(af);
afs_prune_wb_keys(vnode);
_leave(" = 0");
return 0;
}
......@@ -516,16 +568,6 @@ static int afs_readpages(struct file *file, struct address_space *mapping,
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
* - 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)
static void afs_invalidatepage(struct page *page, unsigned int offset,
unsigned int length)
{
struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
_enter("{%lu},%u,%u", page->index, offset, length);
BUG_ON(!PageLocked(page));
......@@ -551,12 +591,7 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
#endif
if (PagePrivate(page)) {
if (wb && !PageWriteback(page)) {
set_page_private(page, 0);
afs_put_writeback(wb);
}
if (!page_private(page))
ClearPagePrivate(page);
}
}
......@@ -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)
{
struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
_enter("{{%x:%u}[%lu],%lx},%x",
......@@ -587,10 +621,7 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
#endif
if (PagePrivate(page)) {
if (wb) {
set_page_private(page, 0);
afs_put_writeback(wb);
}
ClearPagePrivate(page);
}
......
......@@ -1119,18 +1119,18 @@ static const struct afs_call_type afs_RXFSStoreData64 = {
* store a set of pages to a very large file
*/
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,
unsigned offset, unsigned to,
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_net *net = afs_v2net(vnode);
__be32 *bp;
_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,
(4 + 6 + 3 * 2) * 4,
......@@ -1138,10 +1138,9 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
if (!call)
return -ENOMEM;
call->wb = wb;
call->key = wb->key;
call->key = fc->key;
call->mapping = mapping;
call->reply[0] = vnode;
call->mapping = vnode->vfs_inode.i_mapping;
call->first = first;
call->last = last;
call->first_offset = offset;
......@@ -1177,18 +1176,18 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
/*
* 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,
unsigned offset, unsigned to)
{
struct afs_vnode *vnode = wb->vnode;
struct afs_vnode *vnode = fc->vnode;
struct afs_call *call;
struct afs_net *net = afs_v2net(vnode);
loff_t size, pos, i_size;
__be32 *bp;
_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;
if (first != last)
......@@ -1205,7 +1204,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb,
(unsigned long long) i_size);
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);
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,
if (!call)
return -ENOMEM;
call->wb = wb;
call->key = wb->key;
call->key = fc->key;
call->mapping = mapping;
call->reply[0] = vnode;
call->mapping = vnode->vfs_inode.i_mapping;
call->first = first;
call->last = last;
call->first_offset = offset;
......
......@@ -482,7 +482,12 @@ void afs_evict_inode(struct inode *inode)
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
fscache_relinquish_cookie(vnode->cache, 0);
......@@ -514,10 +519,8 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
}
/* 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);
afs_writeback_all(vnode);
}
if (attr->ia_valid & ATTR_FILE) {
key = afs_file_key(attr->ia_file);
......
......@@ -89,8 +89,7 @@ struct afs_call {
struct afs_server *cm_server; /* Server affected by incoming CM call */
struct afs_cb_interest *cbi; /* Callback interest for server used */
void *request; /* request data (first part) */
struct address_space *mapping; /* page set */
struct afs_writeback *wb; /* writeback being performed */
struct address_space *mapping; /* Pages being written from */
void *buffer; /* reply receive buffer */
void *reply[4]; /* Where to put the reply */
pgoff_t first; /* first page in mapping to deal with */
......@@ -138,11 +137,21 @@ struct afs_call_type {
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.
*/
struct afs_file {
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)
......@@ -167,32 +176,6 @@ struct afs_read {
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
* - there's one superblock per volume
......@@ -460,7 +443,7 @@ struct afs_vnode {
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 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 */
unsigned long flags;
#define AFS_VNODE_CB_PROMISED 0 /* Set if vnode has a callback promise */
......@@ -476,7 +459,7 @@ struct afs_vnode {
#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 */
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 granted_locks; /* locks granted on this file */
struct delayed_work lock_work; /* work to be done in locking */
......@@ -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 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_release(struct inode *, struct file *);
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 *,
struct afs_fid *, struct afs_file_status *);
extern int afs_fs_rename(struct afs_fs_cursor *, 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);
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 *);
......@@ -889,7 +874,6 @@ extern int afs_check_volume_status(struct afs_volume *, struct key *);
* write.c
*/
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,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata);
......@@ -900,9 +884,10 @@ extern int afs_writepage(struct page *, 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 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_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
......
......@@ -546,9 +546,9 @@ static void afs_i_init_once(void *_vnode)
inode_init_once(&vnode->vfs_inode);
mutex_init(&vnode->io_lock);
mutex_init(&vnode->validate_lock);
spin_lock_init(&vnode->writeback_lock);
spin_lock_init(&vnode->wb_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->granted_locks);
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)
wait_queue_head_t *q = page_waitqueue(page);
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
......
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