Skip to content

Commit

Permalink
afs: Get rid of the afs_writeback record
Browse files Browse the repository at this point in the history
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: David Howells <dhowells@redhat.com>
  • Loading branch information
dhowells committed Nov 13, 2017
1 parent 215804a commit 4343d00
Show file tree
Hide file tree
Showing 7 changed files with 412 additions and 395 deletions.
83 changes: 57 additions & 26 deletions fs/afs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
*/
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand All @@ -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));
Expand All @@ -551,13 +591,8 @@ 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);
set_page_private(page, 0);
ClearPagePrivate(page);
}
}

Expand All @@ -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",
Expand All @@ -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);
}
set_page_private(page, 0);
ClearPagePrivate(page);
}

Expand Down
24 changes: 11 additions & 13 deletions fs/afs/fsclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -1119,29 +1119,28 @@ 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,
(21 + 6) * 4);
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;
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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;
Expand Down
11 changes: 7 additions & 4 deletions fs/afs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
51 changes: 18 additions & 33 deletions fs/afs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down Expand Up @@ -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 *);
Expand Down Expand Up @@ -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 *);
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions fs/afs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 4343d00

Please sign in to comment.