You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
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: David Howells <dhowells@redhat.com>
This commit is contained in:
@@ -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,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
set_page_private(page, 0);
|
||||
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);
|
||||
|
||||
633
fs/afs/write.c
633
fs/afs/write.c
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user