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); ...@@ -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);
...@@ -463,13 +462,23 @@ static int afs_readpages(struct file *file, struct address_space *mapping, ...@@ -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) ...@@ -480,7 +489,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);
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
_enter("{%lu},%u,%u", page->index, offset, length); _enter("{%lu},%u,%u", page->index, offset, length);
...@@ -496,15 +504,8 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, ...@@ -496,15 +504,8 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
} }
#endif #endif
if (PagePrivate(page)) { afs_remove_wb_from_page(vnode, page,
if (wb && !PageWriteback(page)) { afs_writeback_trace_invalidate_page);
set_page_private(page, 0);
afs_put_writeback(vnode, wb);
}
if (!page_private(page))
ClearPagePrivate(page);
}
} }
_leave(""); _leave("");
...@@ -516,8 +517,8 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, ...@@ -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) 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);
bool cleared = true;
_enter("{{%x:%u}[%lu],%lx},%x", _enter("{{%x:%u}[%lu],%lx},%x",
vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, 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) ...@@ -532,15 +533,8 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
} }
#endif #endif
if (PagePrivate(page)) { cleared = afs_remove_wb_from_page(vnode, page,
if (wb) { afs_writeback_trace_release_page);
set_page_private(page, 0); _leave(" = %d", cleared);
afs_put_writeback(vnode, wb); return cleared;
}
ClearPagePrivate(page);
}
/* indicate that the page can be released */
_leave(" = T");
return 1;
} }
...@@ -474,10 +474,8 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -474,10 +474,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);
afs_writeback_all(vnode); afs_writeback_all(vnode);
}
if (attr->ia_valid & ATTR_FILE) { if (attr->ia_valid & ATTR_FILE) {
key = attr->ia_file->private_data; key = attr->ia_file->private_data;
......
...@@ -156,7 +156,8 @@ struct afs_writeback { ...@@ -156,7 +156,8 @@ struct afs_writeback {
unsigned offset_first; /* offset into first page of start of write */ unsigned offset_first; /* offset into first page of start of write */
unsigned to_last; /* offset into last page of end of write */ unsigned to_last; /* offset into last page of end of write */
int num_conflicts; /* count of conflicting writes in list */ 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 */ bool conflicts; /* T if has dependent conflicts */
enum { enum {
AFS_WBACK_SYNCING, /* synchronisation being performed */ AFS_WBACK_SYNCING, /* synchronisation being performed */
...@@ -411,6 +412,8 @@ struct afs_interface { ...@@ -411,6 +412,8 @@ struct afs_interface {
unsigned mtu; /* MTU of interface */ unsigned mtu; /* MTU of interface */
}; };
#include <trace/events/afs.h>
/*****************************************************************************/ /*****************************************************************************/
/* /*
* cache.c * cache.c
...@@ -709,7 +712,13 @@ extern int afs_volume_release_fileserver(struct afs_vnode *, ...@@ -709,7 +712,13 @@ extern int afs_volume_release_fileserver(struct afs_vnode *,
* 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_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, 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);
...@@ -723,14 +732,12 @@ extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *); ...@@ -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_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 int afs_launder_page(struct page *);
/*****************************************************************************/ /*****************************************************************************/
/* /*
* debug tracing * debug tracing
*/ */
#include <trace/events/afs.h>
extern unsigned afs_debug; extern unsigned afs_debug;
#define dbgprintk(FMT,...) \ #define dbgprintk(FMT,...) \
......
...@@ -330,7 +330,7 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg) ...@@ -330,7 +330,7 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg)
first += nr; first += nr;
} while (first <= last); } while (first <= last);
trace_afs_sent_pages(call, first, last, ret); trace_afs_sent_pages(call, call->first, last, first, ret);
return ret; return ret;
} }
......
This diff is collapsed.
...@@ -60,6 +60,26 @@ enum afs_vl_operation { ...@@ -60,6 +60,26 @@ enum afs_vl_operation {
afs_VL_Probe = 514, /* AFS Probe Volume Location Service operation ID */ 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 */ #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */
/* /*
...@@ -100,6 +120,25 @@ enum afs_vl_operation { ...@@ -100,6 +120,25 @@ enum afs_vl_operation {
EM(afs_VL_GetEntryByName, "VL.GetEntryByName") \ EM(afs_VL_GetEntryByName, "VL.GetEntryByName") \
E_(afs_VL_Probe, "VL.Probe") 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. * Export enum symbols via userspace.
...@@ -112,6 +151,7 @@ enum afs_vl_operation { ...@@ -112,6 +151,7 @@ enum afs_vl_operation {
afs_call_traces; afs_call_traces;
afs_fs_operations; afs_fs_operations;
afs_vl_operations; afs_vl_operations;
afs_writeback_traces;
/* /*
* Now redefine the EM() and E_() macros to map the enums to the strings that * Now redefine the EM() and E_() macros to map the enums to the strings that
...@@ -344,14 +384,16 @@ TRACE_EVENT(afs_send_pages, ...@@ -344,14 +384,16 @@ TRACE_EVENT(afs_send_pages,
); );
TRACE_EVENT(afs_sent_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( TP_STRUCT__entry(
__field(struct afs_call *, call ) __field(struct afs_call *, call )
__field(pgoff_t, first ) __field(pgoff_t, first )
__field(pgoff_t, last ) __field(pgoff_t, last )
__field(pgoff_t, cursor )
__field(int, ret ) __field(int, ret )
), ),
...@@ -359,13 +401,69 @@ TRACE_EVENT(afs_sent_pages, ...@@ -359,13 +401,69 @@ TRACE_EVENT(afs_sent_pages,
__entry->call = call; __entry->call = call;
__entry->first = first; __entry->first = first;
__entry->last = last; __entry->last = last;
__entry->cursor = cursor;
__entry->ret = ret; __entry->ret = ret;
), ),
TP_printk(" c=%p %lx-%lx r=%d", TP_printk(" c=%p %lx-%lx c=%lx r=%d",
__entry->call, __entry->call,
__entry->first, __entry->last, __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 */ #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