Commit 20181273 authored by David Howells's avatar David Howells

afs: Rewrite writeback handling

Rewrite the writeback handling to make the writeback records refcounted
separately from the completion management so that a ref can be taken on one
without preventing completion from happening.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent f357dbca
......@@ -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);
......@@ -463,13 +462,23 @@ static int afs_readpages(struct file *file, struct address_space *mapping,
}
/*
* write back a dirty page
* Try to remove a page from any writeback it may be entertaining.
*/
static int afs_launder_page(struct page *page)
static bool afs_remove_wb_from_page(struct afs_vnode *vnode, struct page *page,
enum afs_writeback_trace why)
{
_enter("{%lu}", page->index);
struct afs_writeback *wb;
bool cleared = true;
spin_lock(&vnode->writeback_lock);
wb = afs_get_writeback(vnode, (struct afs_writeback *)page_private(page), why);
spin_unlock(&vnode->writeback_lock);
if (wb) {
cleared = afs_writeback_remove_page(vnode, wb, page);
afs_put_writeback(vnode, wb, 1);
}
return 0;
return cleared;
}
/*
......@@ -480,7 +489,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);
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
_enter("{%lu},%u,%u", page->index, offset, length);
......@@ -496,15 +504,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(vnode, wb);
}
if (!page_private(page))
ClearPagePrivate(page);
}
afs_remove_wb_from_page(vnode, page,
afs_writeback_trace_invalidate_page);
}
_leave("");
......@@ -516,8 +517,8 @@ 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);
bool cleared = true;
_enter("{{%x:%u}[%lu],%lx},%x",
vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
......@@ -532,15 +533,8 @@ 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(vnode, wb);
}
ClearPagePrivate(page);
}
/* indicate that the page can be released */
_leave(" = T");
return 1;
cleared = afs_remove_wb_from_page(vnode, page,
afs_writeback_trace_release_page);
_leave(" = %d", cleared);
return cleared;
}
......@@ -474,10 +474,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)) {
filemap_write_and_wait(vnode->vfs_inode.i_mapping);
if (S_ISREG(vnode->vfs_inode.i_mode))
afs_writeback_all(vnode);
}
if (attr->ia_valid & ATTR_FILE) {
key = attr->ia_file->private_data;
......
......@@ -156,7 +156,8 @@ struct afs_writeback {
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;
atomic_t usage;
int nr_pages; /* Number of pages contributing */
bool conflicts; /* T if has dependent conflicts */
enum {
AFS_WBACK_SYNCING, /* synchronisation being performed */
......@@ -411,6 +412,8 @@ struct afs_interface {
unsigned mtu; /* MTU of interface */
};
#include <trace/events/afs.h>
/*****************************************************************************/
/*
* cache.c
......@@ -709,7 +712,13 @@ extern int afs_volume_release_fileserver(struct afs_vnode *,
* write.c
*/
extern int afs_set_page_dirty(struct page *);
extern void afs_put_writeback(struct afs_vnode *, struct afs_writeback *);
extern struct afs_writeback *afs_get_writeback(struct afs_vnode *,
struct afs_writeback *,
enum afs_writeback_trace);
extern void afs_put_writeback(struct afs_vnode *, struct afs_writeback *,
unsigned);
extern bool afs_writeback_remove_page(struct afs_vnode *,
struct afs_writeback *, struct page *);
extern int afs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata);
......@@ -723,14 +732,12 @@ 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 int afs_launder_page(struct page *);
/*****************************************************************************/
/*
* debug tracing
*/
#include <trace/events/afs.h>
extern unsigned afs_debug;
#define dbgprintk(FMT,...) \
......
......@@ -330,7 +330,7 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg)
first += nr;
} while (first <= last);
trace_afs_sent_pages(call, first, last, ret);
trace_afs_sent_pages(call, call->first, last, first, ret);
return ret;
}
......
This diff is collapsed.
......@@ -60,6 +60,26 @@ enum afs_vl_operation {
afs_VL_Probe = 514, /* AFS Probe Volume Location Service operation ID */
};
enum afs_writeback_trace {
afs_writeback_trace_alloc,
afs_writeback_trace_append,
afs_writeback_trace_conflict,
afs_writeback_trace_discard,
afs_writeback_trace_flush,
afs_writeback_trace_fsync,
afs_writeback_trace_invalidate_page,
afs_writeback_trace_new,
afs_writeback_trace_no_wake,
afs_writeback_trace_put,
afs_writeback_trace_release_page,
afs_writeback_trace_subsume,
afs_writeback_trace_unlink,
afs_writeback_trace_wake,
afs_writeback_trace_write,
afs_writeback_trace_writepages,
afs_writeback_trace_written,
};
#endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */
/*
......@@ -100,6 +120,25 @@ enum afs_vl_operation {
EM(afs_VL_GetEntryByName, "VL.GetEntryByName") \
E_(afs_VL_Probe, "VL.Probe")
#define afs_writeback_traces \
EM(afs_writeback_trace_alloc, "Alloc ") \
EM(afs_writeback_trace_append, "Append") \
EM(afs_writeback_trace_conflict, "Conflc") \
EM(afs_writeback_trace_discard, "Discrd") \
EM(afs_writeback_trace_flush, "Flush ") \
EM(afs_writeback_trace_fsync, "Fsync ") \
EM(afs_writeback_trace_invalidate_page, "InvlPg") \
EM(afs_writeback_trace_new, "New ") \
EM(afs_writeback_trace_no_wake, "NoWake") \
EM(afs_writeback_trace_put, "Put ") \
EM(afs_writeback_trace_release_page, "RelsPg") \
EM(afs_writeback_trace_subsume, "Subsum") \
EM(afs_writeback_trace_unlink, "Unlink") \
EM(afs_writeback_trace_wake, "Wake ") \
EM(afs_writeback_trace_write, "Write ") \
EM(afs_writeback_trace_writepages, "Wpages") \
E_(afs_writeback_trace_written, "Writtn")
/*
* Export enum symbols via userspace.
......@@ -112,6 +151,7 @@ enum afs_vl_operation {
afs_call_traces;
afs_fs_operations;
afs_vl_operations;
afs_writeback_traces;
/*
* Now redefine the EM() and E_() macros to map the enums to the strings that
......@@ -344,14 +384,16 @@ TRACE_EVENT(afs_send_pages,
);
TRACE_EVENT(afs_sent_pages,
TP_PROTO(struct afs_call *call, pgoff_t first, pgoff_t last, int ret),
TP_PROTO(struct afs_call *call, pgoff_t first, pgoff_t last,
pgoff_t cursor, int ret),
TP_ARGS(call, first, last, ret),
TP_ARGS(call, first, last, cursor, ret),
TP_STRUCT__entry(
__field(struct afs_call *, call )
__field(pgoff_t, first )
__field(pgoff_t, last )
__field(pgoff_t, cursor )
__field(int, ret )
),
......@@ -359,13 +401,69 @@ TRACE_EVENT(afs_sent_pages,
__entry->call = call;
__entry->first = first;
__entry->last = last;
__entry->cursor = cursor;
__entry->ret = ret;
),
TP_printk(" c=%p %lx-%lx r=%d",
TP_printk(" c=%p %lx-%lx c=%lx r=%d",
__entry->call,
__entry->first, __entry->last,
__entry->ret)
__entry->cursor, __entry->ret)
);
TRACE_EVENT(afs_write_begin,
TP_PROTO(struct afs_vnode *vnode, pgoff_t index,
unsigned from, unsigned to, unsigned flags),
TP_ARGS(vnode, index, from, to, flags),
TP_STRUCT__entry(
__field(struct afs_vnode *, vnode )
__field(pgoff_t, index )
__field(unsigned, from )
__field(unsigned, to )
__field(unsigned, flags )
),
TP_fast_assign(
__entry->vnode = vnode;
__entry->index = index;
__entry->from = from;
__entry->to = to;
__entry->flags = flags;
),
TP_printk("vn=%p pg=%lu %u-%u fl=%u",
__entry->vnode, __entry->index,
__entry->from, __entry->to, __entry->flags)
);
TRACE_EVENT(afs_writeback,
TP_PROTO(struct afs_vnode *vnode, struct afs_writeback *wb,
enum afs_writeback_trace op, int usage, int delta),
TP_ARGS(vnode, wb, op, usage, delta),
TP_STRUCT__entry(
__field(struct afs_vnode *, vnode )
__field(struct afs_writeback *, wb )
__field(int, op )
__field(int, usage )
__field(int, delta )
),
TP_fast_assign(
__entry->vnode = vnode;
__entry->wb = wb;
__entry->op = op;
__entry->usage = usage;
__entry->delta = delta;
),
TP_printk("vn=%p wb=%p %s u=%d d=%d",
__entry->vnode, __entry->wb,
__print_symbolic(__entry->op, afs_writeback_traces),
__entry->usage, __entry->delta)
);
#endif /* _TRACE_AFS_H */
......
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