Commit aa6bf01d authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Ben Myers

xfs: use per-filesystem I/O completion workqueues

The new concurrency managed workqueues are cheap enough that we can create
per-filesystem instead of global workqueues.  This allows us to remove the
trylock or defer scheme on the ilock, which is not helpful once we have
outstanding log reservations until finishing a size update.

Also allow the default concurrency on this workqueues so that I/O completions
blocking on the ilock for one inode do not block process for another inode.
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarMark Tinguely <tinguely@sgi.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 4b217ed9
...@@ -126,21 +126,15 @@ static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend) ...@@ -126,21 +126,15 @@ static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
/* /*
* Update on-disk file size now that data has been written to disk. * Update on-disk file size now that data has been written to disk.
*
* This function does not block as blocking on the inode lock in IO completion
* can lead to IO completion order dependency deadlocks.. If it can't get the
* inode ilock it will return EAGAIN. Callers must handle this.
*/ */
STATIC int STATIC void
xfs_setfilesize( xfs_setfilesize(
xfs_ioend_t *ioend) struct xfs_ioend *ioend)
{ {
xfs_inode_t *ip = XFS_I(ioend->io_inode); struct xfs_inode *ip = XFS_I(ioend->io_inode);
xfs_fsize_t isize; xfs_fsize_t isize;
if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) xfs_ilock(ip, XFS_ILOCK_EXCL);
return EAGAIN;
isize = xfs_ioend_new_eof(ioend); isize = xfs_ioend_new_eof(ioend);
if (isize) { if (isize) {
trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
...@@ -149,7 +143,6 @@ xfs_setfilesize( ...@@ -149,7 +143,6 @@ xfs_setfilesize(
} }
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(ip, XFS_ILOCK_EXCL);
return 0;
} }
/* /*
...@@ -163,10 +156,12 @@ xfs_finish_ioend( ...@@ -163,10 +156,12 @@ xfs_finish_ioend(
struct xfs_ioend *ioend) struct xfs_ioend *ioend)
{ {
if (atomic_dec_and_test(&ioend->io_remaining)) { if (atomic_dec_and_test(&ioend->io_remaining)) {
struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount;
if (ioend->io_type == IO_UNWRITTEN) if (ioend->io_type == IO_UNWRITTEN)
queue_work(xfsconvertd_workqueue, &ioend->io_work); queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
else if (xfs_ioend_is_append(ioend)) else if (xfs_ioend_is_append(ioend))
queue_work(xfsdatad_workqueue, &ioend->io_work); queue_work(mp->m_data_workqueue, &ioend->io_work);
else else
xfs_destroy_ioend(ioend); xfs_destroy_ioend(ioend);
} }
...@@ -207,23 +202,9 @@ xfs_end_io( ...@@ -207,23 +202,9 @@ xfs_end_io(
* We might have to update the on-disk file size after extending * We might have to update the on-disk file size after extending
* writes. * writes.
*/ */
error = xfs_setfilesize(ioend); xfs_setfilesize(ioend);
ASSERT(!error || error == EAGAIN);
done: done:
/* xfs_destroy_ioend(ioend);
* If we didn't complete processing of the ioend, requeue it to the
* tail of the workqueue for another attempt later. Otherwise destroy
* it.
*/
if (error == EAGAIN) {
atomic_inc(&ioend->io_remaining);
xfs_finish_ioend(ioend);
/* ensure we don't spin on blocked ioends */
delay(1);
} else {
xfs_destroy_ioend(ioend);
}
} }
/* /*
......
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#ifndef __XFS_AOPS_H__ #ifndef __XFS_AOPS_H__
#define __XFS_AOPS_H__ #define __XFS_AOPS_H__
extern struct workqueue_struct *xfsdatad_workqueue;
extern struct workqueue_struct *xfsconvertd_workqueue;
extern mempool_t *xfs_ioend_pool; extern mempool_t *xfs_ioend_pool;
/* /*
......
...@@ -45,8 +45,6 @@ static kmem_zone_t *xfs_buf_zone; ...@@ -45,8 +45,6 @@ static kmem_zone_t *xfs_buf_zone;
STATIC int xfsbufd(void *); STATIC int xfsbufd(void *);
static struct workqueue_struct *xfslogd_workqueue; static struct workqueue_struct *xfslogd_workqueue;
struct workqueue_struct *xfsdatad_workqueue;
struct workqueue_struct *xfsconvertd_workqueue;
#ifdef XFS_BUF_LOCK_TRACKING #ifdef XFS_BUF_LOCK_TRACKING
# define XB_SET_OWNER(bp) ((bp)->b_last_holder = current->pid) # define XB_SET_OWNER(bp) ((bp)->b_last_holder = current->pid)
...@@ -1793,21 +1791,8 @@ xfs_buf_init(void) ...@@ -1793,21 +1791,8 @@ xfs_buf_init(void)
if (!xfslogd_workqueue) if (!xfslogd_workqueue)
goto out_free_buf_zone; goto out_free_buf_zone;
xfsdatad_workqueue = alloc_workqueue("xfsdatad", WQ_MEM_RECLAIM, 1);
if (!xfsdatad_workqueue)
goto out_destroy_xfslogd_workqueue;
xfsconvertd_workqueue = alloc_workqueue("xfsconvertd",
WQ_MEM_RECLAIM, 1);
if (!xfsconvertd_workqueue)
goto out_destroy_xfsdatad_workqueue;
return 0; return 0;
out_destroy_xfsdatad_workqueue:
destroy_workqueue(xfsdatad_workqueue);
out_destroy_xfslogd_workqueue:
destroy_workqueue(xfslogd_workqueue);
out_free_buf_zone: out_free_buf_zone:
kmem_zone_destroy(xfs_buf_zone); kmem_zone_destroy(xfs_buf_zone);
out: out:
...@@ -1817,8 +1802,6 @@ xfs_buf_init(void) ...@@ -1817,8 +1802,6 @@ xfs_buf_init(void)
void void
xfs_buf_terminate(void) xfs_buf_terminate(void)
{ {
destroy_workqueue(xfsconvertd_workqueue);
destroy_workqueue(xfsdatad_workqueue);
destroy_workqueue(xfslogd_workqueue); destroy_workqueue(xfslogd_workqueue);
kmem_zone_destroy(xfs_buf_zone); kmem_zone_destroy(xfs_buf_zone);
} }
...@@ -211,6 +211,9 @@ typedef struct xfs_mount { ...@@ -211,6 +211,9 @@ typedef struct xfs_mount {
struct shrinker m_inode_shrink; /* inode reclaim shrinker */ struct shrinker m_inode_shrink; /* inode reclaim shrinker */
int64_t m_low_space[XFS_LOWSP_MAX]; int64_t m_low_space[XFS_LOWSP_MAX];
/* low free space thresholds */ /* low free space thresholds */
struct workqueue_struct *m_data_workqueue;
struct workqueue_struct *m_unwritten_workqueue;
} xfs_mount_t; } xfs_mount_t;
/* /*
......
...@@ -759,6 +759,36 @@ xfs_setup_devices( ...@@ -759,6 +759,36 @@ xfs_setup_devices(
return 0; return 0;
} }
STATIC int
xfs_init_mount_workqueues(
struct xfs_mount *mp)
{
mp->m_data_workqueue = alloc_workqueue("xfs-data/%s",
WQ_MEM_RECLAIM, 0, mp->m_fsname);
if (!mp->m_data_workqueue)
goto out;
mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
WQ_MEM_RECLAIM, 0, mp->m_fsname);
if (!mp->m_unwritten_workqueue)
goto out_destroy_data_iodone_queue;
return 0;
out_destroy_data_iodone_queue:
destroy_workqueue(mp->m_data_workqueue);
out:
return -ENOMEM;
}
STATIC void
xfs_destroy_mount_workqueues(
struct xfs_mount *mp)
{
destroy_workqueue(mp->m_data_workqueue);
destroy_workqueue(mp->m_unwritten_workqueue);
}
/* Catch misguided souls that try to use this interface on XFS */ /* Catch misguided souls that try to use this interface on XFS */
STATIC struct inode * STATIC struct inode *
xfs_fs_alloc_inode( xfs_fs_alloc_inode(
...@@ -982,6 +1012,7 @@ xfs_fs_put_super( ...@@ -982,6 +1012,7 @@ xfs_fs_put_super(
xfs_unmountfs(mp); xfs_unmountfs(mp);
xfs_freesb(mp); xfs_freesb(mp);
xfs_icsb_destroy_counters(mp); xfs_icsb_destroy_counters(mp);
xfs_destroy_mount_workqueues(mp);
xfs_close_devices(mp); xfs_close_devices(mp);
xfs_free_fsname(mp); xfs_free_fsname(mp);
kfree(mp); kfree(mp);
...@@ -1308,10 +1339,14 @@ xfs_fs_fill_super( ...@@ -1308,10 +1339,14 @@ xfs_fs_fill_super(
if (error) if (error)
goto out_free_fsname; goto out_free_fsname;
error = xfs_icsb_init_counters(mp); error = xfs_init_mount_workqueues(mp);
if (error) if (error)
goto out_close_devices; goto out_close_devices;
error = xfs_icsb_init_counters(mp);
if (error)
goto out_destroy_workqueues;
error = xfs_readsb(mp, flags); error = xfs_readsb(mp, flags);
if (error) if (error)
goto out_destroy_counters; goto out_destroy_counters;
...@@ -1374,6 +1409,8 @@ xfs_fs_fill_super( ...@@ -1374,6 +1409,8 @@ xfs_fs_fill_super(
xfs_freesb(mp); xfs_freesb(mp);
out_destroy_counters: out_destroy_counters:
xfs_icsb_destroy_counters(mp); xfs_icsb_destroy_counters(mp);
out_destroy_workqueues:
xfs_destroy_mount_workqueues(mp);
out_close_devices: out_close_devices:
xfs_close_devices(mp); xfs_close_devices(mp);
out_free_fsname: out_free_fsname:
......
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