* [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd)
@ 2011-10-28 9:54 Christoph Hellwig
2011-10-28 9:54 ` [PATCH 01/45] xfs: constify xfs_item_ops Christoph Hellwig
` (41 more replies)
0 siblings, 42 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
Sorry for the patchbomb, but I wanted to flush out my current working
series now that is passing all the testing I've thrown at, including
on a high IOPS flash device that I won't have access to for much longer.
The series really is multiple ones, but we need all of it to make it
to the end goal.
1) inode shrinkage. This has been posted and partially revieved before,
and isn't absolutely nessecary but will make life easier later on.
2) log all inode updates and stop using the VFS dirty tracking for metadata.
This has also been posted before, and it did get some updates. It still
lacks support for optimizing fdatasync, and it still hasn't been updated
to the suggestion by Dave to allocate log space from ->writepage. I have
tried to implement the latter but run into various issues, more on that
later.
3) the various quota updates, which mostly have been posted before. This
version also has a few new patches that add a proper shrinker callout
to the quota code. While the code looks fairly good the testing doesn't
really stress much of this code at all. I will have to write a new
testcase (or a few) that actually have a lot of dquots in memory,
and create memory pressure before I feel confident enought about these
changes.
4) stop writing back inodes from async reclaim. This is just a single patch,
but a huge change in behaviour.
5) implement a way to completely empty the AIL and use it during freeze, umount
and remount r/o. This remove a whole lot of nasty heuristics for flushing
back all metadata to its regular, non-log place by using a single piece
of well understood code.
6) remove xfsbufd and queue up buffers on on-stack list, with the only
one during normal operation beeing the one in xfsaild. Besides greatly
reducing the code this massively reduces calls to the buffercache that
reduce scalability in highly parallel, metada-intensive loads.
7) a few cleanups the reduce and centralize log force trying to unpin buffers.
Comments on all these are highly appreciated, and I will resubmit patches in
here in smaller chunks as soon as were are confident about one or more of
the sub-series.
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 01/45] xfs: constify xfs_item_ops
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 02/45] xfs: make i_flags an unsigned long Christoph Hellwig
` (40 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-constify-xfs_item_ops --]
[-- Type: text/plain, Size: 6122 bytes --]
The log item ops aren't nessecarily the biggest exploit vector, but marking
them const is easy enough. Also remove the unused xfs_item_ops_t typedef
while we're at it.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
---
fs/xfs/xfs_buf_item.c | 2 +-
fs/xfs/xfs_dquot_item.c | 6 +++---
fs/xfs/xfs_extfree_item.c | 4 ++--
fs/xfs/xfs_inode_item.c | 2 +-
fs/xfs/xfs_log.c | 2 +-
fs/xfs/xfs_log.h | 2 +-
fs/xfs/xfs_trans.h | 6 +++---
7 files changed, 12 insertions(+), 12 deletions(-)
Index: xfs/fs/xfs/xfs_buf_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_buf_item.c 2011-10-27 22:39:37.124671335 +0200
+++ xfs/fs/xfs/xfs_buf_item.c 2011-10-27 22:39:42.528674212 +0200
@@ -656,7 +656,7 @@ xfs_buf_item_committing(
/*
* This is the ops vector shared by all buf log items.
*/
-static struct xfs_item_ops xfs_buf_item_ops = {
+static const struct xfs_item_ops xfs_buf_item_ops = {
.iop_size = xfs_buf_item_size,
.iop_format = xfs_buf_item_format,
.iop_pin = xfs_buf_item_pin,
Index: xfs/fs/xfs/xfs_dquot_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot_item.c 2011-10-27 22:39:37.128671186 +0200
+++ xfs/fs/xfs/xfs_dquot_item.c 2011-10-27 22:39:42.528674212 +0200
@@ -295,7 +295,7 @@ xfs_qm_dquot_logitem_committing(
/*
* This is the ops vector for dquots
*/
-static struct xfs_item_ops xfs_dquot_item_ops = {
+static const struct xfs_item_ops xfs_dquot_item_ops = {
.iop_size = xfs_qm_dquot_logitem_size,
.iop_format = xfs_qm_dquot_logitem_format,
.iop_pin = xfs_qm_dquot_logitem_pin,
@@ -483,7 +483,7 @@ xfs_qm_qoff_logitem_committing(
{
}
-static struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
+static const struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
.iop_size = xfs_qm_qoff_logitem_size,
.iop_format = xfs_qm_qoff_logitem_format,
.iop_pin = xfs_qm_qoff_logitem_pin,
@@ -498,7 +498,7 @@ static struct xfs_item_ops xfs_qm_qoffen
/*
* This is the ops vector shared by all quotaoff-start log items.
*/
-static struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
+static const struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
.iop_size = xfs_qm_qoff_logitem_size,
.iop_format = xfs_qm_qoff_logitem_format,
.iop_pin = xfs_qm_qoff_logitem_pin,
Index: xfs/fs/xfs/xfs_extfree_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_extfree_item.c 2011-10-27 22:39:37.136671437 +0200
+++ xfs/fs/xfs/xfs_extfree_item.c 2011-10-27 22:39:42.528674212 +0200
@@ -217,7 +217,7 @@ xfs_efi_item_committing(
/*
* This is the ops vector shared by all efi log items.
*/
-static struct xfs_item_ops xfs_efi_item_ops = {
+static const struct xfs_item_ops xfs_efi_item_ops = {
.iop_size = xfs_efi_item_size,
.iop_format = xfs_efi_item_format,
.iop_pin = xfs_efi_item_pin,
@@ -477,7 +477,7 @@ xfs_efd_item_committing(
/*
* This is the ops vector shared by all efd log items.
*/
-static struct xfs_item_ops xfs_efd_item_ops = {
+static const struct xfs_item_ops xfs_efd_item_ops = {
.iop_size = xfs_efd_item_size,
.iop_format = xfs_efd_item_format,
.iop_pin = xfs_efd_item_pin,
Index: xfs/fs/xfs/xfs_inode_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode_item.c 2011-10-27 22:39:37.148670941 +0200
+++ xfs/fs/xfs/xfs_inode_item.c 2011-10-27 22:39:42.528674212 +0200
@@ -795,7 +795,7 @@ xfs_inode_item_committing(
/*
* This is the ops vector shared by all buf log items.
*/
-static struct xfs_item_ops xfs_inode_item_ops = {
+static const struct xfs_item_ops xfs_inode_item_ops = {
.iop_size = xfs_inode_item_size,
.iop_format = xfs_inode_item_format,
.iop_pin = xfs_inode_item_pin,
Index: xfs/fs/xfs/xfs_log.c
===================================================================
--- xfs.orig/fs/xfs/xfs_log.c 2011-10-27 22:39:37.152670108 +0200
+++ xfs/fs/xfs/xfs_log.c 2011-10-27 22:39:42.532670748 +0200
@@ -626,7 +626,7 @@ xfs_log_item_init(
struct xfs_mount *mp,
struct xfs_log_item *item,
int type,
- struct xfs_item_ops *ops)
+ const struct xfs_item_ops *ops)
{
item->li_mountp = mp;
item->li_ailp = mp->m_ail;
Index: xfs/fs/xfs/xfs_log.h
===================================================================
--- xfs.orig/fs/xfs/xfs_log.h 2011-10-27 22:39:37.160671381 +0200
+++ xfs/fs/xfs/xfs_log.h 2011-10-27 22:39:42.536670491 +0200
@@ -137,7 +137,7 @@ struct xfs_trans;
void xfs_log_item_init(struct xfs_mount *mp,
struct xfs_log_item *item,
int type,
- struct xfs_item_ops *ops);
+ const struct xfs_item_ops *ops);
xfs_lsn_t xfs_log_done(struct xfs_mount *mp,
struct xlog_ticket *ticket,
Index: xfs/fs/xfs/xfs_trans.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trans.h 2011-10-27 22:39:37.168672757 +0200
+++ xfs/fs/xfs/xfs_trans.h 2011-10-27 22:39:42.536670491 +0200
@@ -326,7 +326,7 @@ typedef struct xfs_log_item {
struct xfs_log_item *);
/* buffer item iodone */
/* callback func */
- struct xfs_item_ops *li_ops; /* function list */
+ const struct xfs_item_ops *li_ops; /* function list */
/* delayed logging */
struct list_head li_cil; /* CIL pointers */
@@ -341,7 +341,7 @@ typedef struct xfs_log_item {
{ XFS_LI_IN_AIL, "IN_AIL" }, \
{ XFS_LI_ABORTED, "ABORTED" }
-typedef struct xfs_item_ops {
+struct xfs_item_ops {
uint (*iop_size)(xfs_log_item_t *);
void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
void (*iop_pin)(xfs_log_item_t *);
@@ -352,7 +352,7 @@ typedef struct xfs_item_ops {
void (*iop_push)(xfs_log_item_t *);
bool (*iop_pushbuf)(xfs_log_item_t *);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
-} xfs_item_ops_t;
+};
#define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip)
#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp)
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 02/45] xfs: make i_flags an unsigned long
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
2011-10-28 9:54 ` [PATCH 01/45] xfs: constify xfs_item_ops Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 03/45] xfs: replace i_flock with a sleeping bitlock Christoph Hellwig
` (39 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-use-i_flags --]
[-- Type: text/plain, Size: 1314 bytes --]
To be used for bit wakeup i_flags needs to be an unsigned long or we'll
run into trouble on big endian systems. Beause of the 1-byte i_update
field right after it this actually causes a fairly large size increase
on its own (4 or 8 bytes), but that increase will be more than offset
by the next two patches.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alex Elder <aelder@sgi.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
---
fs/xfs/xfs_inode.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:37.020671981 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:39:52.102172907 +0200
@@ -249,7 +249,7 @@ typedef struct xfs_inode {
wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */
spinlock_t i_flags_lock; /* inode i_flags lock */
/* Miscellaneous state. */
- unsigned short i_flags; /* see defined flags below */
+ unsigned long i_flags; /* see defined flags below */
unsigned char i_update_core; /* timestamps/size is dirty */
unsigned int i_delayed_blks; /* count of delay alloc blks */
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 03/45] xfs: replace i_flock with a sleeping bitlock
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
2011-10-28 9:54 ` [PATCH 01/45] xfs: constify xfs_item_ops Christoph Hellwig
2011-10-28 9:54 ` [PATCH 02/45] xfs: make i_flags an unsigned long Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 04/45] xfs: replace i_pin_wait with a bit waitqueue Christoph Hellwig
` (38 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-kill-i_flush --]
[-- Type: text/plain, Size: 9425 bytes --]
We almost never block on i_flock, the exception is synchronous inode
flushing. Instead of bloating the inode with a 16/24-byte completion
that we abuse as a semaphore just implement it as a bitlock that uses
a bit waitqueue for the rare sleeping path. This primarily is a
tradeoff between a much smaller inode and a faster non-blocking
path vs faster wakeups, and we are much better off with the former.
A small downside is that we will lose lockdep checking for i_flock, but
given that it's always taken inside the ilock that should be acceptable.
Note that for example the inode writeback locking is implemented in a
very similar way.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alex Elder <aelder@sgi.com>
---
fs/xfs/xfs_iget.c | 20 +++++++++++-
fs/xfs/xfs_inode.c | 4 +-
fs/xfs/xfs_inode.h | 78 ++++++++++++++++++++++++++++++------------------
fs/xfs/xfs_inode_item.c | 4 +-
fs/xfs/xfs_super.c | 7 ----
fs/xfs/xfs_sync.c | 9 ++---
6 files changed, 76 insertions(+), 46 deletions(-)
Index: xfs/fs/xfs/xfs_iget.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iget.c 2011-10-27 22:39:36.932670919 +0200
+++ xfs/fs/xfs/xfs_iget.c 2011-10-27 22:39:53.000673410 +0200
@@ -77,7 +77,7 @@ xfs_inode_alloc(
ASSERT(atomic_read(&ip->i_pincount) == 0);
ASSERT(!spin_is_locked(&ip->i_flags_lock));
- ASSERT(completion_done(&ip->i_flush));
+ ASSERT(!xfs_isiflocked(ip));
ASSERT(ip->i_ino == 0);
mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
@@ -151,7 +151,7 @@ xfs_inode_free(
/* asserts to verify all state is correct here */
ASSERT(atomic_read(&ip->i_pincount) == 0);
ASSERT(!spin_is_locked(&ip->i_flags_lock));
- ASSERT(completion_done(&ip->i_flush));
+ ASSERT(!xfs_isiflocked(ip));
/*
* Because we use RCU freeing we need to ensure the inode always
@@ -716,3 +716,19 @@ xfs_isilocked(
return 0;
}
#endif
+
+void
+__xfs_iflock(
+ struct xfs_inode *ip)
+{
+ wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT);
+ DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT);
+
+ do {
+ prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
+ if (xfs_isiflocked(ip))
+ io_schedule();
+ } while (!xfs_iflock_nowait(ip));
+
+ finish_wait(wq, &wait.wait);
+}
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-10-27 22:39:36.936671273 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-10-27 22:39:53.004672919 +0200
@@ -2510,7 +2510,7 @@ xfs_iflush(
XFS_STATS_INC(xs_iflush_count);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
- ASSERT(!completion_done(&ip->i_flush));
+ ASSERT(xfs_isiflocked(ip));
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > ip->i_df.if_ext_max);
@@ -2626,7 +2626,7 @@ xfs_iflush_int(
#endif
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
- ASSERT(!completion_done(&ip->i_flush));
+ ASSERT(xfs_isiflocked(ip));
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > ip->i_df.if_ext_max);
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:52.102172907 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:39:53.008686681 +0200
@@ -244,7 +244,6 @@ typedef struct xfs_inode {
struct xfs_inode_log_item *i_itemp; /* logging information */
mrlock_t i_lock; /* inode lock */
mrlock_t i_iolock; /* inode IO lock */
- struct completion i_flush; /* inode flush completion q */
atomic_t i_pincount; /* inode pin count */
wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */
spinlock_t i_flags_lock; /* inode i_flags lock */
@@ -331,6 +330,19 @@ xfs_iflags_test_and_clear(xfs_inode_t *i
return ret;
}
+static inline int
+xfs_iflags_test_and_set(xfs_inode_t *ip, unsigned short flags)
+{
+ int ret;
+
+ spin_lock(&ip->i_flags_lock);
+ ret = ip->i_flags & flags;
+ if (!ret)
+ ip->i_flags |= flags;
+ spin_unlock(&ip->i_flags_lock);
+ return ret;
+}
+
/*
* Project quota id helpers (previously projid was 16bit only
* and using two 16bit values to hold new 32bit projid was chosen
@@ -351,35 +363,17 @@ xfs_set_projid(struct xfs_inode *ip,
}
/*
- * Manage the i_flush queue embedded in the inode. This completion
- * queue synchronizes processes attempting to flush the in-core
- * inode back to disk.
- */
-static inline void xfs_iflock(xfs_inode_t *ip)
-{
- wait_for_completion(&ip->i_flush);
-}
-
-static inline int xfs_iflock_nowait(xfs_inode_t *ip)
-{
- return try_wait_for_completion(&ip->i_flush);
-}
-
-static inline void xfs_ifunlock(xfs_inode_t *ip)
-{
- complete(&ip->i_flush);
-}
-
-/*
* In-core inode flags.
*/
-#define XFS_IRECLAIM 0x0001 /* started reclaiming this inode */
-#define XFS_ISTALE 0x0002 /* inode has been staled */
-#define XFS_IRECLAIMABLE 0x0004 /* inode can be reclaimed */
-#define XFS_INEW 0x0008 /* inode has just been allocated */
-#define XFS_IFILESTREAM 0x0010 /* inode is in a filestream directory */
-#define XFS_ITRUNCATED 0x0020 /* truncated down so flush-on-close */
-#define XFS_IDIRTY_RELEASE 0x0040 /* dirty release already seen */
+#define XFS_IRECLAIM (1 << 0) /* started reclaiming this inode */
+#define XFS_ISTALE (1 << 1) /* inode has been staled */
+#define XFS_IRECLAIMABLE (1 << 2) /* inode can be reclaimed */
+#define XFS_INEW (1 << 3) /* inode has just been allocated */
+#define XFS_IFILESTREAM (1 << 4) /* inode is in a filestream dir. */
+#define XFS_ITRUNCATED (1 << 5) /* truncated down so flush-on-close */
+#define XFS_IDIRTY_RELEASE (1 << 6) /* dirty release already seen */
+#define __XFS_IFLOCK_BIT 7 /* inode is being flushed right now */
+#define XFS_IFLOCK (1 << __XFS_IFLOCK_BIT)
/*
* Per-lifetime flags need to be reset when re-using a reclaimable inode during
@@ -392,6 +386,34 @@ static inline void xfs_ifunlock(xfs_inod
XFS_IFILESTREAM);
/*
+ * Synchronize processes attempting to flush the in-core inode back to disk.
+ */
+
+extern void __xfs_iflock(struct xfs_inode *ip);
+
+static inline int xfs_iflock_nowait(struct xfs_inode *ip)
+{
+ return !xfs_iflags_test_and_set(ip, XFS_IFLOCK);
+}
+
+static inline void xfs_iflock(struct xfs_inode *ip)
+{
+ if (!xfs_iflock_nowait(ip))
+ __xfs_iflock(ip);
+}
+
+static inline void xfs_ifunlock(struct xfs_inode *ip)
+{
+ xfs_iflags_clear(ip, XFS_IFLOCK);
+ wake_up_bit(&ip->i_flags, __XFS_IFLOCK_BIT);
+}
+
+static inline int xfs_isiflocked(struct xfs_inode *ip)
+{
+ return xfs_iflags_test(ip, XFS_IFLOCK);
+}
+
+/*
* Flags for inode locking.
* Bit ranges: 1<<1 - 1<<16-1 -- iolock/ilock modes (bitfield)
* 1<<16 - 1<<32-1 -- lockdep annotation (integers)
Index: xfs/fs/xfs/xfs_inode_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode_item.c 2011-10-27 22:39:42.528674212 +0200
+++ xfs/fs/xfs/xfs_inode_item.c 2011-10-27 22:39:53.012672850 +0200
@@ -721,7 +721,7 @@ xfs_inode_item_pushbuf(
* If a flush is not in progress anymore, chances are that the
* inode was taken off the AIL. So, just get out.
*/
- if (completion_done(&ip->i_flush) ||
+ if (!xfs_isiflocked(ip) ||
!(lip->li_flags & XFS_LI_IN_AIL)) {
xfs_iunlock(ip, XFS_ILOCK_SHARED);
return true;
@@ -754,7 +754,7 @@ xfs_inode_item_push(
struct xfs_inode *ip = iip->ili_inode;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
- ASSERT(!completion_done(&ip->i_flush));
+ ASSERT(xfs_isiflocked(ip));
/*
* Since we were able to lock the inode's flush lock and
Index: xfs/fs/xfs/xfs_super.c
===================================================================
--- xfs.orig/fs/xfs/xfs_super.c 2011-10-27 22:39:36.964673921 +0200
+++ xfs/fs/xfs/xfs_super.c 2011-10-27 22:39:53.012672850 +0200
@@ -838,13 +838,6 @@ xfs_fs_inode_init_once(
atomic_set(&ip->i_pincount, 0);
spin_lock_init(&ip->i_flags_lock);
init_waitqueue_head(&ip->i_ipin_wait);
- /*
- * Because we want to use a counting completion, complete
- * the flush completion once to allow a single access to
- * the flush completion without blocking.
- */
- init_completion(&ip->i_flush);
- complete(&ip->i_flush);
mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
"xfsino", ip->i_ino);
Index: xfs/fs/xfs/xfs_sync.c
===================================================================
--- xfs.orig/fs/xfs/xfs_sync.c 2011-10-27 22:39:36.972673407 +0200
+++ xfs/fs/xfs/xfs_sync.c 2011-10-27 22:39:53.016673088 +0200
@@ -675,14 +675,13 @@ xfs_reclaim_inode_grab(
return 1;
/*
- * do some unlocked checks first to avoid unnecessary lock traffic.
- * The first is a flush lock check, the second is a already in reclaim
- * check. Only do these checks if we are not going to block on locks.
+ * If we are asked for non-blocking operation, do unlocked checks to
+ * see if the inode already is being flushed or in reclaim to avoid
+ * lock traffic.
*/
if ((flags & SYNC_TRYLOCK) &&
- (!ip->i_flush.done || __xfs_iflags_test(ip, XFS_IRECLAIM))) {
+ __xfs_iflags_test(ip, XFS_IFLOCK | XFS_IRECLAIM))
return 1;
- }
/*
* The radix tree lock here protects a thread in xfs_iget from racing
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 04/45] xfs: replace i_pin_wait with a bit waitqueue
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (2 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 03/45] xfs: replace i_flock with a sleeping bitlock Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 05/45] xfs: remove the unused dm_attrs structure Christoph Hellwig
` (37 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-kill-i_ipin_wait --]
[-- Type: text/plain, Size: 4084 bytes --]
Replace i_pin_wait, which is only used during synchronous inode flushing
with a bit waitqueue. This trades off a much smaller inode against
slightly slower wakeup performance, and saves 12 (32-bit) or 20 (64-bit)
bytes in the XFS inode.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alex Elder <aelder@sgi.com>
---
fs/xfs/xfs_inode.c | 27 +++++++++++++++++++++------
fs/xfs/xfs_inode.h | 3 ++-
fs/xfs/xfs_inode_item.c | 2 +-
fs/xfs/xfs_super.c | 1 -
4 files changed, 24 insertions(+), 9 deletions(-)
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-10-27 22:39:53.004672919 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-10-27 22:39:53.698172120 +0200
@@ -2151,7 +2151,7 @@ xfs_idestroy_fork(
* once someone is waiting for it to be unpinned.
*/
static void
-xfs_iunpin_nowait(
+xfs_iunpin(
struct xfs_inode *ip)
{
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
@@ -2163,14 +2163,29 @@ xfs_iunpin_nowait(
}
+static void
+__xfs_iunpin_wait(
+ struct xfs_inode *ip)
+{
+ wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IPINNED_BIT);
+ DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IPINNED_BIT);
+
+ xfs_iunpin(ip);
+
+ do {
+ prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
+ if (xfs_ipincount(ip))
+ io_schedule();
+ } while (xfs_ipincount(ip));
+ finish_wait(wq, &wait.wait);
+}
+
void
xfs_iunpin_wait(
struct xfs_inode *ip)
{
- if (xfs_ipincount(ip)) {
- xfs_iunpin_nowait(ip);
- wait_event(ip->i_ipin_wait, (xfs_ipincount(ip) == 0));
- }
+ if (xfs_ipincount(ip))
+ __xfs_iunpin_wait(ip);
}
/*
@@ -2529,7 +2544,7 @@ xfs_iflush(
* out for us if they occur after the log force completes.
*/
if (!(flags & SYNC_WAIT) && xfs_ipincount(ip)) {
- xfs_iunpin_nowait(ip);
+ xfs_iunpin(ip);
xfs_ifunlock(ip);
return EAGAIN;
}
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:53.008686681 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:39:53.698172120 +0200
@@ -245,7 +245,6 @@ typedef struct xfs_inode {
mrlock_t i_lock; /* inode lock */
mrlock_t i_iolock; /* inode IO lock */
atomic_t i_pincount; /* inode pin count */
- wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */
spinlock_t i_flags_lock; /* inode i_flags lock */
/* Miscellaneous state. */
unsigned long i_flags; /* see defined flags below */
@@ -374,6 +373,8 @@ xfs_set_projid(struct xfs_inode *ip,
#define XFS_IDIRTY_RELEASE (1 << 6) /* dirty release already seen */
#define __XFS_IFLOCK_BIT 7 /* inode is being flushed right now */
#define XFS_IFLOCK (1 << __XFS_IFLOCK_BIT)
+#define __XFS_IPINNED_BIT 8 /* wakeup key for zero pin count */
+#define XFS_IPINNED (1 << __XFS_IPINNED_BIT)
/*
* Per-lifetime flags need to be reset when re-using a reclaimable inode during
Index: xfs/fs/xfs/xfs_inode_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode_item.c 2011-10-27 22:39:53.012672850 +0200
+++ xfs/fs/xfs/xfs_inode_item.c 2011-10-27 22:39:53.698172120 +0200
@@ -559,7 +559,7 @@ xfs_inode_item_unpin(
trace_xfs_inode_unpin(ip, _RET_IP_);
ASSERT(atomic_read(&ip->i_pincount) > 0);
if (atomic_dec_and_test(&ip->i_pincount))
- wake_up(&ip->i_ipin_wait);
+ wake_up_bit(&ip->i_flags, __XFS_IPINNED_BIT);
}
/*
Index: xfs/fs/xfs/xfs_super.c
===================================================================
--- xfs.orig/fs/xfs/xfs_super.c 2011-10-27 22:39:53.012672850 +0200
+++ xfs/fs/xfs/xfs_super.c 2011-10-27 22:39:53.702172231 +0200
@@ -837,7 +837,6 @@ xfs_fs_inode_init_once(
/* xfs inode */
atomic_set(&ip->i_pincount, 0);
spin_lock_init(&ip->i_flags_lock);
- init_waitqueue_head(&ip->i_ipin_wait);
mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
"xfsino", ip->i_ino);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 05/45] xfs: remove the unused dm_attrs structure
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (3 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 04/45] xfs: replace i_pin_wait with a bit waitqueue Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 06/45] xfs: remove xfs_itruncate_data Christoph Hellwig
` (36 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-remove-dm_attrs --]
[-- Type: text/plain, Size: 1190 bytes --]
.. and the just as dead bhv_desc forward declaration while we're at it.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alex Elder <aelder@sgi.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
---
fs/xfs/xfs_inode.h | 7 -------
1 file changed, 7 deletions(-)
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:53.698172120 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:39:54.225671131 +0200
@@ -211,7 +211,6 @@ typedef struct xfs_icdinode {
#ifdef __KERNEL__
-struct bhv_desc;
struct xfs_buf;
struct xfs_bmap_free;
struct xfs_bmbt_irec;
@@ -220,12 +219,6 @@ struct xfs_mount;
struct xfs_trans;
struct xfs_dquot;
-typedef struct dm_attrs_s {
- __uint32_t da_dmevmask; /* DMIG event mask */
- __uint16_t da_dmstate; /* DMIG state info */
- __uint16_t da_pad; /* DMIG extra padding */
-} dm_attrs_t;
-
typedef struct xfs_inode {
/* Inode linking and identification information. */
struct xfs_mount *i_mount; /* fs mount struct ptr */
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 06/45] xfs: remove xfs_itruncate_data
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (4 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 05/45] xfs: remove the unused dm_attrs structure Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 07/45] xfs: cleanup xfs_iomap_eof_align_last_fsb Christoph Hellwig
` (35 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-kill-xfs_itruncate_data --]
[-- Type: text/plain, Size: 14594 bytes --]
This wrapper isn't overly useful, not to say rather confusing.
Around the call to xfs_itruncate_extents it does:
- add tracing
- add a few asserts in debug builds
- conditionally update the inode size in two places
- log the inode
Both the tracing and the inode logging can be moved to xfs_itruncate_extents
as they are useful for the attribute fork as well - in fact the attr code
already does an equivalent xfs_trans_log_inode call just after calling
xfs_itruncate_extents. The conditional size updates are a mess, and there
was no reason to do them in two places anyway, as the first one was
conditional on the inode having extents - but without extents we
xfs_itruncate_extents would be a no-op and the placement wouldn't matter
anyway. Instead move the size assignments and the asserts that make sense
to the callers that want it.
As a side effect of this clean up xfs_setattr_size by introducing variables
for the old and new inode size, and moving the size updates into a common
place.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_attr.c | 4 -
fs/xfs/xfs_inode.c | 124 +++--------------------------------------------
fs/xfs/xfs_inode.h | 2
fs/xfs/xfs_iops.c | 47 +++++++++++------
fs/xfs/xfs_qm_syscalls.c | 9 +++
fs/xfs/xfs_trace.h | 4 -
fs/xfs/xfs_vnodeops.c | 17 +++++-
7 files changed, 65 insertions(+), 142 deletions(-)
Index: xfs/fs/xfs/xfs_attr.c
===================================================================
--- xfs.orig/fs/xfs/xfs_attr.c 2011-10-27 22:39:36.520671560 +0200
+++ xfs/fs/xfs/xfs_attr.c 2011-10-27 22:39:54.750171592 +0200
@@ -827,10 +827,6 @@ xfs_attr_inactive(xfs_inode_t *dp)
if (error)
goto out;
- /*
- * Commit the last in the sequence of transactions.
- */
- xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-10-27 22:39:53.698172120 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-10-27 22:39:54.754172457 +0200
@@ -1166,52 +1166,6 @@ xfs_ialloc(
}
/*
- * Check to make sure that there are no blocks allocated to the
- * file beyond the size of the file. We don't check this for
- * files with fixed size extents or real time extents, but we
- * at least do it for regular files.
- */
-#ifdef DEBUG
-STATIC void
-xfs_isize_check(
- struct xfs_inode *ip,
- xfs_fsize_t isize)
-{
- struct xfs_mount *mp = ip->i_mount;
- xfs_fileoff_t map_first;
- int nimaps;
- xfs_bmbt_irec_t imaps[2];
- int error;
-
- if (!S_ISREG(ip->i_d.di_mode))
- return;
-
- if (XFS_IS_REALTIME_INODE(ip))
- return;
-
- if (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
- return;
-
- nimaps = 2;
- map_first = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize);
- /*
- * The filesystem could be shutting down, so bmapi may return
- * an error.
- */
- error = xfs_bmapi_read(ip, map_first,
- (XFS_B_TO_FSB(mp,
- (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - map_first),
- imaps, &nimaps, XFS_BMAPI_ENTIRE);
- if (error)
- return;
- ASSERT(nimaps == 1);
- ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK);
-}
-#else /* DEBUG */
-#define xfs_isize_check(ip, isize)
-#endif /* DEBUG */
-
-/*
* Free up the underlying blocks past new_size. The new size must be smaller
* than the current size. This routine can be used both for the attribute and
* data fork, and does not modify the inode size, which is left to the caller.
@@ -1258,6 +1212,8 @@ xfs_itruncate_extents(
ASSERT(ip->i_itemp->ili_lock_flags == 0);
ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
+ trace_xfs_itruncate_extents_start(ip, new_size);
+
/*
* Since it is possible for space to become allocated beyond
* the end of the file (in a crash where the space is allocated
@@ -1325,6 +1281,14 @@ xfs_itruncate_extents(
goto out;
}
+ /*
+ * Always re-log the inode so that our permanent transaction can keep
+ * on rolling it forward in the log.
+ */
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+ trace_xfs_itruncate_extents_end(ip, new_size);
+
out:
*tpp = tp;
return error;
@@ -1338,74 +1302,6 @@ out_bmap_cancel:
goto out;
}
-int
-xfs_itruncate_data(
- struct xfs_trans **tpp,
- struct xfs_inode *ip,
- xfs_fsize_t new_size)
-{
- int error;
-
- trace_xfs_itruncate_data_start(ip, new_size);
-
- /*
- * The first thing we do is set the size to new_size permanently on
- * disk. This way we don't have to worry about anyone ever being able
- * to look at the data being freed even in the face of a crash.
- * What we're getting around here is the case where we free a block, it
- * is allocated to another file, it is written to, and then we crash.
- * If the new data gets written to the file but the log buffers
- * containing the free and reallocation don't, then we'd end up with
- * garbage in the blocks being freed. As long as we make the new_size
- * permanent before actually freeing any blocks it doesn't matter if
- * they get written to.
- */
- if (ip->i_d.di_nextents > 0) {
- /*
- * If we are not changing the file size then do not update
- * the on-disk file size - we may be called from
- * xfs_inactive_free_eofblocks(). If we update the on-disk
- * file size and then the system crashes before the contents
- * of the file are flushed to disk then the files may be
- * full of holes (ie NULL files bug).
- */
- if (ip->i_size != new_size) {
- ip->i_d.di_size = new_size;
- ip->i_size = new_size;
- xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
- }
- }
-
- error = xfs_itruncate_extents(tpp, ip, XFS_DATA_FORK, new_size);
- if (error)
- return error;
-
- /*
- * If we are not changing the file size then do not update the on-disk
- * file size - we may be called from xfs_inactive_free_eofblocks().
- * If we update the on-disk file size and then the system crashes
- * before the contents of the file are flushed to disk then the files
- * may be full of holes (ie NULL files bug).
- */
- xfs_isize_check(ip, new_size);
- if (ip->i_size != new_size) {
- ip->i_d.di_size = new_size;
- ip->i_size = new_size;
- }
-
- ASSERT(new_size != 0 || ip->i_delayed_blks == 0);
- ASSERT(new_size != 0 || ip->i_d.di_nextents == 0);
-
- /*
- * Always re-log the inode so that our permanent transaction can keep
- * on rolling it forward in the log.
- */
- xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
-
- trace_xfs_itruncate_data_end(ip, new_size);
- return 0;
-}
-
/*
* This is called when the inode's link count goes to 0.
* We place the on-disk inode on a list in the AGI. It
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:54.225671131 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:39:54.754172457 +0200
@@ -507,8 +507,6 @@ int xfs_ifree(struct xfs_trans *, xfs_i
struct xfs_bmap_free *);
int xfs_itruncate_extents(struct xfs_trans **, struct xfs_inode *,
int, xfs_fsize_t);
-int xfs_itruncate_data(struct xfs_trans **, struct xfs_inode *,
- xfs_fsize_t);
int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
void xfs_iext_realloc(xfs_inode_t *, int, int);
Index: xfs/fs/xfs/xfs_iops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iops.c 2011-10-27 22:39:36.556673625 +0200
+++ xfs/fs/xfs/xfs_iops.c 2011-10-27 22:39:54.754172457 +0200
@@ -749,6 +749,7 @@ xfs_setattr_size(
struct xfs_mount *mp = ip->i_mount;
struct inode *inode = VFS_I(ip);
int mask = iattr->ia_valid;
+ xfs_off_t oldsize, newsize;
struct xfs_trans *tp;
int error;
uint lock_flags;
@@ -776,11 +777,13 @@ xfs_setattr_size(
lock_flags |= XFS_IOLOCK_EXCL;
xfs_ilock(ip, lock_flags);
+ oldsize = ip->i_size;
+ newsize = iattr->ia_size;
+
/*
* Short circuit the truncate case for zero length files.
*/
- if (iattr->ia_size == 0 &&
- ip->i_size == 0 && ip->i_d.di_nextents == 0) {
+ if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) {
if (!(mask & (ATTR_CTIME|ATTR_MTIME)))
goto out_unlock;
@@ -806,14 +809,14 @@ xfs_setattr_size(
* the inode to the transaction, because the inode cannot be unlocked
* once it is a part of the transaction.
*/
- if (iattr->ia_size > ip->i_size) {
+ if (newsize > oldsize) {
/*
* Do the first part of growing a file: zero any data in the
* last block that is beyond the old EOF. We need to do this
* before the inode is joined to the transaction to modify
* i_size.
*/
- error = xfs_zero_eof(ip, iattr->ia_size, ip->i_size);
+ error = xfs_zero_eof(ip, newsize, oldsize);
if (error)
goto out_unlock;
}
@@ -832,8 +835,8 @@ xfs_setattr_size(
* here and prevents waiting for other data not within the range we
* care about here.
*/
- if (ip->i_size != ip->i_d.di_size && iattr->ia_size > ip->i_d.di_size) {
- error = xfs_flush_pages(ip, ip->i_d.di_size, iattr->ia_size, 0,
+ if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) {
+ error = xfs_flush_pages(ip, ip->i_d.di_size, newsize, 0,
FI_NONE);
if (error)
goto out_unlock;
@@ -844,8 +847,7 @@ xfs_setattr_size(
*/
inode_dio_wait(inode);
- error = -block_truncate_page(inode->i_mapping, iattr->ia_size,
- xfs_get_blocks);
+ error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks);
if (error)
goto out_unlock;
@@ -856,7 +858,7 @@ xfs_setattr_size(
if (error)
goto out_trans_cancel;
- truncate_setsize(inode, iattr->ia_size);
+ truncate_setsize(inode, newsize);
commit_flags = XFS_TRANS_RELEASE_LOG_RES;
lock_flags |= XFS_ILOCK_EXCL;
@@ -875,19 +877,30 @@ xfs_setattr_size(
* these flags set. For all other operations the VFS set these flags
* explicitly if it wants a timestamp update.
*/
- if (iattr->ia_size != ip->i_size &&
- (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
+ if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
iattr->ia_ctime = iattr->ia_mtime =
current_fs_time(inode->i_sb);
mask |= ATTR_CTIME | ATTR_MTIME;
}
- if (iattr->ia_size > ip->i_size) {
- ip->i_d.di_size = iattr->ia_size;
- ip->i_size = iattr->ia_size;
- } else if (iattr->ia_size <= ip->i_size ||
- (iattr->ia_size == 0 && ip->i_d.di_nextents)) {
- error = xfs_itruncate_data(&tp, ip, iattr->ia_size);
+ /*
+ * The first thing we do is set the size to new_size permanently on
+ * disk. This way we don't have to worry about anyone ever being able
+ * to look at the data being freed even in the face of a crash.
+ * What we're getting around here is the case where we free a block, it
+ * is allocated to another file, it is written to, and then we crash.
+ * If the new data gets written to the file but the log buffers
+ * containing the free and reallocation don't, then we'd end up with
+ * garbage in the blocks being freed. As long as we make the new size
+ * permanent before actually freeing any blocks it doesn't matter if
+ * they get written to.
+ */
+ ip->i_d.di_size = newsize;
+ ip->i_size = newsize;
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+ if (newsize <= oldsize) {
+ error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, newsize);
if (error)
goto out_trans_abort;
Index: xfs/fs/xfs/xfs_qm_syscalls.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm_syscalls.c 2011-10-27 22:39:36.564671247 +0200
+++ xfs/fs/xfs/xfs_qm_syscalls.c 2011-10-27 22:39:54.758172111 +0200
@@ -31,6 +31,7 @@
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
+#include "xfs_inode_item.h"
#include "xfs_itable.h"
#include "xfs_bmap.h"
#include "xfs_rtalloc.h"
@@ -263,13 +264,19 @@ xfs_qm_scall_trunc_qfile(
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
- error = xfs_itruncate_data(&tp, ip, 0);
+ ip->i_d.di_size = 0;
+ ip->i_size = 0;
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+ error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
if (error) {
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT);
goto out_unlock;
}
+ ASSERT(ip->i_d.di_nextents == 0);
+
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
Index: xfs/fs/xfs/xfs_trace.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trace.h 2011-10-27 22:39:36.576673656 +0200
+++ xfs/fs/xfs/xfs_trace.h 2011-10-27 22:39:54.766219243 +0200
@@ -1096,8 +1096,8 @@ DECLARE_EVENT_CLASS(xfs_itrunc_class,
DEFINE_EVENT(xfs_itrunc_class, name, \
TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), \
TP_ARGS(ip, new_size))
-DEFINE_ITRUNC_EVENT(xfs_itruncate_data_start);
-DEFINE_ITRUNC_EVENT(xfs_itruncate_data_end);
+DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_start);
+DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_end);
TRACE_EVENT(xfs_pagecache_inval,
TP_PROTO(struct xfs_inode *ip, xfs_off_t start, xfs_off_t finish),
Index: xfs/fs/xfs/xfs_vnodeops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_vnodeops.c 2011-10-27 22:39:36.592672594 +0200
+++ xfs/fs/xfs/xfs_vnodeops.c 2011-10-27 22:39:54.774174431 +0200
@@ -220,7 +220,14 @@ xfs_free_eofblocks(
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
- error = xfs_itruncate_data(&tp, ip, ip->i_size);
+ /*
+ * Do not update the on-disk file size. If we update the
+ * on-disk file size and then the system crashes before the
+ * contents of the file are flushed to disk then the files
+ * may be full of holes (ie NULL files bug).
+ */
+ error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK,
+ ip->i_size);
if (error) {
/*
* If we get an error at this point we simply don't
@@ -664,13 +671,19 @@ xfs_inactive(
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
- error = xfs_itruncate_data(&tp, ip, 0);
+ ip->i_d.di_size = 0;
+ ip->i_size = 0;
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+ error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
if (error) {
xfs_trans_cancel(tp,
XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
return VN_INACTIVE_CACHE;
}
+
+ ASSERT(ip->i_d.di_nextents == 0);
} else if (S_ISLNK(ip->i_d.di_mode)) {
/*
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 07/45] xfs: cleanup xfs_iomap_eof_align_last_fsb
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (5 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 06/45] xfs: remove xfs_itruncate_data Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 08/45] xfs: remove the i_size field in struct xfs_inode Christoph Hellwig
` (34 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-cleanup-xfs_iomap_eof_align_last_fsb --]
[-- Type: text/plain, Size: 2230 bytes --]
Replace the nasty if, else if, elseif condition with more natural C flow
that expressed the logic we want here better.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_iomap.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
Index: xfs/fs/xfs/xfs_iomap.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iomap.c 2011-10-27 22:39:36.380675090 +0200
+++ xfs/fs/xfs/xfs_iomap.c 2011-10-27 22:39:55.230179804 +0200
@@ -57,26 +57,26 @@ xfs_iomap_eof_align_last_fsb(
xfs_fileoff_t *last_fsb)
{
xfs_fileoff_t new_last_fsb = 0;
- xfs_extlen_t align;
+ xfs_extlen_t align = 0;
int eof, error;
- if (XFS_IS_REALTIME_INODE(ip))
- ;
- /*
- * If mounted with the "-o swalloc" option, roundup the allocation
- * request to a stripe width boundary if the file size is >=
- * stripe width and we are allocating past the allocation eof.
- */
- else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) &&
- (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_swidth)))
- new_last_fsb = roundup_64(*last_fsb, mp->m_swidth);
- /*
- * Roundup the allocation request to a stripe unit (m_dalign) boundary
- * if the file size is >= stripe unit size, and we are allocating past
- * the allocation eof.
- */
- else if (mp->m_dalign && (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_dalign)))
- new_last_fsb = roundup_64(*last_fsb, mp->m_dalign);
+ if (!XFS_IS_REALTIME_INODE(ip)) {
+ /*
+ * Round up the allocation request to a stripe unit
+ * (m_dalign) boundary if the file size is >= stripe unit
+ * size, and we are allocating past the allocation eof.
+ *
+ * If mounted with the "-o swalloc" option the alignment is
+ * increased from the strip unit size to the stripe width.
+ */
+ if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC))
+ align = mp->m_swidth;
+ else if (mp->m_dalign)
+ align = mp->m_dalign;
+
+ if (align && ip->i_size >= XFS_FSB_TO_B(mp, align))
+ new_last_fsb = roundup_64(*last_fsb, align);
+ }
/*
* Always round up the allocation request to an extent boundary
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 08/45] xfs: remove the i_size field in struct xfs_inode
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (6 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 07/45] xfs: cleanup xfs_iomap_eof_align_last_fsb Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 09/45] xfs: remove the i_new_size " Christoph Hellwig
` (33 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-kill-i_size --]
[-- Type: text/plain, Size: 17985 bytes --]
There is no fundamental need to keep an in-memory inode size copy in the
XFS inode. We already have the on-disk value in the dinode, and the
separate in-memory copy that we need for regular files only in the
XFS inode.
Remove the xfs_inode i_size field and change the XFS_ISIZE macro to use
the VFS inode i_size field for regular fields. Switch code that was
directly accessing it to either the XFS_ISIZE macro or direct access
of the VFS i_size if the code is limited to regular files and in
highlevel code.
This also allows dropping a a big bunch of fairly complicated code in the
write path which dealt with keeping the xfs_inode i_size uptodate with the
VFS i_size that is getting updated inside ->write_end.
Note that we do not bother resetting the VFS i_size when truncating a file
that gets freed to zero as there is point in doing so. Just relax the
assert in xfs_ifree to only check the on-disk size instead.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_aops.c | 2 +-
fs/xfs/xfs_bmap.c | 15 ++++++---------
fs/xfs/xfs_file.c | 45 +++++++++++----------------------------------
fs/xfs/xfs_fs_subr.c | 2 +-
fs/xfs/xfs_iget.c | 1 -
fs/xfs/xfs_inode.c | 8 ++------
fs/xfs/xfs_inode.h | 16 ++++++++++++----
fs/xfs/xfs_iomap.c | 12 ++++++------
fs/xfs/xfs_iops.c | 3 +--
fs/xfs/xfs_qm_syscalls.c | 1 -
fs/xfs/xfs_trace.h | 2 +-
fs/xfs/xfs_vnodeops.c | 31 +++++++++++++++----------------
12 files changed, 56 insertions(+), 82 deletions(-)
Index: xfs/fs/xfs/xfs_aops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_aops.c 2011-10-27 22:39:36.176673721 +0200
+++ xfs/fs/xfs/xfs_aops.c 2011-10-27 22:39:55.654173048 +0200
@@ -111,7 +111,7 @@ xfs_ioend_new_eof(
xfs_fsize_t bsize;
bsize = ioend->io_offset + ioend->io_size;
- isize = MAX(ip->i_size, ip->i_new_size);
+ isize = MAX(i_size_read(VFS_I(ip)), ip->i_new_size);
isize = MIN(isize, bsize);
return isize > ip->i_d.di_size ? isize : 0;
}
Index: xfs/fs/xfs/xfs_file.c
===================================================================
--- xfs.orig/fs/xfs/xfs_file.c 2011-10-27 22:39:36.188673903 +0200
+++ xfs/fs/xfs/xfs_file.c 2011-10-27 22:39:55.658175758 +0200
@@ -327,7 +327,7 @@ xfs_file_aio_read(
mp->m_rtdev_targp : mp->m_ddev_targp;
if ((iocb->ki_pos & target->bt_smask) ||
(size & target->bt_smask)) {
- if (iocb->ki_pos == ip->i_size)
+ if (iocb->ki_pos == i_size_read(inode))
return 0;
return -XFS_ERROR(EINVAL);
}
@@ -412,30 +412,6 @@ xfs_file_splice_read(
return ret;
}
-STATIC void
-xfs_aio_write_isize_update(
- struct inode *inode,
- loff_t *ppos,
- ssize_t bytes_written)
-{
- struct xfs_inode *ip = XFS_I(inode);
- xfs_fsize_t isize = i_size_read(inode);
-
- if (bytes_written > 0)
- XFS_STATS_ADD(xs_write_bytes, bytes_written);
-
- if (unlikely(bytes_written < 0 && bytes_written != -EFAULT &&
- *ppos > isize))
- *ppos = isize;
-
- if (*ppos > ip->i_size) {
- xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
- if (*ppos > ip->i_size)
- ip->i_size = *ppos;
- xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
- }
-}
-
/*
* If this was a direct or synchronous I/O that failed (such as ENOSPC) then
* part of the I/O may have been written to disk before the error occurred. In
@@ -451,8 +427,8 @@ xfs_aio_write_newsize_update(
xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
if (new_size == ip->i_new_size)
ip->i_new_size = 0;
- if (ip->i_d.di_size > ip->i_size)
- ip->i_d.di_size = ip->i_size;
+ if (ip->i_d.di_size > i_size_read(VFS_I(ip)))
+ ip->i_d.di_size = i_size_read(VFS_I(ip));
xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
}
}
@@ -492,15 +468,16 @@ xfs_file_splice_write(
new_size = *ppos + count;
xfs_ilock(ip, XFS_ILOCK_EXCL);
- if (new_size > ip->i_size)
+ if (new_size > i_size_read(inode))
ip->i_new_size = new_size;
xfs_iunlock(ip, XFS_ILOCK_EXCL);
trace_xfs_file_splice_write(ip, count, *ppos, ioflags);
ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
+ if (ret > 0)
+ XFS_STATS_ADD(xs_write_bytes, ret);
- xfs_aio_write_isize_update(inode, ppos, ret);
xfs_aio_write_newsize_update(ip, new_size);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return ret;
@@ -728,14 +705,14 @@ restart:
* values are still valid.
*/
if ((ip->i_new_size && *pos > ip->i_new_size) ||
- (!ip->i_new_size && *pos > ip->i_size)) {
+ (!ip->i_new_size && *pos > i_size_read(inode))) {
if (*iolock == XFS_IOLOCK_SHARED) {
xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
*iolock = XFS_IOLOCK_EXCL;
xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
goto restart;
}
- error = -xfs_zero_eof(ip, *pos, ip->i_size);
+ error = -xfs_zero_eof(ip, *pos, i_size_read(inode));
}
/*
@@ -744,7 +721,7 @@ restart:
* ip->i_new_size if this IO ends beyond any other in-flight writes.
*/
new_size = *pos + *count;
- if (new_size > ip->i_size) {
+ if (new_size > i_size_read(inode)) {
if (new_size > ip->i_new_size)
ip->i_new_size = new_size;
*new_sizep = new_size;
@@ -957,11 +934,11 @@ xfs_file_aio_write(
ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos,
ocount, &new_size, &iolock);
- xfs_aio_write_isize_update(inode, &iocb->ki_pos, ret);
-
if (ret <= 0)
goto out_unlock;
+ XFS_STATS_ADD(xs_write_bytes, ret);
+
/* Handle various SYNC-type writes */
if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
loff_t end = pos + ret - 1;
Index: xfs/fs/xfs/xfs_fs_subr.c
===================================================================
--- xfs.orig/fs/xfs/xfs_fs_subr.c 2011-10-27 22:39:36.200674939 +0200
+++ xfs/fs/xfs/xfs_fs_subr.c 2011-10-27 22:39:55.658175758 +0200
@@ -90,7 +90,7 @@ xfs_wait_on_pages(
if (mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) {
return -filemap_fdatawait_range(mapping, first,
- last == -1 ? ip->i_size - 1 : last);
+ last == -1 ? XFS_ISIZE(ip) - 1 : last);
}
return 0;
}
Index: xfs/fs/xfs/xfs_iops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iops.c 2011-10-27 22:39:54.754172457 +0200
+++ xfs/fs/xfs/xfs_iops.c 2011-10-27 22:39:55.662176606 +0200
@@ -777,7 +777,7 @@ xfs_setattr_size(
lock_flags |= XFS_IOLOCK_EXCL;
xfs_ilock(ip, lock_flags);
- oldsize = ip->i_size;
+ oldsize = inode->i_size;
newsize = iattr->ia_size;
/*
@@ -896,7 +896,6 @@ xfs_setattr_size(
* they get written to.
*/
ip->i_d.di_size = newsize;
- ip->i_size = newsize;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
if (newsize <= oldsize) {
Index: xfs/fs/xfs/xfs_trace.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trace.h 2011-10-27 22:39:54.766219243 +0200
+++ xfs/fs/xfs/xfs_trace.h 2011-10-27 22:39:55.670178173 +0200
@@ -1044,7 +1044,7 @@ DECLARE_EVENT_CLASS(xfs_simple_io_class,
TP_fast_assign(
__entry->dev = VFS_I(ip)->i_sb->s_dev;
__entry->ino = ip->i_ino;
- __entry->isize = ip->i_size;
+ __entry->isize = VFS_I(ip)->i_size;
__entry->disize = ip->i_d.di_size;
__entry->new_size = ip->i_new_size;
__entry->offset = offset;
Index: xfs/fs/xfs/xfs_bmap.c
===================================================================
--- xfs.orig/fs/xfs/xfs_bmap.c 2011-10-27 22:39:36.232674580 +0200
+++ xfs/fs/xfs/xfs_bmap.c 2011-10-27 22:39:55.678179028 +0200
@@ -3992,11 +3992,8 @@ xfs_bmap_one_block(
xfs_bmbt_irec_t s; /* internal version of extent */
#ifndef DEBUG
- if (whichfork == XFS_DATA_FORK) {
- return S_ISREG(ip->i_d.di_mode) ?
- (ip->i_size == ip->i_mount->m_sb.sb_blocksize) :
- (ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize);
- }
+ if (whichfork == XFS_DATA_FORK)
+ return XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize;
#endif /* !DEBUG */
if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1)
return 0;
@@ -4008,7 +4005,7 @@ xfs_bmap_one_block(
xfs_bmbt_get_all(ep, &s);
rval = s.br_startoff == 0 && s.br_blockcount == 1;
if (rval && whichfork == XFS_DATA_FORK)
- ASSERT(ip->i_size == ip->i_mount->m_sb.sb_blocksize);
+ ASSERT(XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize);
return rval;
}
@@ -5416,7 +5413,7 @@ xfs_getbmapx_fix_eof_hole(
if (startblock == HOLESTARTBLOCK) {
mp = ip->i_mount;
out->bmv_block = -1;
- fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, ip->i_size));
+ fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, XFS_ISIZE(ip)));
fixlen -= out->bmv_offset;
if (prealloced && out->bmv_offset + out->bmv_length == end) {
/* Came to hole at EOF. Trim it. */
@@ -5504,7 +5501,7 @@ xfs_getbmap(
fixlen = XFS_MAXIOFFSET(mp);
} else {
prealloced = 0;
- fixlen = ip->i_size;
+ fixlen = XFS_ISIZE(ip);
}
}
@@ -5533,7 +5530,7 @@ xfs_getbmap(
xfs_ilock(ip, XFS_IOLOCK_SHARED);
if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
- if (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size) {
+ if (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size) {
error = xfs_flush_pages(ip, 0, -1, 0, FI_REMAPF);
if (error)
goto out_unlock_iolock;
Index: xfs/fs/xfs/xfs_iget.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iget.c 2011-10-27 22:39:53.000673410 +0200
+++ xfs/fs/xfs/xfs_iget.c 2011-10-27 22:39:55.686173105 +0200
@@ -94,7 +94,6 @@ xfs_inode_alloc(
ip->i_update_core = 0;
ip->i_delayed_blks = 0;
memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
- ip->i_size = 0;
ip->i_new_size = 0;
return ip;
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-10-27 22:39:54.754172457 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-10-27 22:39:55.694176578 +0200
@@ -350,7 +350,6 @@ xfs_iformat(
return XFS_ERROR(EFSCORRUPTED);
}
ip->i_d.di_size = 0;
- ip->i_size = 0;
ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
break;
@@ -861,7 +860,6 @@ xfs_iread(
}
ip->i_delayed_blks = 0;
- ip->i_size = ip->i_d.di_size;
/*
* Mark the buffer containing the inode as something to keep
@@ -1051,7 +1049,6 @@ xfs_ialloc(
}
ip->i_d.di_size = 0;
- ip->i_size = 0;
ip->i_d.di_nextents = 0;
ASSERT(ip->i_d.di_nblocks == 0);
@@ -1206,7 +1203,7 @@ xfs_itruncate_extents(
int done = 0;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
- ASSERT(new_size <= ip->i_size);
+ ASSERT(new_size <= XFS_ISIZE(ip));
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
ASSERT(ip->i_itemp != NULL);
ASSERT(ip->i_itemp->ili_lock_flags == 0);
@@ -1720,8 +1717,7 @@ xfs_ifree(
ASSERT(ip->i_d.di_nlink == 0);
ASSERT(ip->i_d.di_nextents == 0);
ASSERT(ip->i_d.di_anextents == 0);
- ASSERT((ip->i_d.di_size == 0 && ip->i_size == 0) ||
- (!S_ISREG(ip->i_d.di_mode)));
+ ASSERT(ip->i_d.di_size == 0 || !S_ISREG(ip->i_d.di_mode));
ASSERT(ip->i_d.di_nblocks == 0);
/*
Index: xfs/fs/xfs/xfs_iomap.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iomap.c 2011-10-27 22:39:55.230179804 +0200
+++ xfs/fs/xfs/xfs_iomap.c 2011-10-27 22:39:55.694176578 +0200
@@ -74,7 +74,7 @@ xfs_iomap_eof_align_last_fsb(
else if (mp->m_dalign)
align = mp->m_dalign;
- if (align && ip->i_size >= XFS_FSB_TO_B(mp, align))
+ if (align && XFS_ISIZE(ip) >= XFS_FSB_TO_B(mp, align))
new_last_fsb = roundup_64(*last_fsb, align);
}
@@ -154,7 +154,7 @@ xfs_iomap_write_direct(
offset_fsb = XFS_B_TO_FSBT(mp, offset);
last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
- if ((offset + count) > ip->i_size) {
+ if ((offset + count) > XFS_ISIZE(ip)) {
error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
if (error)
goto error_out;
@@ -211,7 +211,7 @@ xfs_iomap_write_direct(
xfs_trans_ijoin(tp, ip, 0);
bmapi_flag = 0;
- if (offset < ip->i_size || extsz)
+ if (offset < XFS_ISIZE(ip) || extsz)
bmapi_flag |= XFS_BMAPI_PREALLOC;
/*
@@ -286,7 +286,7 @@ xfs_iomap_eof_want_preallocate(
int found_delalloc = 0;
*prealloc = 0;
- if ((offset + count) <= ip->i_size)
+ if (offset + count <= XFS_ISIZE(ip))
return 0;
/*
@@ -340,7 +340,7 @@ xfs_iomap_prealloc_size(
* if we pass in alloc_blocks = 0. Hence the "+ 1" to
* ensure we always pass in a non-zero value.
*/
- alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size) + 1;
+ alloc_blocks = XFS_B_TO_FSB(mp, XFS_ISIZE(ip)) + 1;
alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN,
rounddown_pow_of_two(alloc_blocks));
@@ -564,7 +564,7 @@ xfs_iomap_write_allocate(
* back....
*/
nimaps = 1;
- end_fsb = XFS_B_TO_FSB(mp, ip->i_size);
+ end_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip));
error = xfs_bmap_last_offset(NULL, ip, &last_block,
XFS_DATA_FORK);
if (error)
Index: xfs/fs/xfs/xfs_vnodeops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_vnodeops.c 2011-10-27 22:39:54.774174431 +0200
+++ xfs/fs/xfs/xfs_vnodeops.c 2011-10-27 22:39:55.698174631 +0200
@@ -169,7 +169,7 @@ xfs_free_eofblocks(
* Figure out if there are any blocks beyond the end
* of the file. If not, then there is nothing to do.
*/
- end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));
+ end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
if (last_fsb <= end_fsb)
return 0;
@@ -227,7 +227,7 @@ xfs_free_eofblocks(
* may be full of holes (ie NULL files bug).
*/
error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK,
- ip->i_size);
+ XFS_ISIZE(ip));
if (error) {
/*
* If we get an error at this point we simply don't
@@ -541,8 +541,8 @@ xfs_release(
return 0;
if ((S_ISREG(ip->i_d.di_mode) &&
- ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
- ip->i_delayed_blks > 0)) &&
+ (VFS_I(ip)->i_size > 0 ||
+ (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) &&
(ip->i_df.if_flags & XFS_IFEXTENTS)) &&
(!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
@@ -619,7 +619,7 @@ xfs_inactive(
* only one with a reference to the inode.
*/
truncate = ((ip->i_d.di_nlink == 0) &&
- ((ip->i_d.di_size != 0) || (ip->i_size != 0) ||
+ ((ip->i_d.di_size != 0) || XFS_ISIZE(ip) != 0 ||
(ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
S_ISREG(ip->i_d.di_mode));
@@ -633,12 +633,12 @@ xfs_inactive(
if (ip->i_d.di_nlink != 0) {
if ((S_ISREG(ip->i_d.di_mode) &&
- ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
- ip->i_delayed_blks > 0)) &&
- (ip->i_df.if_flags & XFS_IFEXTENTS) &&
- (!(ip->i_d.di_flags &
+ (VFS_I(ip)->i_size > 0 ||
+ (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) &&
+ (ip->i_df.if_flags & XFS_IFEXTENTS) &&
+ (!(ip->i_d.di_flags &
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
- (ip->i_delayed_blks != 0)))) {
+ ip->i_delayed_blks != 0))) {
error = xfs_free_eofblocks(mp, ip, 0);
if (error)
return VN_INACTIVE_CACHE;
@@ -672,7 +672,6 @@ xfs_inactive(
xfs_trans_ijoin(tp, ip, 0);
ip->i_d.di_size = 0;
- ip->i_size = 0;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
@@ -1968,11 +1967,11 @@ xfs_zero_remaining_bytes(
* since nothing can read beyond eof. The space will
* be zeroed when the file is extended anyway.
*/
- if (startoff >= ip->i_size)
+ if (startoff >= XFS_ISIZE(ip))
return 0;
- if (endoff > ip->i_size)
- endoff = ip->i_size;
+ if (endoff > XFS_ISIZE(ip))
+ endoff = XFS_ISIZE(ip);
bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
mp->m_rtdev_targp : mp->m_ddev_targp,
@@ -2267,7 +2266,7 @@ xfs_change_file_space(
bf->l_start += offset;
break;
case 2: /*SEEK_END*/
- bf->l_start += ip->i_size;
+ bf->l_start += XFS_ISIZE(ip);
break;
default:
return XFS_ERROR(EINVAL);
@@ -2284,7 +2283,7 @@ xfs_change_file_space(
bf->l_whence = 0;
startoffset = bf->l_start;
- fsize = ip->i_size;
+ fsize = XFS_ISIZE(ip);
/*
* XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:54.754172457 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:39:55.704670968 +0200
@@ -246,16 +246,12 @@ typedef struct xfs_inode {
xfs_icdinode_t i_d; /* most of ondisk inode */
- xfs_fsize_t i_size; /* in-memory size */
xfs_fsize_t i_new_size; /* size when write completes */
/* VFS inode */
struct inode i_vnode; /* embedded VFS inode */
} xfs_inode_t;
-#define XFS_ISIZE(ip) S_ISREG((ip)->i_d.di_mode) ? \
- (ip)->i_size : (ip)->i_d.di_size;
-
/* Convert from vfs inode to xfs inode */
static inline struct xfs_inode *XFS_I(struct inode *inode)
{
@@ -269,6 +265,18 @@ static inline struct inode *VFS_I(struct
}
/*
+ * For regular files we only update the on-disk filesize when actually
+ * writing data back to disk. Until then only the copy in the VFS inode
+ * is uptodate.
+ */
+static inline xfs_fsize_t XFS_ISIZE(struct xfs_inode *ip)
+{
+ if (S_ISREG(ip->i_d.di_mode))
+ return i_size_read(VFS_I(ip));
+ return ip->i_d.di_size;
+}
+
+/*
* i_flags helper functions
*/
static inline void
Index: xfs/fs/xfs/xfs_qm_syscalls.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm_syscalls.c 2011-10-27 22:39:54.758172111 +0200
+++ xfs/fs/xfs/xfs_qm_syscalls.c 2011-10-27 22:39:55.704670968 +0200
@@ -265,7 +265,6 @@ xfs_qm_scall_trunc_qfile(
xfs_trans_ijoin(tp, ip, 0);
ip->i_d.di_size = 0;
- ip->i_size = 0;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 09/45] xfs: remove the i_new_size field in struct xfs_inode
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (7 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 08/45] xfs: remove the i_size field in struct xfs_inode Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 10/45] fix: force shutdown handling in xfs_end_io Christoph Hellwig
` (32 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-kill-i_new_size --]
[-- Type: text/plain, Size: 13733 bytes --]
Now that we use the VFS i_size field throughout XFS there is no need for the
i_new_size field any more given that the VFS i_size field gets updated
in ->write_end before unlocking the page, and thus is a) always uptodate when
writeback could see a page. Removing i_new_size also has the advantage that
we will never have to trim back di_size during a failed buffered write,
given that it never gets updated past i_size.
Note that currently the generic direct I/O code only updates i_size after
calling our end_io handler, which requires a small workaround to make
sure di_size actually makes it to disk. I hope to fix this properly in
the generic code.
A downside is that we lose the support for parallel non-overlapping O_DIRECT
appending writes that recently was added. I don't think keeping the complex
and fragile i_new_size infrastructure for this is a good tradeoff - if we
really care about parallel appending writers we should investigate turning
the iolock into a range lock, which would also allow for parallel
non-overlapping buffered writers.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_aops.c | 28 +++++++++++---------
fs/xfs/xfs_file.c | 72 +++++++----------------------------------------------
fs/xfs/xfs_iget.c | 1
fs/xfs/xfs_inode.h | 2 -
fs/xfs/xfs_trace.h | 18 ++-----------
5 files changed, 29 insertions(+), 92 deletions(-)
Index: xfs/fs/xfs/xfs_file.c
===================================================================
--- xfs.orig/fs/xfs/xfs_file.c 2011-10-27 22:39:55.658175758 +0200
+++ xfs/fs/xfs/xfs_file.c 2011-10-27 22:39:56.068672482 +0200
@@ -413,27 +413,6 @@ xfs_file_splice_read(
}
/*
- * If this was a direct or synchronous I/O that failed (such as ENOSPC) then
- * part of the I/O may have been written to disk before the error occurred. In
- * this case the on-disk file size may have been adjusted beyond the in-memory
- * file size and now needs to be truncated back.
- */
-STATIC void
-xfs_aio_write_newsize_update(
- struct xfs_inode *ip,
- xfs_fsize_t new_size)
-{
- if (new_size == ip->i_new_size) {
- xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
- if (new_size == ip->i_new_size)
- ip->i_new_size = 0;
- if (ip->i_d.di_size > i_size_read(VFS_I(ip)))
- ip->i_d.di_size = i_size_read(VFS_I(ip));
- xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
- }
-}
-
-/*
* xfs_file_splice_write() does not use xfs_rw_ilock() because
* generic_file_splice_write() takes the i_mutex itself. This, in theory,
* couuld cause lock inversions between the aio_write path and the splice path
@@ -451,7 +430,6 @@ xfs_file_splice_write(
{
struct inode *inode = outfilp->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
- xfs_fsize_t new_size;
int ioflags = 0;
ssize_t ret;
@@ -465,20 +443,12 @@ xfs_file_splice_write(
xfs_ilock(ip, XFS_IOLOCK_EXCL);
- new_size = *ppos + count;
-
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- if (new_size > i_size_read(inode))
- ip->i_new_size = new_size;
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
trace_xfs_file_splice_write(ip, count, *ppos, ioflags);
ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
if (ret > 0)
XFS_STATS_ADD(xs_write_bytes, ret);
- xfs_aio_write_newsize_update(ip, new_size);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return ret;
}
@@ -673,16 +643,13 @@ xfs_file_aio_write_checks(
struct file *file,
loff_t *pos,
size_t *count,
- xfs_fsize_t *new_sizep,
int *iolock)
{
struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
- xfs_fsize_t new_size;
int error = 0;
xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
- *new_sizep = 0;
restart:
error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode));
if (error) {
@@ -697,15 +664,13 @@ restart:
/*
* If the offset is beyond the size of the file, we need to zero any
* blocks that fall between the existing EOF and the start of this
- * write. There is no need to issue zeroing if another in-flght IO ends
- * at or before this one If zeronig is needed and we are currently
- * holding the iolock shared, we need to update it to exclusive which
- * involves dropping all locks and relocking to maintain correct locking
- * order. If we do this, restart the function to ensure all checks and
- * values are still valid.
+ * write. If zeroing is needed and we are currently holding the
+ * iolock shared, we need to update it to exclusive which involves
+ * dropping all locks and relocking to maintain correct locking order.
+ * If we do this, restart the function to ensure all checks and values
+ * are still valid.
*/
- if ((ip->i_new_size && *pos > ip->i_new_size) ||
- (!ip->i_new_size && *pos > i_size_read(inode))) {
+ if (*pos > i_size_read(inode)) {
if (*iolock == XFS_IOLOCK_SHARED) {
xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
*iolock = XFS_IOLOCK_EXCL;
@@ -714,19 +679,6 @@ restart:
}
error = -xfs_zero_eof(ip, *pos, i_size_read(inode));
}
-
- /*
- * If this IO extends beyond EOF, we may need to update ip->i_new_size.
- * We have already zeroed space beyond EOF (if necessary). Only update
- * ip->i_new_size if this IO ends beyond any other in-flight writes.
- */
- new_size = *pos + *count;
- if (new_size > i_size_read(inode)) {
- if (new_size > ip->i_new_size)
- ip->i_new_size = new_size;
- *new_sizep = new_size;
- }
-
xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
return error;
@@ -772,7 +724,6 @@ xfs_file_dio_aio_write(
unsigned long nr_segs,
loff_t pos,
size_t ocount,
- xfs_fsize_t *new_size,
int *iolock)
{
struct file *file = iocb->ki_filp;
@@ -817,7 +768,7 @@ xfs_file_dio_aio_write(
xfs_rw_ilock(ip, *iolock);
}
- ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock);
+ ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
if (ret)
return ret;
@@ -855,7 +806,6 @@ xfs_file_buffered_aio_write(
unsigned long nr_segs,
loff_t pos,
size_t ocount,
- xfs_fsize_t *new_size,
int *iolock)
{
struct file *file = iocb->ki_filp;
@@ -869,7 +819,7 @@ xfs_file_buffered_aio_write(
*iolock = XFS_IOLOCK_EXCL;
xfs_rw_ilock(ip, *iolock);
- ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock);
+ ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
if (ret)
return ret;
@@ -909,7 +859,6 @@ xfs_file_aio_write(
ssize_t ret;
int iolock;
size_t ocount = 0;
- xfs_fsize_t new_size = 0;
XFS_STATS_INC(xs_write_calls);
@@ -929,10 +878,10 @@ xfs_file_aio_write(
if (unlikely(file->f_flags & O_DIRECT))
ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos,
- ocount, &new_size, &iolock);
+ ocount, &iolock);
else
ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos,
- ocount, &new_size, &iolock);
+ ocount, &iolock);
if (ret <= 0)
goto out_unlock;
@@ -953,7 +902,6 @@ xfs_file_aio_write(
}
out_unlock:
- xfs_aio_write_newsize_update(ip, new_size);
xfs_rw_iunlock(ip, iolock);
return ret;
}
Index: xfs/fs/xfs/xfs_aops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_aops.c 2011-10-27 22:39:55.654173048 +0200
+++ xfs/fs/xfs/xfs_aops.c 2011-10-27 22:39:56.068672482 +0200
@@ -111,8 +111,7 @@ xfs_ioend_new_eof(
xfs_fsize_t bsize;
bsize = ioend->io_offset + ioend->io_size;
- isize = MAX(i_size_read(VFS_I(ip)), ip->i_new_size);
- isize = MIN(isize, bsize);
+ isize = MIN(i_size_read(VFS_I(ip)), bsize);
return isize > ip->i_d.di_size ? isize : 0;
}
@@ -126,11 +125,7 @@ static inline bool xfs_ioend_is_append(s
}
/*
- * Update on-disk file size now that data has been written to disk. The
- * current in-memory file size is i_size. If a write is beyond eof i_new_size
- * will be the intended file size until i_size is updated. If this write does
- * not extend all the way to the valid file size then restrict this update to
- * the end of the write.
+ * 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
@@ -1279,6 +1274,15 @@ xfs_end_io_direct_write(
struct xfs_ioend *ioend = iocb->private;
/*
+ * While the generic direct I/O code updates the inode size, it does
+ * so only after the end_io handler is called, which means our
+ * end_io handler things the on-disk size is outside the in-core
+ * size. To prevent this just update it a little bit earlier here.
+ */
+ if (offset + size > i_size_read(ioend->io_inode))
+ i_size_write(ioend->io_inode, offset + size);
+
+ /*
* blockdev_direct_IO can return an error even after the I/O
* completion handler was called. Thus we need to protect
* against double-freeing.
@@ -1340,12 +1344,10 @@ xfs_vm_write_failed(
if (to > inode->i_size) {
/*
- * punch out the delalloc blocks we have already allocated. We
- * don't call xfs_setattr() to do this as we may be in the
- * middle of a multi-iovec write and so the vfs inode->i_size
- * will not match the xfs ip->i_size and so it will zero too
- * much. Hence we jus truncate the page cache to zero what is
- * necessary and punch the delalloc blocks directly.
+ * Punch out the delalloc blocks we have already allocated.
+ *
+ * Don't bother with xfs_setattr given that nothing can have
+ * it do disk yet as the page is still locked at this point.
*/
struct xfs_inode *ip = XFS_I(inode);
xfs_fileoff_t start_fsb;
Index: xfs/fs/xfs/xfs_iget.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iget.c 2011-10-27 22:39:55.686173105 +0200
+++ xfs/fs/xfs/xfs_iget.c 2011-10-27 22:39:56.072672805 +0200
@@ -94,7 +94,6 @@ xfs_inode_alloc(
ip->i_update_core = 0;
ip->i_delayed_blks = 0;
memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
- ip->i_new_size = 0;
return ip;
}
Index: xfs/fs/xfs/xfs_trace.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trace.h 2011-10-27 22:39:55.670178173 +0200
+++ xfs/fs/xfs/xfs_trace.h 2011-10-27 22:39:56.076671196 +0200
@@ -897,7 +897,6 @@ DECLARE_EVENT_CLASS(xfs_file_class,
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(xfs_fsize_t, size)
- __field(xfs_fsize_t, new_size)
__field(loff_t, offset)
__field(size_t, count)
__field(int, flags)
@@ -906,17 +905,15 @@ DECLARE_EVENT_CLASS(xfs_file_class,
__entry->dev = VFS_I(ip)->i_sb->s_dev;
__entry->ino = ip->i_ino;
__entry->size = ip->i_d.di_size;
- __entry->new_size = ip->i_new_size;
__entry->offset = offset;
__entry->count = count;
__entry->flags = flags;
),
- TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx "
+ TP_printk("dev %d:%d ino 0x%llx size 0x%llx "
"offset 0x%llx count 0x%zx ioflags %s",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->size,
- __entry->new_size,
__entry->offset,
__entry->count,
__print_flags(__entry->flags, "|", XFS_IO_FLAGS))
@@ -984,7 +981,6 @@ DECLARE_EVENT_CLASS(xfs_imap_class,
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(loff_t, size)
- __field(loff_t, new_size)
__field(loff_t, offset)
__field(size_t, count)
__field(int, type)
@@ -996,7 +992,6 @@ DECLARE_EVENT_CLASS(xfs_imap_class,
__entry->dev = VFS_I(ip)->i_sb->s_dev;
__entry->ino = ip->i_ino;
__entry->size = ip->i_d.di_size;
- __entry->new_size = ip->i_new_size;
__entry->offset = offset;
__entry->count = count;
__entry->type = type;
@@ -1004,13 +999,11 @@ DECLARE_EVENT_CLASS(xfs_imap_class,
__entry->startblock = irec ? irec->br_startblock : 0;
__entry->blockcount = irec ? irec->br_blockcount : 0;
),
- TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx "
- "offset 0x%llx count %zd type %s "
- "startoff 0x%llx startblock %lld blockcount 0x%llx",
+ TP_printk("dev %d:%d ino 0x%llx size 0x%llx offset 0x%llx count %zd "
+ "type %s startoff 0x%llx startblock %lld blockcount 0x%llx",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->size,
- __entry->new_size,
__entry->offset,
__entry->count,
__print_symbolic(__entry->type, XFS_IO_TYPES),
@@ -1037,7 +1030,6 @@ DECLARE_EVENT_CLASS(xfs_simple_io_class,
__field(xfs_ino_t, ino)
__field(loff_t, isize)
__field(loff_t, disize)
- __field(loff_t, new_size)
__field(loff_t, offset)
__field(size_t, count)
),
@@ -1046,17 +1038,15 @@ DECLARE_EVENT_CLASS(xfs_simple_io_class,
__entry->ino = ip->i_ino;
__entry->isize = VFS_I(ip)->i_size;
__entry->disize = ip->i_d.di_size;
- __entry->new_size = ip->i_new_size;
__entry->offset = offset;
__entry->count = count;
),
- TP_printk("dev %d:%d ino 0x%llx isize 0x%llx disize 0x%llx new_size 0x%llx "
+ TP_printk("dev %d:%d ino 0x%llx isize 0x%llx disize 0x%llx "
"offset 0x%llx count %zd",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->isize,
__entry->disize,
- __entry->new_size,
__entry->offset,
__entry->count)
);
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:55.704670968 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:39:56.080672114 +0200
@@ -246,8 +246,6 @@ typedef struct xfs_inode {
xfs_icdinode_t i_d; /* most of ondisk inode */
- xfs_fsize_t i_new_size; /* size when write completes */
-
/* VFS inode */
struct inode i_vnode; /* embedded VFS inode */
} xfs_inode_t;
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 10/45] fix: force shutdown handling in xfs_end_io
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (8 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 09/45] xfs: remove the i_new_size " Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-11-05 8:11 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 11/45] xfs: use per-filesystem I/O completion workqueues Christoph Hellwig
` (31 subsequent siblings)
41 siblings, 1 reply; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-fix-end-io-error-handling --]
[-- Type: text/plain, Size: 723 bytes --]
Only ioend->io_error gets propagated back to e.g. AIO completions.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_aops.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: xfs/fs/xfs/xfs_aops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_aops.c 2011-10-27 22:39:56.068672482 +0200
+++ xfs/fs/xfs/xfs_aops.c 2011-10-27 22:39:56.902173367 +0200
@@ -184,7 +184,7 @@ xfs_end_io(
int error = 0;
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- error = -EIO;
+ ioend->io_error = -EIO;
goto done;
}
if (ioend->io_error)
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 11/45] xfs: use per-filesystem I/O completion workqueues
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (9 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 10/45] fix: force shutdown handling in xfs_end_io Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 12/45] xfs: do not require an ioend for new EOF calculation Christoph Hellwig
` (30 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-split-workqueues --]
[-- Type: text/plain, Size: 7447 bytes --]
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.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_aops.c | 39 ++++++++++-----------------------------
fs/xfs/xfs_aops.h | 2 --
fs/xfs/xfs_buf.c | 17 -----------------
fs/xfs/xfs_mount.h | 3 +++
fs/xfs/xfs_super.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 55 insertions(+), 49 deletions(-)
Index: xfs/fs/xfs/xfs_aops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_aops.c 2011-10-27 22:39:56.902173367 +0200
+++ xfs/fs/xfs/xfs_aops.c 2011-10-27 22:39:57.490177027 +0200
@@ -126,21 +126,15 @@ static inline bool xfs_ioend_is_append(s
/*
* 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_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;
- if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL))
- return EAGAIN;
-
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
isize = xfs_ioend_new_eof(ioend);
if (isize) {
trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
@@ -149,7 +143,6 @@ xfs_setfilesize(
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- return 0;
}
/*
@@ -163,10 +156,12 @@ xfs_finish_ioend(
struct xfs_ioend *ioend)
{
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)
- queue_work(xfsconvertd_workqueue, &ioend->io_work);
+ queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
else if (xfs_ioend_is_append(ioend))
- queue_work(xfsdatad_workqueue, &ioend->io_work);
+ queue_work(mp->m_data_workqueue, &ioend->io_work);
else
xfs_destroy_ioend(ioend);
}
@@ -207,23 +202,9 @@ xfs_end_io(
* We might have to update the on-disk file size after extending
* writes.
*/
- error = xfs_setfilesize(ioend);
- ASSERT(!error || error == EAGAIN);
-
+ xfs_setfilesize(ioend);
done:
- /*
- * 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);
- }
+ xfs_destroy_ioend(ioend);
}
/*
Index: xfs/fs/xfs/xfs_aops.h
===================================================================
--- xfs.orig/fs/xfs/xfs_aops.h 2011-10-27 22:39:35.702172559 +0200
+++ xfs/fs/xfs/xfs_aops.h 2011-10-27 22:39:57.490177027 +0200
@@ -18,8 +18,6 @@
#ifndef __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;
/*
Index: xfs/fs/xfs/xfs_buf.c
===================================================================
--- xfs.orig/fs/xfs/xfs_buf.c 2011-10-27 22:39:35.714171799 +0200
+++ xfs/fs/xfs/xfs_buf.c 2011-10-27 22:39:57.490177027 +0200
@@ -45,8 +45,6 @@ static kmem_zone_t *xfs_buf_zone;
STATIC int xfsbufd(void *);
static struct workqueue_struct *xfslogd_workqueue;
-struct workqueue_struct *xfsdatad_workqueue;
-struct workqueue_struct *xfsconvertd_workqueue;
#ifdef XFS_BUF_LOCK_TRACKING
# define XB_SET_OWNER(bp) ((bp)->b_last_holder = current->pid)
@@ -1797,21 +1795,8 @@ xfs_buf_init(void)
if (!xfslogd_workqueue)
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;
- out_destroy_xfsdatad_workqueue:
- destroy_workqueue(xfsdatad_workqueue);
- out_destroy_xfslogd_workqueue:
- destroy_workqueue(xfslogd_workqueue);
out_free_buf_zone:
kmem_zone_destroy(xfs_buf_zone);
out:
@@ -1821,8 +1806,6 @@ xfs_buf_init(void)
void
xfs_buf_terminate(void)
{
- destroy_workqueue(xfsconvertd_workqueue);
- destroy_workqueue(xfsdatad_workqueue);
destroy_workqueue(xfslogd_workqueue);
kmem_zone_destroy(xfs_buf_zone);
}
Index: xfs/fs/xfs/xfs_super.c
===================================================================
--- xfs.orig/fs/xfs/xfs_super.c 2011-10-27 22:39:53.702172231 +0200
+++ xfs/fs/xfs/xfs_super.c 2011-10-27 22:39:57.498171619 +0200
@@ -769,6 +769,40 @@ xfs_setup_devices(
return 0;
}
+STATIC int
+xfs_init_mount_workqueues(
+ struct xfs_mount *mp)
+{
+#define XFS_WQ_NAME_LEN 512
+ char name[XFS_WQ_NAME_LEN];
+
+ snprintf(name, XFS_WQ_NAME_LEN, "xfs-data/%s", mp->m_fsname);
+ mp->m_data_workqueue = alloc_workqueue(name, WQ_MEM_RECLAIM, 1);
+ if (!mp->m_data_workqueue)
+ goto out;
+
+ snprintf(name, XFS_WQ_NAME_LEN, "xfs-conv/%s", mp->m_fsname);
+ mp->m_unwritten_workqueue = alloc_workqueue(name, WQ_MEM_RECLAIM, 1);
+ 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;
+#undef XFS_WQ_NAME_LEN
+}
+
+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 */
STATIC struct inode *
xfs_fs_alloc_inode(
@@ -1012,6 +1046,7 @@ xfs_fs_put_super(
xfs_unmountfs(mp);
xfs_freesb(mp);
xfs_icsb_destroy_counters(mp);
+ xfs_destroy_mount_workqueues(mp);
xfs_close_devices(mp);
xfs_free_fsname(mp);
kfree(mp);
@@ -1345,10 +1380,14 @@ xfs_fs_fill_super(
if (error)
goto out_free_fsname;
- error = xfs_icsb_init_counters(mp);
+ error = xfs_init_mount_workqueues(mp);
if (error)
goto out_close_devices;
+ error = xfs_icsb_init_counters(mp);
+ if (error)
+ goto out_destroy_workqueues;
+
error = xfs_readsb(mp, flags);
if (error)
goto out_destroy_counters;
@@ -1411,6 +1450,8 @@ xfs_fs_fill_super(
xfs_freesb(mp);
out_destroy_counters:
xfs_icsb_destroy_counters(mp);
+out_destroy_workqueues:
+ xfs_destroy_mount_workqueues(mp);
out_close_devices:
xfs_close_devices(mp);
out_free_fsname:
Index: xfs/fs/xfs/xfs_mount.h
===================================================================
--- xfs.orig/fs/xfs/xfs_mount.h 2011-10-27 22:39:35.738171837 +0200
+++ xfs/fs/xfs/xfs_mount.h 2011-10-27 22:39:57.502188861 +0200
@@ -211,6 +211,9 @@ typedef struct xfs_mount {
struct shrinker m_inode_shrink; /* inode reclaim shrinker */
int64_t m_low_space[XFS_LOWSP_MAX];
/* low free space thresholds */
+
+ struct workqueue_struct *m_data_workqueue;
+ struct workqueue_struct *m_unwritten_workqueue;
} xfs_mount_t;
/*
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 12/45] xfs: do not require an ioend for new EOF calculation
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (10 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 11/45] xfs: use per-filesystem I/O completion workqueues Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 16/45] xfs: untange SYNC_WAIT and SYNC_TRYLOCK meanings for xfs_qm_dqflush Christoph Hellwig
` (29 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-simplify-eof-calculation --]
[-- Type: text/plain, Size: 3075 bytes --]
Replace xfs_ioend_new_eof with a new inline xfs_new_eof helper that
doesn't require and ioend, and is available also outside of xfs_aops.c.
Also make the code a bit more clear by using a normal if statement
instead of a slightly misleading MIN().
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_aops.c | 24 ++++--------------------
fs/xfs/xfs_inode.h | 14 ++++++++++++++
2 files changed, 18 insertions(+), 20 deletions(-)
Index: xfs/fs/xfs/xfs_aops.c
===================================================================
--- xfs.orig/fs/xfs/xfs_aops.c 2011-10-27 22:39:57.490177027 +0200
+++ xfs/fs/xfs/xfs_aops.c 2011-10-27 22:39:58.142174495 +0200
@@ -99,23 +99,6 @@ xfs_destroy_ioend(
}
/*
- * If the end of the current ioend is beyond the current EOF,
- * return the new EOF value, otherwise zero.
- */
-STATIC xfs_fsize_t
-xfs_ioend_new_eof(
- xfs_ioend_t *ioend)
-{
- xfs_inode_t *ip = XFS_I(ioend->io_inode);
- xfs_fsize_t isize;
- xfs_fsize_t bsize;
-
- bsize = ioend->io_offset + ioend->io_size;
- isize = MIN(i_size_read(VFS_I(ip)), bsize);
- return isize > ip->i_d.di_size ? isize : 0;
-}
-
-/*
* Fast and loose check if this write could update the on-disk inode size.
*/
static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
@@ -135,7 +118,7 @@ xfs_setfilesize(
xfs_fsize_t isize;
xfs_ilock(ip, XFS_ILOCK_EXCL);
- isize = xfs_ioend_new_eof(ioend);
+ isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
if (isize) {
trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
ip->i_d.di_size = isize;
@@ -357,6 +340,7 @@ xfs_submit_ioend_bio(
xfs_ioend_t *ioend,
struct bio *bio)
{
+ struct xfs_inode *ip = XFS_I(ioend->io_inode);
atomic_inc(&ioend->io_remaining);
bio->bi_private = ioend;
bio->bi_end_io = xfs_end_bio;
@@ -365,8 +349,8 @@ xfs_submit_ioend_bio(
* If the I/O is beyond EOF we mark the inode dirty immediately
* but don't update the inode size until I/O completion.
*/
- if (xfs_ioend_new_eof(ioend))
- xfs_mark_inode_dirty(XFS_I(ioend->io_inode));
+ if (xfs_new_eof(ip, ioend->io_offset + ioend->io_size))
+ xfs_mark_inode_dirty(ip);
submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, bio);
}
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:56.080672114 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:39:58.142174495 +0200
@@ -275,6 +275,20 @@ static inline xfs_fsize_t XFS_ISIZE(stru
}
/*
+ * If this I/O goes past the on-disk inode size update it unless it would
+ * be past the current in-core inode size.
+ */
+static inline xfs_fsize_t
+xfs_new_eof(struct xfs_inode *ip, xfs_fsize_t new_size)
+{
+ xfs_fsize_t i_size = i_size_read(VFS_I(ip));
+
+ if (new_size > i_size)
+ new_size = i_size;
+ return new_size > ip->i_d.di_size ? new_size : 0;
+}
+
+/*
* i_flags helper functions
*/
static inline void
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 16/45] xfs: untange SYNC_WAIT and SYNC_TRYLOCK meanings for xfs_qm_dqflush
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (11 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 12/45] xfs: do not require an ioend for new EOF calculation Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 17/45] xfs: make sure to really flush all dquots in xfs_qm_quotacheck Christoph Hellwig
` (28 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-dquota-cleanup-SYNC_-flags --]
[-- Type: text/plain, Size: 2044 bytes --]
Only skip pinned dquots if SYNC_TRYLOCK is specified, and adjust the callers
to keep the behaviour unchanged.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 2 +-
fs/xfs/xfs_dquot_item.c | 2 +-
fs/xfs/xfs_qm.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:39:34.952673735 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:00.076675206 +0200
@@ -1169,7 +1169,7 @@ xfs_qm_dqflush(
* If not dirty, or it's pinned and we are not supposed to block, nada.
*/
if (!XFS_DQ_IS_DIRTY(dqp) ||
- (!(flags & SYNC_WAIT) && atomic_read(&dqp->q_pincount) > 0)) {
+ ((flags & SYNC_TRYLOCK) && atomic_read(&dqp->q_pincount) > 0)) {
xfs_dqfunlock(dqp);
return 0;
}
Index: xfs/fs/xfs/xfs_dquot_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot_item.c 2011-10-27 22:39:42.528674212 +0200
+++ xfs/fs/xfs/xfs_dquot_item.c 2011-10-27 22:40:00.080676002 +0200
@@ -134,7 +134,7 @@ xfs_qm_dquot_logitem_push(
* lock without sleeping, then there must not have been
* anyone in the process of flushing the dquot.
*/
- error = xfs_qm_dqflush(dqp, 0);
+ error = xfs_qm_dqflush(dqp, SYNC_TRYLOCK);
if (error)
xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p",
__func__, error, dqp);
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:39:34.980673855 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:00.080676002 +0200
@@ -1660,7 +1660,7 @@ xfs_qm_quotacheck(
* successfully.
*/
if (!error)
- error = xfs_qm_dqflush_all(mp, 0);
+ error = xfs_qm_dqflush_all(mp, SYNC_TRYLOCK);
/*
* We can get this error if we couldn't do a dquot allocation inside
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 17/45] xfs: make sure to really flush all dquots in xfs_qm_quotacheck
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (12 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 16/45] xfs: untange SYNC_WAIT and SYNC_TRYLOCK meanings for xfs_qm_dqflush Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 18/45] xfs: remove xfs_qm_sync Christoph Hellwig
` (27 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quotacheck-dont-trylock --]
[-- Type: text/plain, Size: 939 bytes --]
Make sure we do not skip any dquots when flushing them out after a
quotacheck to make sure that we will never have any dirty dquots on a life
filesystem. At this point no dquot should be pinnable, but lets be anal
about it.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_qm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:00.080676002 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:00.653671530 +0200
@@ -1660,7 +1660,7 @@ xfs_qm_quotacheck(
* successfully.
*/
if (!error)
- error = xfs_qm_dqflush_all(mp, SYNC_TRYLOCK);
+ error = xfs_qm_dqflush_all(mp, 0);
/*
* We can get this error if we couldn't do a dquot allocation inside
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 18/45] xfs: remove xfs_qm_sync
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (13 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 17/45] xfs: make sure to really flush all dquots in xfs_qm_quotacheck Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 19/45] xfs: remove the sync_mode argument to xfs_qm_dqflush_all Christoph Hellwig
` (26 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-remove-xfs_qm_sync --]
[-- Type: text/plain, Size: 6539 bytes --]
Now that we can't have any dirty dquots around that aren't in the AIL we
can get rid of the explicit dquot syncing from xfssyncd and xfs_fs_sync_fs.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_qm.c | 94 -----------------------------------------------------
fs/xfs/xfs_qm.h | 6 ---
fs/xfs/xfs_quota.h | 5 --
fs/xfs/xfs_super.c | 11 +-----
fs/xfs/xfs_sync.c | 6 ---
5 files changed, 3 insertions(+), 119 deletions(-)
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:00.653671530 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:01.234172361 +0200
@@ -878,100 +878,6 @@ xfs_qm_dqdetach(
}
}
-int
-xfs_qm_sync(
- struct xfs_mount *mp,
- int flags)
-{
- struct xfs_quotainfo *q = mp->m_quotainfo;
- int recl, restarts;
- struct xfs_dquot *dqp;
- int error;
-
- if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
- return 0;
-
- restarts = 0;
-
- again:
- mutex_lock(&q->qi_dqlist_lock);
- /*
- * dqpurge_all() also takes the mplist lock and iterate thru all dquots
- * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared
- * when we have the mplist lock, we know that dquots will be consistent
- * as long as we have it locked.
- */
- if (!XFS_IS_QUOTA_ON(mp)) {
- mutex_unlock(&q->qi_dqlist_lock);
- return 0;
- }
- ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
- list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
- /*
- * If this is vfs_sync calling, then skip the dquots that
- * don't 'seem' to be dirty. ie. don't acquire dqlock.
- * This is very similar to what xfs_sync does with inodes.
- */
- if (flags & SYNC_TRYLOCK) {
- if (!XFS_DQ_IS_DIRTY(dqp))
- continue;
- if (!xfs_qm_dqlock_nowait(dqp))
- continue;
- } else {
- xfs_dqlock(dqp);
- }
-
- /*
- * Now, find out for sure if this dquot is dirty or not.
- */
- if (! XFS_DQ_IS_DIRTY(dqp)) {
- xfs_dqunlock(dqp);
- continue;
- }
-
- /* XXX a sentinel would be better */
- recl = q->qi_dqreclaims;
- if (!xfs_dqflock_nowait(dqp)) {
- if (flags & SYNC_TRYLOCK) {
- xfs_dqunlock(dqp);
- continue;
- }
- /*
- * If we can't grab the flush lock then if the caller
- * really wanted us to give this our best shot, so
- * see if we can give a push to the buffer before we wait
- * on the flush lock. At this point, we know that
- * even though the dquot is being flushed,
- * it has (new) dirty data.
- */
- xfs_qm_dqflock_pushbuf_wait(dqp);
- }
- /*
- * Let go of the mplist lock. We don't want to hold it
- * across a disk write
- */
- mutex_unlock(&q->qi_dqlist_lock);
- error = xfs_qm_dqflush(dqp, flags);
- xfs_dqunlock(dqp);
- if (error && XFS_FORCED_SHUTDOWN(mp))
- return 0; /* Need to prevent umount failure */
- else if (error)
- return error;
-
- mutex_lock(&q->qi_dqlist_lock);
- if (recl != q->qi_dqreclaims) {
- if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS)
- break;
-
- mutex_unlock(&q->qi_dqlist_lock);
- goto again;
- }
- }
-
- mutex_unlock(&q->qi_dqlist_lock);
- return 0;
-}
-
/*
* The hash chains and the mplist use the same xfs_dqhash structure as
* their list head, but we can take the mplist qh_lock and one of the
Index: xfs/fs/xfs/xfs_qm.h
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.h 2011-10-27 22:39:34.744674251 +0200
+++ xfs/fs/xfs/xfs_qm.h 2011-10-27 22:40:01.234172361 +0200
@@ -33,12 +33,6 @@ extern kmem_zone_t *qm_dqzone;
extern kmem_zone_t *qm_dqtrxzone;
/*
- * Used in xfs_qm_sync called by xfs_sync to count the max times that it can
- * iterate over the mountpt's dquot list in one call.
- */
-#define XFS_QM_SYNC_MAX_RESTARTS 7
-
-/*
* Ditto, for xfs_qm_dqreclaim_one.
*/
#define XFS_QM_RECLAIM_MAX_RESTARTS 4
Index: xfs/fs/xfs/xfs_quota.h
===================================================================
--- xfs.orig/fs/xfs/xfs_quota.h 2011-10-27 22:39:34.756674997 +0200
+++ xfs/fs/xfs/xfs_quota.h 2011-10-27 22:40:01.238188776 +0200
@@ -326,7 +326,6 @@ extern int xfs_qm_dqattach_locked(struct
extern void xfs_qm_dqdetach(struct xfs_inode *);
extern void xfs_qm_dqrele(struct xfs_dquot *);
extern void xfs_qm_statvfs(struct xfs_inode *, struct kstatfs *);
-extern int xfs_qm_sync(struct xfs_mount *, int);
extern int xfs_qm_newmount(struct xfs_mount *, uint *, uint *);
extern void xfs_qm_mount_quotas(struct xfs_mount *);
extern void xfs_qm_unmount(struct xfs_mount *);
@@ -366,10 +365,6 @@ static inline int xfs_trans_reserve_quot
#define xfs_qm_dqdetach(ip)
#define xfs_qm_dqrele(d)
#define xfs_qm_statvfs(ip, s)
-static inline int xfs_qm_sync(struct xfs_mount *mp, int flags)
-{
- return 0;
-}
#define xfs_qm_newmount(mp, a, b) (0)
#define xfs_qm_mount_quotas(mp)
#define xfs_qm_unmount(mp)
Index: xfs/fs/xfs/xfs_super.c
===================================================================
--- xfs.orig/fs/xfs/xfs_super.c 2011-10-27 22:39:59.661174646 +0200
+++ xfs/fs/xfs/xfs_super.c 2011-10-27 22:40:01.238188776 +0200
@@ -1001,17 +1001,10 @@ xfs_fs_sync_fs(
int error;
/*
- * Not much we can do for the first async pass. Writing out the
- * superblock would be counter-productive as we are going to redirty
- * when writing out other data and metadata (and writing out a single
- * block is quite fast anyway).
- *
- * Try to asynchronously kick off quota syncing at least.
+ * Doing anything during the async pass would be counterproductive.
*/
- if (!wait) {
- xfs_qm_sync(mp, SYNC_TRYLOCK);
+ if (!wait)
return 0;
- }
error = xfs_quiesce_data(mp);
if (error)
Index: xfs/fs/xfs/xfs_sync.c
===================================================================
--- xfs.orig/fs/xfs/xfs_sync.c 2011-10-27 22:39:53.016673088 +0200
+++ xfs/fs/xfs/xfs_sync.c 2011-10-27 22:40:01.246171848 +0200
@@ -359,10 +359,7 @@ xfs_quiesce_data(
{
int error, error2 = 0;
- xfs_qm_sync(mp, SYNC_TRYLOCK);
- xfs_qm_sync(mp, SYNC_WAIT);
-
- /* force out the newly dirtied log buffers */
+ /* force out the log */
xfs_log_force(mp, XFS_LOG_SYNC);
/* write superblock and hoover up shutdown errors */
@@ -470,7 +467,6 @@ xfs_sync_worker(
error = xfs_fs_log_dummy(mp);
else
xfs_log_force(mp, 0);
- error = xfs_qm_sync(mp, SYNC_TRYLOCK);
/* start pushing all the metadata that is currently dirty */
xfs_ail_push_all(mp->m_ail);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 19/45] xfs: remove the sync_mode argument to xfs_qm_dqflush_all
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (14 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 18/45] xfs: remove xfs_qm_sync Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 20/45] xfs: cleanup dquot locking helpers Christoph Hellwig
` (25 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-remove-xfs_qm_dqflush_all-sync-mode --]
[-- Type: text/plain, Size: 1215 bytes --]
It always is zero, and removing it will make future changes easier.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_qm.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:01.234172361 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:01.742172177 +0200
@@ -415,8 +415,7 @@ xfs_qm_unmount_quotas(
*/
STATIC int
xfs_qm_dqflush_all(
- struct xfs_mount *mp,
- int sync_mode)
+ struct xfs_mount *mp)
{
struct xfs_quotainfo *q = mp->m_quotainfo;
int recl;
@@ -451,7 +450,7 @@ again:
* across a disk write.
*/
mutex_unlock(&q->qi_dqlist_lock);
- error = xfs_qm_dqflush(dqp, sync_mode);
+ error = xfs_qm_dqflush(dqp, 0);
xfs_dqunlock(dqp);
if (error)
return error;
@@ -1566,7 +1565,7 @@ xfs_qm_quotacheck(
* successfully.
*/
if (!error)
- error = xfs_qm_dqflush_all(mp, 0);
+ error = xfs_qm_dqflush_all(mp);
/*
* We can get this error if we couldn't do a dquot allocation inside
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 20/45] xfs: cleanup dquot locking helpers
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (15 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 19/45] xfs: remove the sync_mode argument to xfs_qm_dqflush_all Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 21/45] xfs: cleanup xfs_qm_dqlookup Christoph Hellwig
` (24 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-clenaup-locking-helpers --]
[-- Type: text/plain, Size: 4708 bytes --]
Mark the trivial lock wrappers as inline, and make the naming consistent
for all of them.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 31 ++++---------------------------
fs/xfs/xfs_dquot.h | 25 +++++++++++++++++++------
fs/xfs/xfs_dquot_item.c | 2 +-
fs/xfs/xfs_qm.c | 2 +-
4 files changed, 25 insertions(+), 35 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:00.076675206 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:02.250173174 +0200
@@ -1257,40 +1257,17 @@ xfs_qm_dqflush(
}
-int
-xfs_qm_dqlock_nowait(
- xfs_dquot_t *dqp)
-{
- return mutex_trylock(&dqp->q_qlock);
-}
-
-void
-xfs_dqlock(
- xfs_dquot_t *dqp)
-{
- mutex_lock(&dqp->q_qlock);
-}
-
void
xfs_dqunlock(
xfs_dquot_t *dqp)
{
- mutex_unlock(&(dqp->q_qlock));
+ xfs_dqunlock_nonotify(dqp);
if (dqp->q_logitem.qli_dquot == dqp) {
- /* Once was dqp->q_mount, but might just have been cleared */
xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_ailp,
- (xfs_log_item_t*)&(dqp->q_logitem));
+ &dqp->q_logitem.qli_item);
}
}
-
-void
-xfs_dqunlock_nonotify(
- xfs_dquot_t *dqp)
-{
- mutex_unlock(&(dqp->q_qlock));
-}
-
/*
* Lock two xfs_dquot structures.
*
@@ -1370,7 +1347,7 @@ xfs_qm_dqpurge(
* Block on the flush lock after nudging dquot buffer,
* if it is incore.
*/
- xfs_qm_dqflock_pushbuf_wait(dqp);
+ xfs_dqflock_pushbuf_wait(dqp);
}
/*
@@ -1427,7 +1404,7 @@ xfs_qm_dqpurge(
* wait on the flush lock.
*/
void
-xfs_qm_dqflock_pushbuf_wait(
+xfs_dqflock_pushbuf_wait(
xfs_dquot_t *dqp)
{
xfs_mount_t *mp = dqp->q_mount;
Index: xfs/fs/xfs/xfs_dquot.h
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.h 2011-10-27 22:39:34.512674054 +0200
+++ xfs/fs/xfs/xfs_dquot.h 2011-10-27 22:40:02.250173174 +0200
@@ -102,6 +102,21 @@ static inline void xfs_dqfunlock(xfs_dqu
complete(&dqp->q_flush);
}
+static inline int xfs_dqlock_nowait(struct xfs_dquot *dqp)
+{
+ return mutex_trylock(&dqp->q_qlock);
+}
+
+static inline void xfs_dqlock(struct xfs_dquot *dqp)
+{
+ mutex_lock(&dqp->q_qlock);
+}
+
+static inline void xfs_dqunlock_nonotify(struct xfs_dquot *dqp)
+{
+ mutex_unlock(&dqp->q_qlock);
+}
+
#define XFS_DQ_IS_LOCKED(dqp) (mutex_is_locked(&((dqp)->q_qlock)))
#define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY)
#define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER)
@@ -120,8 +135,6 @@ extern void xfs_qm_dqdestroy(xfs_dquot_
extern int xfs_qm_dqflush(xfs_dquot_t *, uint);
extern int xfs_qm_dqpurge(xfs_dquot_t *);
extern void xfs_qm_dqunpin_wait(xfs_dquot_t *);
-extern int xfs_qm_dqlock_nowait(xfs_dquot_t *);
-extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp);
extern void xfs_qm_adjust_dqtimers(xfs_mount_t *,
xfs_disk_dquot_t *);
extern void xfs_qm_adjust_dqlimits(xfs_mount_t *,
@@ -129,9 +142,9 @@ extern void xfs_qm_adjust_dqlimits(xfs_
extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
xfs_dqid_t, uint, uint, xfs_dquot_t **);
extern void xfs_qm_dqput(xfs_dquot_t *);
-extern void xfs_dqlock(xfs_dquot_t *);
-extern void xfs_dqlock2(xfs_dquot_t *, xfs_dquot_t *);
-extern void xfs_dqunlock(xfs_dquot_t *);
-extern void xfs_dqunlock_nonotify(xfs_dquot_t *);
+
+extern void xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
+extern void xfs_dqunlock(struct xfs_dquot *);
+extern void xfs_dqflock_pushbuf_wait(struct xfs_dquot *dqp);
#endif /* __XFS_DQUOT_H__ */
Index: xfs/fs/xfs/xfs_dquot_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot_item.c 2011-10-27 22:40:00.080676002 +0200
+++ xfs/fs/xfs/xfs_dquot_item.c 2011-10-27 22:40:02.254174248 +0200
@@ -237,7 +237,7 @@ xfs_qm_dquot_logitem_trylock(
if (atomic_read(&dqp->q_pincount) > 0)
return XFS_ITEM_PINNED;
- if (!xfs_qm_dqlock_nowait(dqp))
+ if (!xfs_dqlock_nowait(dqp))
return XFS_ITEM_LOCKED;
if (!xfs_dqflock_nowait(dqp)) {
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:01.742172177 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:02.254174248 +0200
@@ -443,7 +443,7 @@ again:
* out immediately. We'll be able to acquire
* the flush lock when the I/O completes.
*/
- xfs_qm_dqflock_pushbuf_wait(dqp);
+ xfs_dqflock_pushbuf_wait(dqp);
}
/*
* Let go of the mplist lock. We don't want to hold it
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 21/45] xfs: cleanup xfs_qm_dqlookup
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (16 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 20/45] xfs: cleanup dquot locking helpers Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 22/45] xfs: remove XFS_DQ_INACTIVE Christoph Hellwig
` (23 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-cleanup-xfs_qm_dqlookup --]
[-- Type: text/plain, Size: 1829 bytes --]
Rearrange the code to avoid the conditional locking around the
flist_locked variable. This means we lose a (rather pointless)
assert, and hold the freelist lock a bit longer for one corner
case.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 25 +++++--------------------
1 file changed, 5 insertions(+), 20 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:02.250173174 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:02.770171231 +0200
@@ -710,12 +710,9 @@ xfs_qm_dqlookup(
xfs_dquot_t **O_dqpp)
{
xfs_dquot_t *dqp;
- uint flist_locked;
ASSERT(mutex_is_locked(&qh->qh_lock));
- flist_locked = B_FALSE;
-
/*
* Traverse the hashchain looking for a match
*/
@@ -750,31 +747,19 @@ xfs_qm_dqlookup(
xfs_dqlock(dqp);
dqp->dq_flags &= ~(XFS_DQ_WANT);
}
- flist_locked = B_TRUE;
- }
-
- /*
- * id couldn't have changed; we had the hashlock all
- * along
- */
- ASSERT(be32_to_cpu(dqp->q_core.d_id) == id);
- if (flist_locked) {
- if (dqp->q_nrefs != 0) {
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- flist_locked = B_FALSE;
- } else {
+ if (dqp->q_nrefs == 0) {
/* take it off the freelist */
trace_xfs_dqlookup_freelist(dqp);
list_del_init(&dqp->q_freelist);
xfs_Gqm->qm_dqfrlist_cnt--;
}
+ XFS_DQHOLD(dqp);
+ mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+ } else {
+ XFS_DQHOLD(dqp);
}
- XFS_DQHOLD(dqp);
-
- if (flist_locked)
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
/*
* move the dquot to the front of the hashchain
*/
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 22/45] xfs: remove XFS_DQ_INACTIVE
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (17 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 21/45] xfs: cleanup xfs_qm_dqlookup Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 23/45] xfs: implement lazy removal for the dquot freelist Christoph Hellwig
` (22 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-kill-XFS_DQ_INACTIVE --]
[-- Type: text/plain, Size: 5711 bytes --]
Free dquots when purging them during umount instead of keeping them around
on the freelist in a degraded state. The out of order locking in
xfs_qm_dqpurge will be removed again later in this series.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 25 +++++++++++++--------
fs/xfs/xfs_qm.c | 61 +++++------------------------------------------------
fs/xfs/xfs_quota.h | 4 ---
3 files changed, 23 insertions(+), 67 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:02.770171231 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:03.314171810 +0200
@@ -1302,6 +1302,14 @@ xfs_qm_dqpurge(
ASSERT(mutex_is_locked(&mp->m_quotainfo->qi_dqlist_lock));
ASSERT(mutex_is_locked(&dqp->q_hash->qh_lock));
+ /*
+ * XXX(hch): horrible locking order, will get cleaned up ASAP.
+ */
+ if (!mutex_trylock(&xfs_Gqm->qm_dqfrlist_lock)) {
+ mutex_unlock(&dqp->q_hash->qh_lock);
+ return 1;
+ }
+
xfs_dqlock(dqp);
/*
* We really can't afford to purge a dquot that is
@@ -1364,22 +1372,21 @@ xfs_qm_dqpurge(
list_del_init(&dqp->q_hashlist);
qh->qh_version++;
+
list_del_init(&dqp->q_mplist);
mp->m_quotainfo->qi_dqreclaims++;
mp->m_quotainfo->qi_dquots--;
- /*
- * XXX Move this to the front of the freelist, if we can get the
- * freelist lock.
- */
- ASSERT(!list_empty(&dqp->q_freelist));
- dqp->q_mount = NULL;
- dqp->q_hash = NULL;
- dqp->dq_flags = XFS_DQ_INACTIVE;
- memset(&dqp->q_core, 0, sizeof(dqp->q_core));
+ list_del_init(&dqp->q_freelist);
+ xfs_Gqm->qm_dqfrlist_cnt--;
+
xfs_dqfunlock(dqp);
xfs_dqunlock(dqp);
+
+ mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
mutex_unlock(&qh->qh_lock);
+
+ xfs_qm_dqdestroy(dqp);
return (0);
}
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:02.254174248 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:03.314171810 +0200
@@ -154,12 +154,17 @@ STATIC void
xfs_qm_destroy(
struct xfs_qm *xqm)
{
- struct xfs_dquot *dqp, *n;
int hsize, i;
ASSERT(xqm != NULL);
ASSERT(xqm->qm_nrefs == 0);
+
unregister_shrinker(&xfs_qm_shaker);
+
+ mutex_lock(&xqm->qm_dqfrlist_lock);
+ ASSERT(list_empty(&xqm->qm_dqfrlist));
+ mutex_unlock(&xqm->qm_dqfrlist_lock);
+
hsize = xqm->qm_dqhashmask + 1;
for (i = 0; i < hsize; i++) {
xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
@@ -171,17 +176,6 @@ xfs_qm_destroy(
xqm->qm_grp_dqhtable = NULL;
xqm->qm_dqhashmask = 0;
- /* frlist cleanup */
- mutex_lock(&xqm->qm_dqfrlist_lock);
- list_for_each_entry_safe(dqp, n, &xqm->qm_dqfrlist, q_freelist) {
- xfs_dqlock(dqp);
- list_del_init(&dqp->q_freelist);
- xfs_Gqm->qm_dqfrlist_cnt--;
- xfs_dqunlock(dqp);
- xfs_qm_dqdestroy(dqp);
- }
- mutex_unlock(&xqm->qm_dqfrlist_lock);
- mutex_destroy(&xqm->qm_dqfrlist_lock);
kmem_free(xqm);
}
@@ -232,34 +226,10 @@ STATIC void
xfs_qm_rele_quotafs_ref(
struct xfs_mount *mp)
{
- xfs_dquot_t *dqp, *n;
-
ASSERT(xfs_Gqm);
ASSERT(xfs_Gqm->qm_nrefs > 0);
/*
- * Go thru the freelist and destroy all inactive dquots.
- */
- mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-
- list_for_each_entry_safe(dqp, n, &xfs_Gqm->qm_dqfrlist, q_freelist) {
- xfs_dqlock(dqp);
- if (dqp->dq_flags & XFS_DQ_INACTIVE) {
- ASSERT(dqp->q_mount == NULL);
- ASSERT(! XFS_DQ_IS_DIRTY(dqp));
- ASSERT(list_empty(&dqp->q_hashlist));
- ASSERT(list_empty(&dqp->q_mplist));
- list_del_init(&dqp->q_freelist);
- xfs_Gqm->qm_dqfrlist_cnt--;
- xfs_dqunlock(dqp);
- xfs_qm_dqdestroy(dqp);
- } else {
- xfs_dqunlock(dqp);
- }
- }
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
-
- /*
* Destroy the entire XQM. If somebody mounts with quotaon, this'll
* be restarted.
*/
@@ -1727,8 +1697,6 @@ again:
* both the dquot and the freelistlock.
*/
if (dqp->dq_flags & XFS_DQ_WANT) {
- ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
-
trace_xfs_dqreclaim_want(dqp);
XQM_STATS_INC(xqmstats.xs_qm_dqwants);
restarts++;
@@ -1736,23 +1704,6 @@ again:
goto dqunlock;
}
- /*
- * If the dquot is inactive, we are assured that it is
- * not on the mplist or the hashlist, and that makes our
- * life easier.
- */
- if (dqp->dq_flags & XFS_DQ_INACTIVE) {
- ASSERT(mp == NULL);
- ASSERT(! XFS_DQ_IS_DIRTY(dqp));
- ASSERT(list_empty(&dqp->q_hashlist));
- ASSERT(list_empty(&dqp->q_mplist));
- list_del_init(&dqp->q_freelist);
- xfs_Gqm->qm_dqfrlist_cnt--;
- dqpout = dqp;
- XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
- goto dqunlock;
- }
-
ASSERT(dqp->q_hash);
ASSERT(!list_empty(&dqp->q_mplist));
Index: xfs/fs/xfs/xfs_quota.h
===================================================================
--- xfs.orig/fs/xfs/xfs_quota.h 2011-10-27 22:40:01.238188776 +0200
+++ xfs/fs/xfs/xfs_quota.h 2011-10-27 22:40:03.322220265 +0200
@@ -88,7 +88,6 @@ typedef struct xfs_dqblk {
#define XFS_DQ_GROUP 0x0004 /* a group quota */
#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
#define XFS_DQ_WANT 0x0010 /* for lookup/reclaim race */
-#define XFS_DQ_INACTIVE 0x0020 /* dq off mplist & hashlist */
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
@@ -97,8 +96,7 @@ typedef struct xfs_dqblk {
{ XFS_DQ_PROJ, "PROJ" }, \
{ XFS_DQ_GROUP, "GROUP" }, \
{ XFS_DQ_DIRTY, "DIRTY" }, \
- { XFS_DQ_WANT, "WANT" }, \
- { XFS_DQ_INACTIVE, "INACTIVE" }
+ { XFS_DQ_WANT, "WANT" }
/*
* In the worst case, when both user and group quotas are on,
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 23/45] xfs: implement lazy removal for the dquot freelist
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (18 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 22/45] xfs: remove XFS_DQ_INACTIVE Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 24/45] xfs: flatten the dquot lock ordering Christoph Hellwig
` (21 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-lazy-lru --]
[-- Type: text/plain, Size: 6130 bytes --]
Do not remove dquots from the freelist when we grab a reference to them in
xfs_qm_dqlookup, but leave them on the freelist util scanning notices that
they have a reference. This speeds up the lookup fastpath, and greatly
simplifies the lock ordering constraints. Note that the same scheme is
used by the VFS inode and dentry caches.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 65 +++++++++++++----------------------------------------
fs/xfs/xfs_qm.c | 22 ++++++++---------
fs/xfs/xfs_quota.h | 4 ---
fs/xfs/xfs_trace.h | 2 -
4 files changed, 29 insertions(+), 64 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:03.314171810 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:03.870173003 +0200
@@ -722,58 +722,25 @@ xfs_qm_dqlookup(
* dqlock to look at the id field of the dquot, since the
* id can't be modified without the hashlock anyway.
*/
- if (be32_to_cpu(dqp->q_core.d_id) == id && dqp->q_mount == mp) {
- trace_xfs_dqlookup_found(dqp);
+ if (be32_to_cpu(dqp->q_core.d_id) != id || dqp->q_mount != mp)
+ continue;
- /*
- * All in core dquots must be on the dqlist of mp
- */
- ASSERT(!list_empty(&dqp->q_mplist));
+ trace_xfs_dqlookup_found(dqp);
- xfs_dqlock(dqp);
- if (dqp->q_nrefs == 0) {
- ASSERT(!list_empty(&dqp->q_freelist));
- if (!mutex_trylock(&xfs_Gqm->qm_dqfrlist_lock)) {
- trace_xfs_dqlookup_want(dqp);
-
- /*
- * We may have raced with dqreclaim_one()
- * (and lost). So, flag that we don't
- * want the dquot to be reclaimed.
- */
- dqp->dq_flags |= XFS_DQ_WANT;
- xfs_dqunlock(dqp);
- mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
- xfs_dqlock(dqp);
- dqp->dq_flags &= ~(XFS_DQ_WANT);
- }
-
- if (dqp->q_nrefs == 0) {
- /* take it off the freelist */
- trace_xfs_dqlookup_freelist(dqp);
- list_del_init(&dqp->q_freelist);
- xfs_Gqm->qm_dqfrlist_cnt--;
- }
- XFS_DQHOLD(dqp);
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- } else {
- XFS_DQHOLD(dqp);
- }
+ xfs_dqlock(dqp);
+ XFS_DQHOLD(dqp);
- /*
- * move the dquot to the front of the hashchain
- */
- ASSERT(mutex_is_locked(&qh->qh_lock));
- list_move(&dqp->q_hashlist, &qh->qh_list);
- trace_xfs_dqlookup_done(dqp);
- *O_dqpp = dqp;
- return 0;
- }
+ /*
+ * move the dquot to the front of the hashchain
+ */
+ list_move(&dqp->q_hashlist, &qh->qh_list);
+ trace_xfs_dqlookup_done(dqp);
+ *O_dqpp = dqp;
+ return 0;
}
*O_dqpp = NULL;
- ASSERT(mutex_is_locked(&qh->qh_lock));
- return (1);
+ return 1;
}
/*
@@ -1033,8 +1000,10 @@ xfs_qm_dqput(
if (--dqp->q_nrefs == 0) {
trace_xfs_dqput_free(dqp);
- list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
- xfs_Gqm->qm_dqfrlist_cnt++;
+ if (list_empty(&dqp->q_freelist)) {
+ list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
+ xfs_Gqm->qm_dqfrlist_cnt++;
+ }
/*
* If we just added a udquot to the freelist, then
Index: xfs/fs/xfs/xfs_trace.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trace.h 2011-10-27 22:39:59.657022417 +0200
+++ xfs/fs/xfs/xfs_trace.h 2011-10-27 22:40:03.870173003 +0200
@@ -743,8 +743,6 @@ DEFINE_DQUOT_EVENT(xfs_dqtobp_read);
DEFINE_DQUOT_EVENT(xfs_dqread);
DEFINE_DQUOT_EVENT(xfs_dqread_fail);
DEFINE_DQUOT_EVENT(xfs_dqlookup_found);
-DEFINE_DQUOT_EVENT(xfs_dqlookup_want);
-DEFINE_DQUOT_EVENT(xfs_dqlookup_freelist);
DEFINE_DQUOT_EVENT(xfs_dqlookup_done);
DEFINE_DQUOT_EVENT(xfs_dqget_hit);
DEFINE_DQUOT_EVENT(xfs_dqget_miss);
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:03.314171810 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:03.874199381 +0200
@@ -517,13 +517,12 @@ xfs_qm_dqpurge_int(
* get them off mplist and hashlist, but leave them on freelist.
*/
list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
- /*
- * It's OK to look at the type without taking dqlock here.
- * We're holding the mplist lock here, and that's needed for
- * a dqreclaim.
- */
- if ((dqp->dq_flags & dqtype) == 0)
+ xfs_dqlock(dqp);
+ if ((dqp->dq_flags & dqtype) == 0) {
+ xfs_dqunlock(dqp);
continue;
+ }
+ xfs_dqunlock(dqp);
if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
nrecl = q->qi_dqreclaims;
@@ -1691,14 +1690,15 @@ again:
xfs_dqlock(dqp);
/*
- * We are racing with dqlookup here. Naturally we don't
- * want to reclaim a dquot that lookup wants. We release the
- * freelist lock and start over, so that lookup will grab
- * both the dquot and the freelistlock.
+ * This dquot has already been grabbed by dqlookup.
+ * Remove it from the freelist and try again.
*/
- if (dqp->dq_flags & XFS_DQ_WANT) {
+ if (dqp->q_nrefs) {
trace_xfs_dqreclaim_want(dqp);
XQM_STATS_INC(xqmstats.xs_qm_dqwants);
+
+ list_del_init(&dqp->q_freelist);
+ xfs_Gqm->qm_dqfrlist_cnt--;
restarts++;
startagain = 1;
goto dqunlock;
Index: xfs/fs/xfs/xfs_quota.h
===================================================================
--- xfs.orig/fs/xfs/xfs_quota.h 2011-10-27 22:40:03.322220265 +0200
+++ xfs/fs/xfs/xfs_quota.h 2011-10-27 22:40:03.878172958 +0200
@@ -87,7 +87,6 @@ typedef struct xfs_dqblk {
#define XFS_DQ_PROJ 0x0002 /* project quota */
#define XFS_DQ_GROUP 0x0004 /* a group quota */
#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
-#define XFS_DQ_WANT 0x0010 /* for lookup/reclaim race */
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
@@ -95,8 +94,7 @@ typedef struct xfs_dqblk {
{ XFS_DQ_USER, "USER" }, \
{ XFS_DQ_PROJ, "PROJ" }, \
{ XFS_DQ_GROUP, "GROUP" }, \
- { XFS_DQ_DIRTY, "DIRTY" }, \
- { XFS_DQ_WANT, "WANT" }
+ { XFS_DQ_DIRTY, "DIRTY" }
/*
* In the worst case, when both user and group quotas are on,
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 24/45] xfs: flatten the dquot lock ordering
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (19 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 23/45] xfs: implement lazy removal for the dquot freelist Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 25/45] xfs: nest the qm_dqfrlist_lock insise the dquot qlock Christoph Hellwig
` (20 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-add-DQ_FREEING --]
[-- Type: text/plain, Size: 13738 bytes --]
Introduce a new XFS_DQ_FREEING flag that tells lookup and mplist walks
to skip a dquot that is beeing freed, and use this avoid the trylock
on the hash and mplist locks in xfs_qm_dqreclaim_one. Also simplify
xfs_dqpurge by moving the inodes to a dispose list after marking them
XFS_DQ_FREEING and avoid the locker ordering constraints.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 110 ++++++++++++++++++---------------------------
fs/xfs/xfs_dquot.h | 2
fs/xfs/xfs_qm.c | 129 ++++++++++++++++++-----------------------------------
fs/xfs/xfs_quota.h | 4 +
4 files changed, 96 insertions(+), 149 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:03.870173003 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:04.372672510 +0200
@@ -728,6 +728,12 @@ xfs_qm_dqlookup(
trace_xfs_dqlookup_found(dqp);
xfs_dqlock(dqp);
+ if (dqp->dq_flags & XFS_DQ_FREEING) {
+ *O_dqpp = NULL;
+ xfs_dqunlock(dqp);
+ return -1;
+ }
+
XFS_DQHOLD(dqp);
/*
@@ -781,11 +787,7 @@ xfs_qm_dqget(
return (EIO);
}
}
-#endif
- again:
-
-#ifdef DEBUG
ASSERT(type == XFS_DQ_USER ||
type == XFS_DQ_PROJ ||
type == XFS_DQ_GROUP);
@@ -797,13 +799,21 @@ xfs_qm_dqget(
ASSERT(ip->i_gdquot == NULL);
}
#endif
+
+restart:
mutex_lock(&h->qh_lock);
/*
* Look in the cache (hashtable).
* The chain is kept locked during lookup.
*/
- if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) {
+ switch (xfs_qm_dqlookup(mp, id, h, O_dqpp)) {
+ case -1:
+ XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
+ mutex_unlock(&h->qh_lock);
+ delay(1);
+ goto restart;
+ case 0:
XQM_STATS_INC(xqmstats.xs_qm_dqcachehits);
/*
* The dquot was found, moved to the front of the chain,
@@ -814,9 +824,11 @@ xfs_qm_dqget(
ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
mutex_unlock(&h->qh_lock);
trace_xfs_dqget_hit(*O_dqpp);
- return (0); /* success */
+ return 0; /* success */
+ default:
+ XQM_STATS_INC(xqmstats.xs_qm_dqcachemisses);
+ break;
}
- XQM_STATS_INC(xqmstats.xs_qm_dqcachemisses);
/*
* Dquot cache miss. We don't want to keep the inode lock across
@@ -913,16 +925,21 @@ xfs_qm_dqget(
* lock order between the two dquots here since dqp isn't
* on any findable lists yet.
*/
- if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) {
+ switch (xfs_qm_dqlookup(mp, id, h, &tmpdqp)) {
+ case 0:
+ case -1:
/*
- * Duplicate found. Just throw away the new dquot
- * and start over.
+ * Duplicate found, either in cache or on its way out.
+ * Just throw away the new dquot and start over.
*/
- xfs_qm_dqput(tmpdqp);
+ if (tmpdqp)
+ xfs_qm_dqput(tmpdqp);
mutex_unlock(&h->qh_lock);
xfs_qm_dqdestroy(dqp);
XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
- goto again;
+ goto restart;
+ default:
+ break;
}
}
@@ -1250,51 +1267,18 @@ xfs_dqlock2(
}
}
-
/*
- * Take a dquot out of the mount's dqlist as well as the hashlist.
- * This is called via unmount as well as quotaoff, and the purge
- * will always succeed unless there are soft (temp) references
- * outstanding.
- *
- * This returns 0 if it was purged, 1 if it wasn't. It's not an error code
- * that we're returning! XXXsup - not cool.
+ * Take a dquot out of the mount's dqlist as well as the hashlist. This is
+ * called via unmount as well as quotaoff, and the purge will always succeed.
*/
-/* ARGSUSED */
-int
+void
xfs_qm_dqpurge(
- xfs_dquot_t *dqp)
+ struct xfs_dquot *dqp)
{
- xfs_dqhash_t *qh = dqp->q_hash;
- xfs_mount_t *mp = dqp->q_mount;
-
- ASSERT(mutex_is_locked(&mp->m_quotainfo->qi_dqlist_lock));
- ASSERT(mutex_is_locked(&dqp->q_hash->qh_lock));
-
- /*
- * XXX(hch): horrible locking order, will get cleaned up ASAP.
- */
- if (!mutex_trylock(&xfs_Gqm->qm_dqfrlist_lock)) {
- mutex_unlock(&dqp->q_hash->qh_lock);
- return 1;
- }
+ struct xfs_mount *mp = dqp->q_mount;
+ struct xfs_dqhash *qh = dqp->q_hash;
xfs_dqlock(dqp);
- /*
- * We really can't afford to purge a dquot that is
- * referenced, because these are hard refs.
- * It shouldn't happen in general because we went thru _all_ inodes in
- * dqrele_all_inodes before calling this and didn't let the mountlock go.
- * However it is possible that we have dquots with temporary
- * references that are not attached to an inode. e.g. see xfs_setattr().
- */
- if (dqp->q_nrefs != 0) {
- xfs_dqunlock(dqp);
- mutex_unlock(&dqp->q_hash->qh_lock);
- return (1);
- }
-
- ASSERT(!list_empty(&dqp->q_freelist));
/*
* If we're turning off quotas, we have to make sure that, for
@@ -1313,19 +1297,14 @@ xfs_qm_dqpurge(
}
/*
- * XXXIf we're turning this type of quotas off, we don't care
+ * If we are turning this type of quotas off, we don't care
* about the dirty metadata sitting in this dquot. OTOH, if
* we're unmounting, we do care, so we flush it and wait.
*/
if (XFS_DQ_IS_DIRTY(dqp)) {
int error;
- /* dqflush unlocks dqflock */
/*
- * Given that dqpurge is a very rare occurrence, it is OK
- * that we're holding the hashlist and mplist locks
- * across the disk write. But, ... XXXsup
- *
* We don't care about getting disk errors here. We need
* to purge this dquot anyway, so we go ahead regardless.
*/
@@ -1335,31 +1314,34 @@ xfs_qm_dqpurge(
__func__, dqp);
xfs_dqflock(dqp);
}
+
ASSERT(atomic_read(&dqp->q_pincount) == 0);
ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
!(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
+ xfs_dqfunlock(dqp);
+ xfs_dqunlock(dqp);
+
+ mutex_lock(&qh->qh_lock);
list_del_init(&dqp->q_hashlist);
qh->qh_version++;
+ mutex_unlock(&qh->qh_lock);
+ mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
list_del_init(&dqp->q_mplist);
mp->m_quotainfo->qi_dqreclaims++;
mp->m_quotainfo->qi_dquots--;
+ mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
+ mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
+ ASSERT(!list_empty(&dqp->q_freelist));
list_del_init(&dqp->q_freelist);
xfs_Gqm->qm_dqfrlist_cnt--;
-
- xfs_dqfunlock(dqp);
- xfs_dqunlock(dqp);
-
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- mutex_unlock(&qh->qh_lock);
xfs_qm_dqdestroy(dqp);
- return (0);
}
-
/*
* Give the buffer a little push if it is incore and
* wait on the flush lock.
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:03.874199381 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:04.372672510 +0200
@@ -398,7 +398,8 @@ again:
mutex_lock(&q->qi_dqlist_lock);
list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
xfs_dqlock(dqp);
- if (! XFS_DQ_IS_DIRTY(dqp)) {
+ if ((dqp->dq_flags & XFS_DQ_FREEING) ||
+ !XFS_DQ_IS_DIRTY(dqp)) {
xfs_dqunlock(dqp);
continue;
}
@@ -437,6 +438,7 @@ again:
/* return ! busy */
return 0;
}
+
/*
* Release the group dquot pointers the user dquots may be
* carrying around as a hint. mplist is locked on entry and exit.
@@ -453,6 +455,13 @@ xfs_qm_detach_gdquots(
ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
xfs_dqlock(dqp);
+ if (dqp->dq_flags & XFS_DQ_FREEING) {
+ xfs_dqunlock(dqp);
+ mutex_unlock(&q->qi_dqlist_lock);
+ delay(1);
+ mutex_lock(&q->qi_dqlist_lock);
+ goto again;
+ }
if ((gdqp = dqp->q_gdquot)) {
xfs_dqlock(gdqp);
dqp->q_gdquot = NULL;
@@ -489,8 +498,8 @@ xfs_qm_dqpurge_int(
struct xfs_quotainfo *q = mp->m_quotainfo;
struct xfs_dquot *dqp, *n;
uint dqtype;
- int nrecl;
- int nmisses;
+ int nmisses = 0;
+ LIST_HEAD (dispose_list);
if (!q)
return 0;
@@ -509,46 +518,27 @@ xfs_qm_dqpurge_int(
*/
xfs_qm_detach_gdquots(mp);
- again:
- nmisses = 0;
- ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
/*
* Try to get rid of all of the unwanted dquots. The idea is to
* get them off mplist and hashlist, but leave them on freelist.
*/
list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
xfs_dqlock(dqp);
- if ((dqp->dq_flags & dqtype) == 0) {
- xfs_dqunlock(dqp);
- continue;
+ if ((dqp->dq_flags & dqtype) != 0 &&
+ !(dqp->dq_flags & XFS_DQ_FREEING)) {
+ if (dqp->q_nrefs == 0) {
+ dqp->dq_flags |= XFS_DQ_FREEING;
+ list_move_tail(&dqp->q_mplist, &dispose_list);
+ } else
+ nmisses++;
}
xfs_dqunlock(dqp);
-
- if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
- nrecl = q->qi_dqreclaims;
- mutex_unlock(&q->qi_dqlist_lock);
- mutex_lock(&dqp->q_hash->qh_lock);
- mutex_lock(&q->qi_dqlist_lock);
-
- /*
- * XXXTheoretically, we can get into a very long
- * ping pong game here.
- * No one can be adding dquots to the mplist at
- * this point, but somebody might be taking things off.
- */
- if (nrecl != q->qi_dqreclaims) {
- mutex_unlock(&dqp->q_hash->qh_lock);
- goto again;
- }
- }
-
- /*
- * Take the dquot off the mplist and hashlist. It may remain on
- * freelist in INACTIVE state.
- */
- nmisses += xfs_qm_dqpurge(dqp);
}
mutex_unlock(&q->qi_dqlist_lock);
+
+ list_for_each_entry_safe(dqp, n, &dispose_list, q_mplist)
+ xfs_qm_dqpurge(dqp);
+
return nmisses;
}
@@ -1666,25 +1656,16 @@ xfs_qm_init_quotainos(
/*
- * Just pop the least recently used dquot off the freelist and
- * recycle it. The returned dquot is locked.
+ * Pop the least recently used dquot off the freelist and recycle it.
*/
-STATIC xfs_dquot_t *
+STATIC struct xfs_dquot *
xfs_qm_dqreclaim_one(void)
{
- xfs_dquot_t *dqpout;
- xfs_dquot_t *dqp;
- int restarts;
- int startagain;
-
- restarts = 0;
- dqpout = NULL;
+ struct xfs_dquot *dqp;
+ int restarts = 0;
- /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
-again:
- startagain = 0;
mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-
+restart:
list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) {
struct xfs_mount *mp = dqp->q_mount;
xfs_dqlock(dqp);
@@ -1700,7 +1681,6 @@ again:
list_del_init(&dqp->q_freelist);
xfs_Gqm->qm_dqfrlist_cnt--;
restarts++;
- startagain = 1;
goto dqunlock;
}
@@ -1736,57 +1716,40 @@ again:
}
goto dqunlock;
}
+ xfs_dqfunlock(dqp);
/*
- * We're trying to get the hashlock out of order. This races
- * with dqlookup; so, we giveup and goto the next dquot if
- * we couldn't get the hashlock. This way, we won't starve
- * a dqlookup process that holds the hashlock that is
- * waiting for the freelist lock.
+ * Prevent lookups now that we are past the point of no return.
*/
- if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
- restarts++;
- goto dqfunlock;
- }
+ dqp->dq_flags |= XFS_DQ_FREEING;
+ xfs_dqunlock(dqp);
- /*
- * This races with dquot allocation code as well as dqflush_all
- * and reclaim code. So, if we failed to grab the mplist lock,
- * giveup everything and start over.
- */
- if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) {
- restarts++;
- startagain = 1;
- goto qhunlock;
- }
+ mutex_lock(&dqp->q_hash->qh_lock);
+ list_del_init(&dqp->q_hashlist);
+ dqp->q_hash->qh_version++;
+ mutex_unlock(&dqp->q_hash->qh_lock);
- ASSERT(dqp->q_nrefs == 0);
+ mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
list_del_init(&dqp->q_mplist);
mp->m_quotainfo->qi_dquots--;
mp->m_quotainfo->qi_dqreclaims++;
- list_del_init(&dqp->q_hashlist);
- dqp->q_hash->qh_version++;
+ mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
+
+ ASSERT(dqp->q_nrefs == 0);
list_del_init(&dqp->q_freelist);
xfs_Gqm->qm_dqfrlist_cnt--;
- dqpout = dqp;
- mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
-qhunlock:
- mutex_unlock(&dqp->q_hash->qh_lock);
-dqfunlock:
- xfs_dqfunlock(dqp);
+
+ mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+ return dqp;
dqunlock:
xfs_dqunlock(dqp);
- if (dqpout)
- break;
if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
break;
- if (startagain) {
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- goto again;
- }
+ goto restart;
}
+
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- return dqpout;
+ return NULL;
}
/*
Index: xfs/fs/xfs/xfs_quota.h
===================================================================
--- xfs.orig/fs/xfs/xfs_quota.h 2011-10-27 22:40:03.878172958 +0200
+++ xfs/fs/xfs/xfs_quota.h 2011-10-27 22:40:04.376671215 +0200
@@ -87,6 +87,7 @@ typedef struct xfs_dqblk {
#define XFS_DQ_PROJ 0x0002 /* project quota */
#define XFS_DQ_GROUP 0x0004 /* a group quota */
#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
+#define XFS_DQ_FREEING 0x0010 /* dquot is beeing torn down */
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
@@ -94,7 +95,8 @@ typedef struct xfs_dqblk {
{ XFS_DQ_USER, "USER" }, \
{ XFS_DQ_PROJ, "PROJ" }, \
{ XFS_DQ_GROUP, "GROUP" }, \
- { XFS_DQ_DIRTY, "DIRTY" }
+ { XFS_DQ_DIRTY, "DIRTY" }, \
+ { XFS_DQ_FREEING, "FREEING" }
/*
* In the worst case, when both user and group quotas are on,
Index: xfs/fs/xfs/xfs_dquot.h
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.h 2011-10-27 22:40:02.250173174 +0200
+++ xfs/fs/xfs/xfs_dquot.h 2011-10-27 22:40:04.376671215 +0200
@@ -133,7 +133,7 @@ static inline void xfs_dqunlock_nonotify
extern void xfs_qm_dqdestroy(xfs_dquot_t *);
extern int xfs_qm_dqflush(xfs_dquot_t *, uint);
-extern int xfs_qm_dqpurge(xfs_dquot_t *);
+extern void xfs_qm_dqpurge(xfs_dquot_t *);
extern void xfs_qm_dqunpin_wait(xfs_dquot_t *);
extern void xfs_qm_adjust_dqtimers(xfs_mount_t *,
xfs_disk_dquot_t *);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 25/45] xfs: nest the qm_dqfrlist_lock insise the dquot qlock
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (20 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 24/45] xfs: flatten the dquot lock ordering Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 26/45] xfs: simplify xfs_qm_dqattach_grouphint Christoph Hellwig
` (19 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-change-quota-freelist-lock-ordering --]
[-- Type: text/plain, Size: 4375 bytes --]
Make sure the xfs_qm_dqput fast path works without trylock loops by nesting
the freelist lock inside the dquot qlock, and do the trylock in dquot reclaim
and purge instead. Document our new lock ordering now that it has settled.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 98 +++++++++++++++++++++--------------------------------
fs/xfs/xfs_qm.c | 4 +-
2 files changed, 42 insertions(+), 60 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:04.372672510 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:04.892672352 +0200
@@ -39,20 +39,20 @@
#include "xfs_qm.h"
#include "xfs_trace.h"
-
/*
- LOCK ORDER
+ * Lock ordering:
+ *
+ * ip->i_lock
+ * qh->qh_lock
+ * qi->qi_dqlist_lock
+ * dquot->q_qlock
+ * dquot->q_flush
+ * xfs_Gqm->qm_dqfrlist_lock
+ *
+ * If two dquots need to be locked the order is user before group/project,
+ * otherwise by the lowest id first, see xfs_dqlock2.
+ */
- inode lock (ilock)
- dquot hash-chain lock (hashlock)
- xqm dquot freelist lock (freelistlock
- mount's dquot list lock (mplistlock)
- user dquot lock - lock ordering among dquots is based on the uid or gid
- group dquot lock - similar to udquots. Between the two dquots, the udquot
- has to be locked first.
- pin lock - the dquot lock must be held to take this lock.
- flush lock - ditto.
-*/
#ifdef DEBUG
xfs_buftarg_t *xfs_dqerror_target;
@@ -984,69 +984,49 @@ restart:
*/
void
xfs_qm_dqput(
- xfs_dquot_t *dqp)
+ struct xfs_dquot *dqp)
{
- xfs_dquot_t *gdqp;
+ struct xfs_dquot *gdqp;
ASSERT(dqp->q_nrefs > 0);
ASSERT(XFS_DQ_IS_LOCKED(dqp));
trace_xfs_dqput(dqp);
- if (dqp->q_nrefs != 1) {
- dqp->q_nrefs--;
+recurse:
+ if (--dqp->q_nrefs > 0) {
xfs_dqunlock(dqp);
return;
}
- /*
- * drop the dqlock and acquire the freelist and dqlock
- * in the right order; but try to get it out-of-order first
- */
- if (!mutex_trylock(&xfs_Gqm->qm_dqfrlist_lock)) {
- trace_xfs_dqput_wait(dqp);
- xfs_dqunlock(dqp);
- mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
- xfs_dqlock(dqp);
- }
-
- while (1) {
- gdqp = NULL;
+ trace_xfs_dqput_free(dqp);
- /* We can't depend on nrefs being == 1 here */
- if (--dqp->q_nrefs == 0) {
- trace_xfs_dqput_free(dqp);
-
- if (list_empty(&dqp->q_freelist)) {
- list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
- xfs_Gqm->qm_dqfrlist_cnt++;
- }
+ mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
+ if (list_empty(&dqp->q_freelist)) {
+ list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
+ xfs_Gqm->qm_dqfrlist_cnt++;
+ }
+ mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- /*
- * If we just added a udquot to the freelist, then
- * we want to release the gdquot reference that
- * it (probably) has. Otherwise it'll keep the
- * gdquot from getting reclaimed.
- */
- if ((gdqp = dqp->q_gdquot)) {
- /*
- * Avoid a recursive dqput call
- */
- xfs_dqlock(gdqp);
- dqp->q_gdquot = NULL;
- }
- }
- xfs_dqunlock(dqp);
+ /*
+ * If we just added a udquot to the freelist, then we want to release
+ * the gdquot reference that it (probably) has. Otherwise it'll keep
+ * the gdquot from getting reclaimed.
+ */
+ gdqp = dqp->q_gdquot;
+ if (gdqp) {
+ xfs_dqlock(gdqp);
+ dqp->q_gdquot = NULL;
+ }
+ xfs_dqunlock(dqp);
- /*
- * If we had a group quota inside the user quota as a hint,
- * release it now.
- */
- if (! gdqp)
- break;
+ /*
+ * If we had a group quota hint, release it now.
+ */
+ if (gdqp) {
dqp = gdqp;
+ goto recurse;
}
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
}
/*
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:04.372672510 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:04.892672352 +0200
@@ -1668,7 +1668,9 @@ xfs_qm_dqreclaim_one(void)
restart:
list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) {
struct xfs_mount *mp = dqp->q_mount;
- xfs_dqlock(dqp);
+
+ if (!xfs_dqlock_nowait(dqp))
+ continue;
/*
* This dquot has already been grabbed by dqlookup.
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 26/45] xfs: simplify xfs_qm_dqattach_grouphint
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (21 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 25/45] xfs: nest the qm_dqfrlist_lock insise the dquot qlock Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 27/45] xfs: add a xfs_dqhold helper Christoph Hellwig
` (18 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-cleanup-xfs_qm_dqattach_grouphint --]
[-- Type: text/plain, Size: 3128 bytes --]
No need to play games with the qlock now that the freelist lock nestst
inside it. Also clean up lots of outdated comments.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_qm.c | 64 ++++++++++++++------------------------------------------
1 file changed, 16 insertions(+), 48 deletions(-)
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:04.892672352 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:05.388673160 +0200
@@ -650,11 +650,7 @@ xfs_qm_dqattach_one(
/*
* Given a udquot and gdquot, attach a ptr to the group dquot in the
- * udquot as a hint for future lookups. The idea sounds simple, but the
- * execution isn't, because the udquot might have a group dquot attached
- * already and getting rid of that gets us into lock ordering constraints.
- * The process is complicated more by the fact that the dquots may or may not
- * be locked on entry.
+ * udquot as a hint for future lookups.
*/
STATIC void
xfs_qm_dqattach_grouphint(
@@ -665,45 +661,21 @@ xfs_qm_dqattach_grouphint(
xfs_dqlock(udq);
- if ((tmp = udq->q_gdquot)) {
- if (tmp == gdq) {
- xfs_dqunlock(udq);
- return;
- }
+ tmp = udq->q_gdquot;
+ if (tmp) {
+ if (tmp == gdq)
+ goto done;
udq->q_gdquot = NULL;
- /*
- * We can't keep any dqlocks when calling dqrele,
- * because the freelist lock comes before dqlocks.
- */
- xfs_dqunlock(udq);
- /*
- * we took a hard reference once upon a time in dqget,
- * so give it back when the udquot no longer points at it
- * dqput() does the unlocking of the dquot.
- */
xfs_qm_dqrele(tmp);
-
- xfs_dqlock(udq);
- xfs_dqlock(gdq);
-
- } else {
- ASSERT(XFS_DQ_IS_LOCKED(udq));
- xfs_dqlock(gdq);
- }
-
- ASSERT(XFS_DQ_IS_LOCKED(udq));
- ASSERT(XFS_DQ_IS_LOCKED(gdq));
- /*
- * Somebody could have attached a gdquot here,
- * when we dropped the uqlock. If so, just do nothing.
- */
- if (udq->q_gdquot == NULL) {
- XFS_DQHOLD(gdq);
- udq->q_gdquot = gdq;
}
+ xfs_dqlock(gdq);
+ XFS_DQHOLD(gdq);
xfs_dqunlock(gdq);
+
+ udq->q_gdquot = gdq;
+done:
xfs_dqunlock(udq);
}
@@ -770,17 +742,13 @@ xfs_qm_dqattach_locked(
ASSERT(ip->i_gdquot);
/*
- * We may or may not have the i_udquot locked at this point,
- * but this check is OK since we don't depend on the i_gdquot to
- * be accurate 100% all the time. It is just a hint, and this
- * will succeed in general.
- */
- if (ip->i_udquot->q_gdquot == ip->i_gdquot)
- goto done;
- /*
- * Attach i_gdquot to the gdquot hint inside the i_udquot.
+ * We do not have i_udquot locked at this point, but this check
+ * is OK since we don't depend on the i_gdquot to be accurate
+ * 100% all the time. It is just a hint, and this will
+ * succeed in general.
*/
- xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
+ if (ip->i_udquot->q_gdquot != ip->i_gdquot)
+ xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
}
done:
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 27/45] xfs: add a xfs_dqhold helper
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (22 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 26/45] xfs: simplify xfs_qm_dqattach_grouphint Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 28/45] xfs: kill xfs_qm_dqinit_core Christoph Hellwig
` (17 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-add-xfs_dqhold --]
[-- Type: text/plain, Size: 4752 bytes --]
Factor the common:
xfs_dqlock(dqp);
XFS_DQHOLD(dqp);
xfs_dqunlock(dqp);
pattern into a new helper, and remove XFS_DQHOLD now that only two callers
are left.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 2 +-
fs/xfs/xfs_dquot.h | 10 ++++++++--
fs/xfs/xfs_qm.c | 50 +++++++++++++-------------------------------------
3 files changed, 22 insertions(+), 40 deletions(-)
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:05.388673160 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:05.868674047 +0200
@@ -606,12 +606,9 @@ xfs_qm_dqattach_one(
*/
dqp = udqhint->q_gdquot;
if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) {
- xfs_dqlock(dqp);
- XFS_DQHOLD(dqp);
ASSERT(*IO_idqpp == NULL);
- *IO_idqpp = dqp;
- xfs_dqunlock(dqp);
+ *IO_idqpp = xfs_qm_dqhold(dqp);
xfs_dqunlock(udqhint);
return 0;
}
@@ -670,11 +667,7 @@ xfs_qm_dqattach_grouphint(
xfs_qm_dqrele(tmp);
}
- xfs_dqlock(gdq);
- XFS_DQHOLD(gdq);
- xfs_dqunlock(gdq);
-
- udq->q_gdquot = gdq;
+ udq->q_gdquot = xfs_qm_dqhold(gdq);
done:
xfs_dqunlock(udq);
}
@@ -1939,10 +1932,7 @@ xfs_qm_vop_dqalloc(
* this to caller
*/
ASSERT(ip->i_udquot);
- uq = ip->i_udquot;
- xfs_dqlock(uq);
- XFS_DQHOLD(uq);
- xfs_dqunlock(uq);
+ uq = xfs_qm_dqhold(ip->i_udquot);
}
}
if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) {
@@ -1963,10 +1953,7 @@ xfs_qm_vop_dqalloc(
xfs_ilock(ip, lockflags);
} else {
ASSERT(ip->i_gdquot);
- gq = ip->i_gdquot;
- xfs_dqlock(gq);
- XFS_DQHOLD(gq);
- xfs_dqunlock(gq);
+ gq = xfs_qm_dqhold(ip->i_gdquot);
}
} else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
if (xfs_get_projid(ip) != prid) {
@@ -1986,10 +1973,7 @@ xfs_qm_vop_dqalloc(
xfs_ilock(ip, lockflags);
} else {
ASSERT(ip->i_gdquot);
- gq = ip->i_gdquot;
- xfs_dqlock(gq);
- XFS_DQHOLD(gq);
- xfs_dqunlock(gq);
+ gq = xfs_qm_dqhold(ip->i_gdquot);
}
}
if (uq)
@@ -2039,14 +2023,10 @@ xfs_qm_vop_chown(
xfs_trans_mod_dquot(tp, newdq, XFS_TRANS_DQ_ICOUNT, 1);
/*
- * Take an extra reference, because the inode
- * is going to keep this dquot pointer even
- * after the trans_commit.
- */
- xfs_dqlock(newdq);
- XFS_DQHOLD(newdq);
- xfs_dqunlock(newdq);
- *IO_olddq = newdq;
+ * Take an extra reference, because the inode is going to keep
+ * this dquot pointer even after the trans_commit.
+ */
+ *IO_olddq = xfs_qm_dqhold(newdq);
return prevdq;
}
@@ -2178,25 +2158,21 @@ xfs_qm_vop_create_dqattach(
ASSERT(XFS_IS_QUOTA_RUNNING(mp));
if (udqp) {
- xfs_dqlock(udqp);
- XFS_DQHOLD(udqp);
- xfs_dqunlock(udqp);
ASSERT(ip->i_udquot == NULL);
- ip->i_udquot = udqp;
ASSERT(XFS_IS_UQUOTA_ON(mp));
ASSERT(ip->i_d.di_uid == be32_to_cpu(udqp->q_core.d_id));
+
+ ip->i_udquot = xfs_qm_dqhold(udqp);
xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
}
if (gdqp) {
- xfs_dqlock(gdqp);
- XFS_DQHOLD(gdqp);
- xfs_dqunlock(gdqp);
ASSERT(ip->i_gdquot == NULL);
- ip->i_gdquot = gdqp;
ASSERT(XFS_IS_OQUOTA_ON(mp));
ASSERT((XFS_IS_GQUOTA_ON(mp) ?
ip->i_d.di_gid : xfs_get_projid(ip)) ==
be32_to_cpu(gdqp->q_core.d_id));
+
+ ip->i_gdquot = xfs_qm_dqhold(gdqp);
xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
}
}
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:04.892672352 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:05.872671537 +0200
@@ -734,7 +734,7 @@ xfs_qm_dqlookup(
return -1;
}
- XFS_DQHOLD(dqp);
+ dqp->q_nrefs++;
/*
* move the dquot to the front of the hashchain
Index: xfs/fs/xfs/xfs_dquot.h
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.h 2011-10-27 22:40:04.376671215 +0200
+++ xfs/fs/xfs/xfs_dquot.h 2011-10-27 22:40:05.876670670 +0200
@@ -80,8 +80,6 @@ enum {
XFS_QLOCK_NESTED,
};
-#define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++)
-
/*
* Manage the q_flush completion queue embedded in the dquot. This completion
* queue synchronizes processes attempting to flush the in-core dquot back to
@@ -147,4 +145,12 @@ extern void xfs_dqlock2(struct xfs_dquo
extern void xfs_dqunlock(struct xfs_dquot *);
extern void xfs_dqflock_pushbuf_wait(struct xfs_dquot *dqp);
+static inline struct xfs_dquot *xfs_qm_dqhold(struct xfs_dquot *dqp)
+{
+ xfs_dqlock(dqp);
+ dqp->q_nrefs++;
+ xfs_dqunlock(dqp);
+ return dqp;
+}
+
#endif /* __XFS_DQUOT_H__ */
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 28/45] xfs: kill xfs_qm_dqinit_core
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (23 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 27/45] xfs: add a xfs_dqhold helper Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 29/45] xfs: kill xfs_qm_idtodq Christoph Hellwig
` (16 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-kill-xfs_qm_dqinit_core --]
[-- Type: text/plain, Size: 1808 bytes --]
Merge into it's only caller, which also obsoletes the comments.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 27 +++++++--------------------
1 file changed, 7 insertions(+), 20 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:05.872671537 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:06.408674693 +0200
@@ -155,24 +155,6 @@ xfs_qm_dqdestroy(
}
/*
- * This is what a 'fresh' dquot inside a dquot chunk looks like on disk.
- */
-STATIC void
-xfs_qm_dqinit_core(
- xfs_dqid_t id,
- uint type,
- xfs_dqblk_t *d)
-{
- /*
- * Caller has zero'd the entire dquot 'chunk' already.
- */
- d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);
- d->dd_diskdq.d_version = XFS_DQUOT_VERSION;
- d->dd_diskdq.d_id = cpu_to_be32(id);
- d->dd_diskdq.d_flags = type;
-}
-
-/*
* If default limits are in force, push them into the dquot now.
* We overwrite the dquot limits only if they are zero and this
* is not the root dquot.
@@ -328,8 +310,13 @@ xfs_qm_init_dquot_blk(
curid = id - (id % q->qi_dqperchunk);
ASSERT(curid >= 0);
memset(d, 0, BBTOB(q->qi_dqchunklen));
- for (i = 0; i < q->qi_dqperchunk; i++, d++, curid++)
- xfs_qm_dqinit_core(curid, type, d);
+ for (i = 0; i < q->qi_dqperchunk; i++, d++, curid++) {
+ d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);
+ d->dd_diskdq.d_version = XFS_DQUOT_VERSION;
+ d->dd_diskdq.d_id = cpu_to_be32(curid);
+ d->dd_diskdq.d_flags = type;
+ }
+
xfs_trans_dquot_buf(tp, bp,
(type & XFS_DQ_USER ? XFS_BLF_UDQUOT_BUF :
((type & XFS_DQ_PROJ) ? XFS_BLF_PDQUOT_BUF :
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 29/45] xfs: kill xfs_qm_idtodq
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (24 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 28/45] xfs: kill xfs_qm_dqinit_core Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 30/45] xfs: remove XFS_QMOPT_DQSUSER Christoph Hellwig
` (15 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-cleanup-quota-read --]
[-- Type: text/plain, Size: 5229 bytes --]
This function doesn't help the code flow, so merge the dquot allocation and
transaction handling into xfs_qm_dqread.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 134 ++++++++++++++++++-----------------------------------
1 file changed, 47 insertions(+), 87 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:06.408674693 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:06.948673259 +0200
@@ -551,36 +551,59 @@ xfs_qm_dqtobp(
* Read in the ondisk dquot using dqtobp() then copy it to an incore version,
* and release the buffer immediately.
*
+ * If XFS_QMOPT_DQALLOC is set, allocate a dquot on disk if it needed.
*/
-/* ARGSUSED */
STATIC int
xfs_qm_dqread(
- xfs_trans_t **tpp,
- xfs_dqid_t id,
- xfs_dquot_t *dqp, /* dquot to get filled in */
- uint flags)
+ struct xfs_mount *mp,
+ xfs_dqid_t id,
+ uint type,
+ uint flags,
+ struct xfs_dquot **O_dqpp)
{
- xfs_disk_dquot_t *ddqp;
- xfs_buf_t *bp;
- int error;
- xfs_trans_t *tp;
+ struct xfs_dquot *dqp;
+ struct xfs_disk_dquot *ddqp;
+ struct xfs_buf *bp;
+ struct xfs_trans *tp = NULL;
+ int error;
+ int cancelflags = 0;
- ASSERT(tpp);
+ dqp = xfs_qm_dqinit(mp, id, type);
trace_xfs_dqread(dqp);
+ if (flags & XFS_QMOPT_DQALLOC) {
+ tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);
+ error = xfs_trans_reserve(tp, XFS_QM_DQALLOC_SPACE_RES(mp),
+ XFS_WRITE_LOG_RES(mp) +
+ BBTOB(mp->m_quotainfo->qi_dqchunklen) - 1 +
+ 128,
+ 0,
+ XFS_TRANS_PERM_LOG_RES,
+ XFS_WRITE_LOG_COUNT);
+ if (error)
+ goto error1;
+ cancelflags = XFS_TRANS_RELEASE_LOG_RES;
+ }
+
/*
* get a pointer to the on-disk dquot and the buffer containing it
* dqp already knows its own type (GROUP/USER).
*/
- if ((error = xfs_qm_dqtobp(tpp, dqp, &ddqp, &bp, flags))) {
- return (error);
+ error = xfs_qm_dqtobp(&tp, dqp, &ddqp, &bp, flags);
+ if (error) {
+ /*
+ * This can happen if quotas got turned off (ESRCH),
+ * or if the dquot didn't exist on disk and we ask to
+ * allocate (ENOENT).
+ */
+ trace_xfs_dqread_fail(dqp);
+ cancelflags |= XFS_TRANS_ABORT;
+ goto error1;
}
- tp = *tpp;
/* copy everything from disk dquot to the incore dquot */
memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
- ASSERT(be32_to_cpu(dqp->q_core.d_id) == id);
xfs_qm_dquot_logitem_init(dqp);
/*
@@ -609,77 +632,22 @@ xfs_qm_dqread(
ASSERT(xfs_buf_islocked(bp));
xfs_trans_brelse(tp, bp);
- return (error);
-}
-
-
-/*
- * allocate an incore dquot from the kernel heap,
- * and fill its core with quota information kept on disk.
- * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk
- * if it wasn't already allocated.
- */
-STATIC int
-xfs_qm_idtodq(
- xfs_mount_t *mp,
- xfs_dqid_t id, /* gid or uid, depending on type */
- uint type, /* UDQUOT or GDQUOT */
- uint flags, /* DQALLOC, DQREPAIR */
- xfs_dquot_t **O_dqpp)/* OUT : incore dquot, not locked */
-{
- xfs_dquot_t *dqp;
- int error;
- xfs_trans_t *tp;
- int cancelflags=0;
-
- dqp = xfs_qm_dqinit(mp, id, type);
- tp = NULL;
- if (flags & XFS_QMOPT_DQALLOC) {
- tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);
- error = xfs_trans_reserve(tp, XFS_QM_DQALLOC_SPACE_RES(mp),
- XFS_WRITE_LOG_RES(mp) +
- BBTOB(mp->m_quotainfo->qi_dqchunklen) - 1 +
- 128,
- 0,
- XFS_TRANS_PERM_LOG_RES,
- XFS_WRITE_LOG_COUNT);
- if (error) {
- cancelflags = 0;
- goto error0;
- }
- cancelflags = XFS_TRANS_RELEASE_LOG_RES;
- }
-
- /*
- * Read it from disk; xfs_dqread() takes care of
- * all the necessary initialization of dquot's fields (locks, etc)
- */
- if ((error = xfs_qm_dqread(&tp, id, dqp, flags))) {
- /*
- * This can happen if quotas got turned off (ESRCH),
- * or if the dquot didn't exist on disk and we ask to
- * allocate (ENOENT).
- */
- trace_xfs_dqread_fail(dqp);
- cancelflags |= XFS_TRANS_ABORT;
- goto error0;
- }
if (tp) {
- if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES)))
- goto error1;
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+ if (error)
+ goto error0;
}
*O_dqpp = dqp;
- return (0);
+ return error;
- error0:
- ASSERT(error);
+error1:
if (tp)
xfs_trans_cancel(tp, cancelflags);
- error1:
+error0:
xfs_qm_dqdestroy(dqp);
*O_dqpp = NULL;
- return (error);
+ return error;
}
/*
@@ -833,19 +801,11 @@ restart:
version = h->qh_version;
mutex_unlock(&h->qh_lock);
- /*
- * Allocate the dquot on the kernel heap, and read the ondisk
- * portion off the disk. Also, do all the necessary initialization
- * This can return ENOENT if dquot didn't exist on disk and we didn't
- * ask it to allocate; ESRCH if quotas got turned off suddenly.
- */
- if ((error = xfs_qm_idtodq(mp, id, type,
- flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR|
- XFS_QMOPT_DOWARN),
- &dqp))) {
+ error = xfs_qm_dqread(mp, id, type, flags, &dqp);
+ if (error) {
if (ip)
xfs_ilock(ip, XFS_ILOCK_EXCL);
- return (error);
+ return error;
}
/*
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 30/45] xfs: remove XFS_QMOPT_DQSUSER
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (25 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 29/45] xfs: kill xfs_qm_idtodq Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 31/45] xfs: simplify xfs_qm_detach_gdquots Christoph Hellwig
` (14 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-kill-XFS_QMOPT_DQSUSER --]
[-- Type: text/plain, Size: 5052 bytes --]
Just read the id 0 dquot from disk directly in xfs_qm_init_quotainfo, instead
of going through dqget and having a special flag to not add the dquot to any
lists.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 27 ++++++---------------------
fs/xfs/xfs_dquot.h | 2 ++
fs/xfs/xfs_qm.c | 22 ++++++++++------------
fs/xfs/xfs_quota.h | 1 -
4 files changed, 18 insertions(+), 34 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:06.948673259 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:07.534173092 +0200
@@ -553,7 +553,7 @@ xfs_qm_dqtobp(
*
* If XFS_QMOPT_DQALLOC is set, allocate a dquot on disk if it needed.
*/
-STATIC int
+int
xfs_qm_dqread(
struct xfs_mount *mp,
xfs_dqid_t id,
@@ -802,32 +802,17 @@ restart:
mutex_unlock(&h->qh_lock);
error = xfs_qm_dqread(mp, id, type, flags, &dqp);
- if (error) {
- if (ip)
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- return error;
- }
- /*
- * See if this is mount code calling to look at the overall quota limits
- * which are stored in the id == 0 user or group's dquot.
- * Since we may not have done a quotacheck by this point, just return
- * the dquot without attaching it to any hashtables, lists, etc, or even
- * taking a reference.
- * The caller must dqdestroy this once done.
- */
- if (flags & XFS_QMOPT_DQSUSER) {
- ASSERT(id == 0);
- ASSERT(! ip);
- goto dqret;
- }
+ if (ip)
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+ if (error)
+ return error;
/*
* Dquot lock comes after hashlock in the lock ordering
*/
if (ip) {
- xfs_ilock(ip, XFS_ILOCK_EXCL);
-
/*
* A dquot could be attached to this inode by now, since
* we had dropped the ilock.
Index: xfs/fs/xfs/xfs_dquot.h
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.h 2011-10-27 22:40:05.876670670 +0200
+++ xfs/fs/xfs/xfs_dquot.h 2011-10-27 22:40:07.534173092 +0200
@@ -129,6 +129,8 @@ static inline void xfs_dqunlock_nonotify
(XFS_IS_UQUOTA_ON((d)->q_mount)) : \
(XFS_IS_OQUOTA_ON((d)->q_mount))))
+extern int xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
+ uint, struct xfs_dquot **);
extern void xfs_qm_dqdestroy(xfs_dquot_t *);
extern int xfs_qm_dqflush(xfs_dquot_t *, uint);
extern void xfs_qm_dqpurge(xfs_dquot_t *);
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:05.868674047 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:07.538179215 +0200
@@ -858,18 +858,21 @@ xfs_qm_init_quotainfo(
/*
* We try to get the limits from the superuser's limits fields.
* This is quite hacky, but it is standard quota practice.
+ *
* We look at the USR dquot with id == 0 first, but if user quotas
* are not enabled we goto the GRP dquot with id == 0.
* We don't really care to keep separate default limits for user
* and group quotas, at least not at this point.
+ *
+ * Since we may not have done a quotacheck by this point, just read
+ * the dquot without attaching it to any hashtables or lists.
*/
- error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0,
- XFS_IS_UQUOTA_RUNNING(mp) ? XFS_DQ_USER :
- (XFS_IS_GQUOTA_RUNNING(mp) ? XFS_DQ_GROUP :
- XFS_DQ_PROJ),
- XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
- &dqp);
- if (! error) {
+ error = xfs_qm_dqread(mp, 0,
+ XFS_IS_UQUOTA_RUNNING(mp) ? XFS_DQ_USER :
+ (XFS_IS_GQUOTA_RUNNING(mp) ? XFS_DQ_GROUP :
+ XFS_DQ_PROJ),
+ XFS_QMOPT_DOWARN, &dqp);
+ if (!error) {
xfs_disk_dquot_t *ddqp = &dqp->q_core;
/*
@@ -896,11 +899,6 @@ xfs_qm_init_quotainfo(
qinf->qi_rtbhardlimit = be64_to_cpu(ddqp->d_rtb_hardlimit);
qinf->qi_rtbsoftlimit = be64_to_cpu(ddqp->d_rtb_softlimit);
- /*
- * We sent the XFS_QMOPT_DQSUSER flag to dqget because
- * we don't want this dquot cached. We haven't done a
- * quotacheck yet, and quotacheck doesn't like incore dquots.
- */
xfs_qm_dqdestroy(dqp);
} else {
qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
Index: xfs/fs/xfs/xfs_quota.h
===================================================================
--- xfs.orig/fs/xfs/xfs_quota.h 2011-10-27 22:40:04.376671215 +0200
+++ xfs/fs/xfs/xfs_quota.h 2011-10-27 22:40:07.542229613 +0200
@@ -197,7 +197,6 @@ typedef struct xfs_qoff_logformat {
#define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */
#define XFS_QMOPT_PQUOTA 0x0000008 /* project dquot requested */
#define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */
-#define XFS_QMOPT_DQSUSER 0x0000020 /* don't cache super users dquot */
#define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */
#define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if needed */
#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot if damaged */
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 31/45] xfs: simplify xfs_qm_detach_gdquots
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (26 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 30/45] xfs: remove XFS_QMOPT_DQSUSER Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 32/45] xfs: use a normal shrinker for the dquot freelist Christoph Hellwig
` (13 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-simplify-xfs_qm_detach_gdquots --]
[-- Type: text/plain, Size: 1407 bytes --]
With the new lock order there is no reason to drop qi_dqlist_lock around
calls to xfs_qm_dqrele.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_qm.c | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:07.538179215 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:08.124671538 +0200
@@ -449,7 +449,6 @@ xfs_qm_detach_gdquots(
{
struct xfs_quotainfo *q = mp->m_quotainfo;
struct xfs_dquot *dqp, *gdqp;
- int nrecl;
again:
ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
@@ -462,25 +461,14 @@ xfs_qm_detach_gdquots(
mutex_lock(&q->qi_dqlist_lock);
goto again;
}
- if ((gdqp = dqp->q_gdquot)) {
- xfs_dqlock(gdqp);
+
+ gdqp = dqp->q_gdquot;
+ if (gdqp)
dqp->q_gdquot = NULL;
- }
xfs_dqunlock(dqp);
- if (gdqp) {
- /*
- * Can't hold the mplist lock across a dqput.
- * XXXmust convert to marker based iterations here.
- */
- nrecl = q->qi_dqreclaims;
- mutex_unlock(&q->qi_dqlist_lock);
- xfs_qm_dqput(gdqp);
-
- mutex_lock(&q->qi_dqlist_lock);
- if (nrecl != q->qi_dqreclaims)
- goto again;
- }
+ if (gdqp)
+ xfs_qm_dqrele(gdqp);
}
}
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 32/45] xfs: use a normal shrinker for the dquot freelist
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (27 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 31/45] xfs: simplify xfs_qm_detach_gdquots Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 33/45] xfs: reclaim clean dquots first Christoph Hellwig
` (12 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-fix-shrinker --]
[-- Type: text/plain, Size: 15928 bytes --]
Stop reusing dquots from the freelist when allocating new ones directly, and
implement a shrinker that actually follows the specifications for the
interface. The shrinker implementation is still highly suboptimal at this
point, but we can gradually work on it.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/kmem.h | 6 -
fs/xfs/xfs_dquot.c | 103 ++++---------------
fs/xfs/xfs_qm.c | 271 ++++++++++++++++----------------------------------
fs/xfs/xfs_qm.h | 9 -
fs/xfs/xfs_qm_stats.c | 4
fs/xfs/xfs_trace.h | 2
6 files changed, 120 insertions(+), 275 deletions(-)
Index: xfs/fs/xfs/kmem.h
===================================================================
--- xfs.orig/fs/xfs/kmem.h 2011-10-27 22:39:33.216674214 +0200
+++ xfs/fs/xfs/kmem.h 2011-10-27 22:40:08.594173542 +0200
@@ -115,10 +115,4 @@ kmem_zone_destroy(kmem_zone_t *zone)
extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);
-static inline int
-kmem_shake_allow(gfp_t gfp_mask)
-{
- return ((gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS));
-}
-
#endif /* __XFS_SUPPORT_KMEM_H__ */
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:08.124671538 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:08.594173542 +0200
@@ -50,7 +50,6 @@
*/
struct mutex xfs_Gqm_lock;
struct xfs_qm *xfs_Gqm;
-uint ndquot;
kmem_zone_t *qm_dqzone;
kmem_zone_t *qm_dqtrxzone;
@@ -93,7 +92,6 @@ xfs_Gqm_init(void)
goto out_free_udqhash;
hsize /= sizeof(xfs_dqhash_t);
- ndquot = hsize << 8;
xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
xqm->qm_dqhashmask = hsize - 1;
@@ -137,7 +135,6 @@ xfs_Gqm_init(void)
xqm->qm_dqtrxzone = qm_dqtrxzone;
atomic_set(&xqm->qm_totaldquots, 0);
- xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;
xqm->qm_nrefs = 0;
return xqm;
@@ -1600,214 +1597,130 @@ xfs_qm_init_quotainos(
return 0;
}
+STATIC bool
+xfs_qm_dqreclaim_one(
+ struct xfs_dquot *dqp)
+{
+ struct xfs_mount *mp = dqp->q_mount;
+ int error;
+ /*
+ * Move the dquot to the tail so that we don't spin on it.
+ */
+ if (!xfs_dqlock_nowait(dqp))
+ goto out_busy;
-/*
- * Pop the least recently used dquot off the freelist and recycle it.
- */
-STATIC struct xfs_dquot *
-xfs_qm_dqreclaim_one(void)
-{
- struct xfs_dquot *dqp;
- int restarts = 0;
+ /*
+ * This dquot has already been grabbed by dqlookup.
+ * Remove it from the freelist and try again.
+ */
+ if (dqp->q_nrefs) {
+ xfs_dqunlock(dqp);
- mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-restart:
- list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) {
- struct xfs_mount *mp = dqp->q_mount;
+ trace_xfs_dqreclaim_want(dqp);
+ XQM_STATS_INC(xqmstats.xs_qm_dqwants);
- if (!xfs_dqlock_nowait(dqp))
- continue;
+ list_del_init(&dqp->q_freelist);
+ xfs_Gqm->qm_dqfrlist_cnt--;
+ return true;
+ }
- /*
- * This dquot has already been grabbed by dqlookup.
- * Remove it from the freelist and try again.
- */
- if (dqp->q_nrefs) {
- trace_xfs_dqreclaim_want(dqp);
- XQM_STATS_INC(xqmstats.xs_qm_dqwants);
-
- list_del_init(&dqp->q_freelist);
- xfs_Gqm->qm_dqfrlist_cnt--;
- restarts++;
- goto dqunlock;
- }
+ ASSERT(dqp->q_hash);
+ ASSERT(!list_empty(&dqp->q_mplist));
- ASSERT(dqp->q_hash);
- ASSERT(!list_empty(&dqp->q_mplist));
+ /*
+ * Try to grab the flush lock. If this dquot is in the process of
+ * getting flushed to disk, we don't want to reclaim it.
+ */
+ if (!xfs_dqflock_nowait(dqp))
+ goto out_busy;
- /*
- * Try to grab the flush lock. If this dquot is in the process
- * of getting flushed to disk, we don't want to reclaim it.
- */
- if (!xfs_dqflock_nowait(dqp))
- goto dqunlock;
+ /*
+ * We have the flush lock so we know that this is not in the
+ * process of being flushed. So, if this is dirty, flush it
+ * DELWRI so that we don't get a freelist infested with
+ * dirty dquots.
+ */
+ if (XFS_DQ_IS_DIRTY(dqp)) {
+ trace_xfs_dqreclaim_dirty(dqp);
/*
- * We have the flush lock so we know that this is not in the
- * process of being flushed. So, if this is dirty, flush it
- * DELWRI so that we don't get a freelist infested with
- * dirty dquots.
+ * We flush it delayed write, so don't bother releasing the
+ * freelist lock.
*/
- if (XFS_DQ_IS_DIRTY(dqp)) {
- int error;
-
- trace_xfs_dqreclaim_dirty(dqp);
-
- /*
- * We flush it delayed write, so don't bother
- * releasing the freelist lock.
- */
- error = xfs_qm_dqflush(dqp, 0);
- if (error) {
- xfs_warn(mp, "%s: dquot %p flush failed",
- __func__, dqp);
- }
- goto dqunlock;
+ error = xfs_qm_dqflush(dqp, 0);
+ if (error) {
+ xfs_warn(mp, "%s: dquot %p flush failed",
+ __func__, dqp);
}
- xfs_dqfunlock(dqp);
/*
- * Prevent lookups now that we are past the point of no return.
+ * Give the dquot another try on the freelist, as the
+ * flushing will take some time.
*/
- dqp->dq_flags |= XFS_DQ_FREEING;
- xfs_dqunlock(dqp);
-
- mutex_lock(&dqp->q_hash->qh_lock);
- list_del_init(&dqp->q_hashlist);
- dqp->q_hash->qh_version++;
- mutex_unlock(&dqp->q_hash->qh_lock);
-
- mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
- list_del_init(&dqp->q_mplist);
- mp->m_quotainfo->qi_dquots--;
- mp->m_quotainfo->qi_dqreclaims++;
- mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
-
- ASSERT(dqp->q_nrefs == 0);
- list_del_init(&dqp->q_freelist);
- xfs_Gqm->qm_dqfrlist_cnt--;
-
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- return dqp;
-dqunlock:
- xfs_dqunlock(dqp);
- if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
- break;
- goto restart;
+ goto out_busy;
}
+ xfs_dqfunlock(dqp);
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- return NULL;
-}
+ /*
+ * Prevent lookups now that we are past the point of no return.
+ */
+ dqp->dq_flags |= XFS_DQ_FREEING;
+ xfs_dqunlock(dqp);
-/*
- * Traverse the freelist of dquots and attempt to reclaim a maximum of
- * 'howmany' dquots. This operation races with dqlookup(), and attempts to
- * favor the lookup function ...
- */
-STATIC int
-xfs_qm_shake_freelist(
- int howmany)
-{
- int nreclaimed = 0;
- xfs_dquot_t *dqp;
+ mutex_lock(&dqp->q_hash->qh_lock);
+ list_del_init(&dqp->q_hashlist);
+ dqp->q_hash->qh_version++;
+ mutex_unlock(&dqp->q_hash->qh_lock);
+
+ mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
+ list_del_init(&dqp->q_mplist);
+ mp->m_quotainfo->qi_dquots--;
+ mp->m_quotainfo->qi_dqreclaims++;
+ mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
+
+ ASSERT(dqp->q_nrefs == 0);
+ list_del_init(&dqp->q_freelist);
+ xfs_Gqm->qm_dqfrlist_cnt--;
+ XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);
- if (howmany <= 0)
- return 0;
+ xfs_qm_dqdestroy(dqp);
+ return true;
- while (nreclaimed < howmany) {
- dqp = xfs_qm_dqreclaim_one();
- if (!dqp)
- return nreclaimed;
- xfs_qm_dqdestroy(dqp);
- nreclaimed++;
- }
- return nreclaimed;
+out_busy:
+ xfs_dqunlock(dqp);
+ return false;
}
-/*
- * The kmem_shake interface is invoked when memory is running low.
- */
-/* ARGSUSED */
STATIC int
xfs_qm_shake(
- struct shrinker *shrink,
- struct shrink_control *sc)
+ struct shrinker *shrink,
+ struct shrink_control *sc)
{
- int ndqused, nfree, n;
- gfp_t gfp_mask = sc->gfp_mask;
-
- if (!kmem_shake_allow(gfp_mask))
- return 0;
- if (!xfs_Gqm)
- return 0;
-
- nfree = xfs_Gqm->qm_dqfrlist_cnt; /* free dquots */
- /* incore dquots in all f/s's */
- ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree;
-
- ASSERT(ndqused >= 0);
+ int nr_to_scan = sc->nr_to_scan;
+ struct xfs_dquot *dqp;
- if (nfree <= ndqused && nfree < ndquot)
+ if ((sc->gfp_mask & (__GFP_FS|__GFP_WAIT)) != (__GFP_FS|__GFP_WAIT))
return 0;
- ndqused *= xfs_Gqm->qm_dqfree_ratio; /* target # of free dquots */
- n = nfree - ndqused - ndquot; /* # over target */
-
- return xfs_qm_shake_freelist(MAX(nfree, n));
-}
-
-
-/*------------------------------------------------------------------*/
+ if (!nr_to_scan)
+ goto out;
-/*
- * Return a new incore dquot. Depending on the number of
- * dquots in the system, we either allocate a new one on the kernel heap,
- * or reclaim a free one.
- * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed
- * to reclaim an existing one from the freelist.
- */
-boolean_t
-xfs_qm_dqalloc_incore(
- xfs_dquot_t **O_dqpp)
-{
- xfs_dquot_t *dqp;
+ mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
+ while (!list_empty(&xfs_Gqm->qm_dqfrlist)) {
+ if (nr_to_scan-- <= 0)
+ break;
+ dqp = list_first_entry(&xfs_Gqm->qm_dqfrlist, struct xfs_dquot,
+ q_freelist);
- /*
- * Check against high water mark to see if we want to pop
- * a nincompoop dquot off the freelist.
- */
- if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) {
- /*
- * Try to recycle a dquot from the freelist.
- */
- if ((dqp = xfs_qm_dqreclaim_one())) {
- XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);
- /*
- * Just zero the core here. The rest will get
- * reinitialized by caller. XXX we shouldn't even
- * do this zero ...
- */
- memset(&dqp->q_core, 0, sizeof(dqp->q_core));
- *O_dqpp = dqp;
- return B_FALSE;
- }
- XQM_STATS_INC(xqmstats.xs_qm_dqreclaim_misses);
+ if (!xfs_qm_dqreclaim_one(dqp))
+ list_move_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
}
-
- /*
- * Allocate a brand new dquot on the kernel heap and return it
- * to the caller to initialize.
- */
- ASSERT(xfs_Gqm->qm_dqzone != NULL);
- *O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
- atomic_inc(&xfs_Gqm->qm_totaldquots);
-
- return B_TRUE;
+ mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+out:
+ return (xfs_Gqm->qm_dqfrlist_cnt / 100) * sysctl_vfs_cache_pressure;
}
-
/*
* Start a transaction and write the incore superblock changes to
* disk. flags parameter indicates which fields have changed.
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:07.534173092 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:08.598176882 +0200
@@ -64,82 +64,6 @@ int xfs_dqerror_mod = 33;
static struct lock_class_key xfs_dquot_other_class;
/*
- * Allocate and initialize a dquot. We don't always allocate fresh memory;
- * we try to reclaim a free dquot if the number of incore dquots are above
- * a threshold.
- * The only field inside the core that gets initialized at this point
- * is the d_id field. The idea is to fill in the entire q_core
- * when we read in the on disk dquot.
- */
-STATIC xfs_dquot_t *
-xfs_qm_dqinit(
- xfs_mount_t *mp,
- xfs_dqid_t id,
- uint type)
-{
- xfs_dquot_t *dqp;
- boolean_t brandnewdquot;
-
- brandnewdquot = xfs_qm_dqalloc_incore(&dqp);
- dqp->dq_flags = type;
- dqp->q_core.d_id = cpu_to_be32(id);
- dqp->q_mount = mp;
-
- /*
- * No need to re-initialize these if this is a reclaimed dquot.
- */
- if (brandnewdquot) {
- INIT_LIST_HEAD(&dqp->q_freelist);
- mutex_init(&dqp->q_qlock);
- init_waitqueue_head(&dqp->q_pinwait);
-
- /*
- * Because we want to use a counting completion, complete
- * the flush completion once to allow a single access to
- * the flush completion without blocking.
- */
- init_completion(&dqp->q_flush);
- complete(&dqp->q_flush);
-
- trace_xfs_dqinit(dqp);
- } else {
- /*
- * Only the q_core portion was zeroed in dqreclaim_one().
- * So, we need to reset others.
- */
- dqp->q_nrefs = 0;
- dqp->q_blkno = 0;
- INIT_LIST_HEAD(&dqp->q_mplist);
- INIT_LIST_HEAD(&dqp->q_hashlist);
- dqp->q_bufoffset = 0;
- dqp->q_fileoffset = 0;
- dqp->q_transp = NULL;
- dqp->q_gdquot = NULL;
- dqp->q_res_bcount = 0;
- dqp->q_res_icount = 0;
- dqp->q_res_rtbcount = 0;
- atomic_set(&dqp->q_pincount, 0);
- dqp->q_hash = NULL;
- ASSERT(list_empty(&dqp->q_freelist));
-
- trace_xfs_dqreuse(dqp);
- }
-
- /*
- * In either case we need to make sure group quotas have a different
- * lock class than user quotas, to make sure lockdep knows we can
- * locks of one of each at the same time.
- */
- if (!(type & XFS_DQ_USER))
- lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
-
- /*
- * log item gets initialized later
- */
- return (dqp);
-}
-
-/*
* This is called to free all the memory associated with a dquot
*/
void
@@ -568,7 +492,32 @@ xfs_qm_dqread(
int error;
int cancelflags = 0;
- dqp = xfs_qm_dqinit(mp, id, type);
+
+ dqp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
+
+ dqp->dq_flags = type;
+ dqp->q_core.d_id = cpu_to_be32(id);
+ dqp->q_mount = mp;
+ INIT_LIST_HEAD(&dqp->q_freelist);
+ mutex_init(&dqp->q_qlock);
+ init_waitqueue_head(&dqp->q_pinwait);
+
+ /*
+ * Because we want to use a counting completion, complete
+ * the flush completion once to allow a single access to
+ * the flush completion without blocking.
+ */
+ init_completion(&dqp->q_flush);
+ complete(&dqp->q_flush);
+
+ /*
+ * Make sure group quotas have a different lock class than user
+ * quotas.
+ */
+ if (!(type & XFS_DQ_USER))
+ lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
+
+ atomic_inc(&xfs_Gqm->qm_totaldquots);
trace_xfs_dqread(dqp);
Index: xfs/fs/xfs/xfs_qm.h
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.h 2011-10-27 22:40:01.234172361 +0200
+++ xfs/fs/xfs/xfs_qm.h 2011-10-27 22:40:08.606225990 +0200
@@ -26,7 +26,6 @@
struct xfs_qm;
struct xfs_inode;
-extern uint ndquot;
extern struct mutex xfs_Gqm_lock;
extern struct xfs_qm *xfs_Gqm;
extern kmem_zone_t *qm_dqzone;
@@ -38,12 +37,6 @@ extern kmem_zone_t *qm_dqtrxzone;
#define XFS_QM_RECLAIM_MAX_RESTARTS 4
/*
- * Ideal ratio of free to in use dquots. Quota manager makes an attempt
- * to keep this balance.
- */
-#define XFS_QM_DQFREE_RATIO 2
-
-/*
* Dquot hashtable constants/threshold values.
*/
#define XFS_QM_HASHSIZE_LOW (PAGE_SIZE / sizeof(xfs_dqhash_t))
@@ -74,7 +67,6 @@ typedef struct xfs_qm {
int qm_dqfrlist_cnt;
atomic_t qm_totaldquots; /* total incore dquots */
uint qm_nrefs; /* file systems with quota on */
- int qm_dqfree_ratio;/* ratio of free to inuse dquots */
kmem_zone_t *qm_dqzone; /* dquot mem-alloc zone */
kmem_zone_t *qm_dqtrxzone; /* t_dqinfo of transactions */
} xfs_qm_t;
@@ -143,7 +135,6 @@ extern int xfs_qm_quotacheck(xfs_mount_
extern int xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
/* dquot stuff */
-extern boolean_t xfs_qm_dqalloc_incore(xfs_dquot_t **);
extern int xfs_qm_dqpurge_all(xfs_mount_t *, uint);
extern void xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
Index: xfs/fs/xfs/xfs_qm_stats.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm_stats.c 2011-10-27 22:39:33.264675954 +0200
+++ xfs/fs/xfs/xfs_qm_stats.c 2011-10-27 22:40:08.610173785 +0200
@@ -42,9 +42,9 @@ static int xqm_proc_show(struct seq_file
{
/* maximum; incore; ratio free to inuse; freelist */
seq_printf(m, "%d\t%d\t%d\t%u\n",
- ndquot,
+ INT_MAX,
xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
- xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0,
+ 0,
xfs_Gqm? xfs_Gqm->qm_dqfrlist_cnt : 0);
return 0;
}
Index: xfs/fs/xfs/xfs_trace.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trace.h 2011-10-27 22:40:03.870173003 +0200
+++ xfs/fs/xfs/xfs_trace.h 2011-10-27 22:40:08.610173785 +0200
@@ -736,8 +736,6 @@ DEFINE_DQUOT_EVENT(xfs_dqreclaim_dirty);
DEFINE_DQUOT_EVENT(xfs_dqreclaim_unlink);
DEFINE_DQUOT_EVENT(xfs_dqattach_found);
DEFINE_DQUOT_EVENT(xfs_dqattach_get);
-DEFINE_DQUOT_EVENT(xfs_dqinit);
-DEFINE_DQUOT_EVENT(xfs_dqreuse);
DEFINE_DQUOT_EVENT(xfs_dqalloc);
DEFINE_DQUOT_EVENT(xfs_dqtobp_read);
DEFINE_DQUOT_EVENT(xfs_dqread);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 33/45] xfs: reclaim clean dquots first
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (28 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 32/45] xfs: use a normal shrinker for the dquot freelist Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 34/45] xfs: do flush inodes during asynchronous inode reclaim Christoph Hellwig
` (11 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-quota-fix-shrinker-2 --]
[-- Type: text/plain, Size: 2707 bytes --]
Always try to reclaim clean dquots before doing I/O in the dquot shrinker.
This is still a bit suboptimal compared to how e.g. the inode shrinker
works, but it is required for the removal of the global delwri lists.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_qm.c | 35 +++++++++++++++++++++--------------
1 file changed, 21 insertions(+), 14 deletions(-)
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:08.594173542 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:09.097172140 +0200
@@ -1599,7 +1599,8 @@ xfs_qm_init_quotainos(
STATIC bool
xfs_qm_dqreclaim_one(
- struct xfs_dquot *dqp)
+ struct xfs_dquot *dqp,
+ bool write_dirty)
{
struct xfs_mount *mp = dqp->q_mount;
int error;
@@ -1642,23 +1643,18 @@ xfs_qm_dqreclaim_one(
* dirty dquots.
*/
if (XFS_DQ_IS_DIRTY(dqp)) {
+ if (!write_dirty)
+ goto out_busy;
+
trace_xfs_dqreclaim_dirty(dqp);
- /*
- * We flush it delayed write, so don't bother releasing the
- * freelist lock.
- */
- error = xfs_qm_dqflush(dqp, 0);
+ mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+ error = xfs_qm_dqflush(dqp, SYNC_WAIT);
if (error) {
xfs_warn(mp, "%s: dquot %p flush failed",
__func__, dqp);
}
-
- /*
- * Give the dquot another try on the freelist, as the
- * flushing will take some time.
- */
- goto out_busy;
+ mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
}
xfs_dqfunlock(dqp);
@@ -1698,7 +1694,7 @@ xfs_qm_shake(
struct shrink_control *sc)
{
int nr_to_scan = sc->nr_to_scan;
- struct xfs_dquot *dqp;
+ struct xfs_dquot *dqp, *n;
if ((sc->gfp_mask & (__GFP_FS|__GFP_WAIT)) != (__GFP_FS|__GFP_WAIT))
return 0;
@@ -1706,16 +1702,27 @@ xfs_qm_shake(
if (!nr_to_scan)
goto out;
+ /*
+ * We first try to reclaim only clean dquots, and only if we have to
+ * start writing dirty ones.
+ */
mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
+ list_for_each_entry_safe(dqp, n, &xfs_Gqm->qm_dqfrlist, q_freelist) {
+ if (nr_to_scan-- <= 0)
+ goto out_unlock;
+ xfs_qm_dqreclaim_one(dqp, false);
+ }
+
while (!list_empty(&xfs_Gqm->qm_dqfrlist)) {
if (nr_to_scan-- <= 0)
break;
dqp = list_first_entry(&xfs_Gqm->qm_dqfrlist, struct xfs_dquot,
q_freelist);
- if (!xfs_qm_dqreclaim_one(dqp))
+ if (!xfs_qm_dqreclaim_one(dqp, true))
list_move_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
}
+out_unlock:
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
out:
return (xfs_Gqm->qm_dqfrlist_cnt / 100) * sysctl_vfs_cache_pressure;
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 34/45] xfs: do flush inodes during asynchronous inode reclaim
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (29 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 33/45] xfs: reclaim clean dquots first Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 35/45] xfs: remove log item from AIL in xfs_qm_dqflush after a shutdown Christoph Hellwig
` (10 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-do-not-write-inodes-from-async-reclaim --]
[-- Type: text/plain, Size: 6311 bytes --]
We already push out the whole AIL when the shrinker is called, so do not
try to flush inodes from asynchronous reclaim as well.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_sync.c | 102 ++++++++++++++++++++++--------------------------------
1 file changed, 42 insertions(+), 60 deletions(-)
Index: xfs/fs/xfs/xfs_sync.c
===================================================================
--- xfs.orig/fs/xfs/xfs_sync.c 2011-10-27 22:40:01.246171848 +0200
+++ xfs/fs/xfs/xfs_sync.c 2011-10-27 22:40:10.705172023 +0200
@@ -702,11 +702,8 @@ xfs_reclaim_inode_grab(
}
/*
- * Inodes in different states need to be treated differently, and the return
- * value of xfs_iflush is not sufficient to get this right. The following table
- * lists the inode states and the reclaim actions necessary for non-blocking
- * reclaim:
- *
+ * Inodes in different states need to be treated differently. The following
+ * table lists the inode states and the reclaim actions necessary:
*
* inode state iflush ret required action
* --------------- ---------- ---------------
@@ -716,9 +713,8 @@ xfs_reclaim_inode_grab(
* stale, unpinned 0 reclaim
* clean, pinned(*) 0 requeue
* stale, pinned EAGAIN requeue
- * dirty, delwri ok 0 requeue
- * dirty, delwri blocked EAGAIN requeue
- * dirty, sync flush 0 reclaim
+ * dirty, async - requeue
+ * dirty, sync 0 reclaim
*
* (*) dgc: I don't think the clean, pinned state is possible but it gets
* handled anyway given the order of checks implemented.
@@ -729,26 +725,23 @@ xfs_reclaim_inode_grab(
*
* Also, because we get the flush lock first, we know that any inode that has
* been flushed delwri has had the flush completed by the time we check that
- * the inode is clean. The clean inode check needs to be done before flushing
- * the inode delwri otherwise we would loop forever requeuing clean inodes as
- * we cannot tell apart a successful delwri flush and a clean inode from the
- * return value of xfs_iflush().
- *
- * Note that because the inode is flushed delayed write by background
- * writeback, the flush lock may already be held here and waiting on it can
- * result in very long latencies. Hence for sync reclaims, where we wait on the
- * flush lock, the caller should push out delayed write inodes first before
- * trying to reclaim them to minimise the amount of time spent waiting. For
- * background relaim, we just requeue the inode for the next pass.
+ * the inode is clean.
+ *
+ * Note that because the inode is flushed delayed write by AIL pushing, the
+ * flush lock may already be held here and waiting on it can result in very
+ * long latencies. Hence for sync reclaims, where we wait on the flush lock,
+ * the caller should push the AIL first before trying to reclaim inodes to
+ * minimise the amount of time spent waiting. For background relaim, we only
+ * bother to reclaim clean inodes anyway.
*
* Hence the order of actions after gaining the locks should be:
* bad => reclaim
* shutdown => unpin and reclaim
- * pinned, delwri => requeue
+ * pinned, async => requeue
* pinned, sync => unpin
* stale => reclaim
* clean => reclaim
- * dirty, delwri => flush and requeue
+ * dirty, async => requeue
* dirty, sync => flush, wait and reclaim
*/
STATIC int
@@ -775,10 +768,8 @@ restart:
goto reclaim;
}
if (xfs_ipincount(ip)) {
- if (!(sync_mode & SYNC_WAIT)) {
- xfs_ifunlock(ip);
- goto out;
- }
+ if (!(sync_mode & SYNC_WAIT))
+ goto out_ifunlock;
xfs_iunpin_wait(ip);
}
if (xfs_iflags_test(ip, XFS_ISTALE))
@@ -787,6 +778,13 @@ restart:
goto reclaim;
/*
+ * Never flush out dirty data during non-blocking reclaim, as it would
+ * just contend with AIL pushing trying to do the same job.
+ */
+ if (!(sync_mode & SYNC_WAIT))
+ goto out_ifunlock;
+
+ /*
* Now we have an inode that needs flushing.
*
* We do a nonblocking flush here even if we are doing a SYNC_WAIT
@@ -804,42 +802,13 @@ restart:
* pass through will see the stale flag set on the inode.
*/
error = xfs_iflush(ip, SYNC_TRYLOCK | sync_mode);
- if (sync_mode & SYNC_WAIT) {
- if (error == EAGAIN) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- /* backoff longer than in xfs_ifree_cluster */
- delay(2);
- goto restart;
- }
- xfs_iflock(ip);
- goto reclaim;
+ if (error == EAGAIN) {
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ /* backoff longer than in xfs_ifree_cluster */
+ delay(2);
+ goto restart;
}
-
- /*
- * When we have to flush an inode but don't have SYNC_WAIT set, we
- * flush the inode out using a delwri buffer and wait for the next
- * call into reclaim to find it in a clean state instead of waiting for
- * it now. We also don't return errors here - if the error is transient
- * then the next reclaim pass will flush the inode, and if the error
- * is permanent then the next sync reclaim will reclaim the inode and
- * pass on the error.
- */
- if (error && error != EAGAIN && !XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- xfs_warn(ip->i_mount,
- "inode 0x%llx background reclaim flush failed with %d",
- (long long)ip->i_ino, error);
- }
-out:
- xfs_iflags_clear(ip, XFS_IRECLAIM);
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- /*
- * We could return EAGAIN here to make reclaim rescan the inode tree in
- * a short while. However, this just burns CPU time scanning the tree
- * waiting for IO to complete and xfssyncd never goes back to the idle
- * state. Instead, return 0 to let the next scheduled background reclaim
- * attempt to reclaim the inode again.
- */
- return 0;
+ xfs_iflock(ip);
reclaim:
xfs_ifunlock(ip);
@@ -877,6 +846,19 @@ reclaim:
xfs_inode_free(ip);
return error;
+out_ifunlock:
+ xfs_ifunlock(ip);
+out:
+ xfs_iflags_clear(ip, XFS_IRECLAIM);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ /*
+ * We could return EAGAIN here to make reclaim rescan the inode tree in
+ * a short while. However, this just burns CPU time scanning the tree
+ * waiting for IO to complete and xfssyncd never goes back to the idle
+ * state. Instead, return 0 to let the next scheduled background reclaim
+ * attempt to reclaim the inode again.
+ */
+ return 0;
}
/*
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 35/45] xfs: remove log item from AIL in xfs_qm_dqflush after a shutdown
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (30 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 34/45] xfs: do flush inodes during asynchronous inode reclaim Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 36/45] xfs: remove log item from AIL in xfs_iflush " Christoph Hellwig
` (9 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-delete-dquot-from-ail-earlier --]
[-- Type: text/plain, Size: 1685 bytes --]
If a filesystem has been forced shutdown we are never going to write dquots
to disk, which means the dquot items will stay in the AIL forever.
Currently that is not a problem, but a pending chance requires us to
empty the AIL before shutting down the filesystem, in which case this
behaviour is lethal. Make sure to remove the log item from the AIL
to allow emptying the AIL on shutdown filesystems.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:08.598176882 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:11.298171586 +0200
@@ -1010,10 +1010,21 @@ xfs_qm_dqflush(
/*
* This may have been unpinned because the filesystem is shutting
* down forcibly. If that's the case we must not write this dquot
- * to disk, because the log record didn't make it to disk!
+ * to disk, because the log record didn't make it to disk.
+ *
+ * We also have to remove the log item from the AIL in this case,
+ * as we wait for an emptry AIL as part of the unmount process.
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
+ struct xfs_log_item *lip = &dqp->q_logitem.qli_item;
dqp->dq_flags &= ~XFS_DQ_DIRTY;
+
+ spin_lock(&mp->m_ail->xa_lock);
+ if (lip->li_flags & XFS_LI_IN_AIL)
+ xfs_trans_ail_delete(mp->m_ail, lip);
+ else
+ spin_unlock(&mp->m_ail->xa_lock);
+
xfs_dqfunlock(dqp);
return XFS_ERROR(EIO);
}
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 36/45] xfs: remove log item from AIL in xfs_iflush after a shutdown
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (31 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 35/45] xfs: remove log item from AIL in xfs_qm_dqflush after a shutdown Christoph Hellwig
@ 2011-10-28 9:54 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 37/45] xfs: implement freezing by emptying the AIL Christoph Hellwig
` (8 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:54 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-delete-inode-from-ail-earlier --]
[-- Type: text/plain, Size: 3260 bytes --]
If a filesystem has been forced shutdown we are never going to write inodes
to disk, which means the dquot items will stay in the AIL until we free
the inod. Currently that is not a problem, but a pending chance requires us
to empty the AIL before shutting down the filesystem, in which case this
behaviour is lethal. Make sure to remove the log item from the AIL
to allow emptying the AIL on shutdown filesystems.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_iget.c | 17 +----------------
fs/xfs/xfs_inode.c | 17 +++++++++--------
2 files changed, 10 insertions(+), 24 deletions(-)
Index: xfs/fs/xfs/xfs_iget.c
===================================================================
--- xfs.orig/fs/xfs/xfs_iget.c 2011-10-27 22:39:59.605174201 +0200
+++ xfs/fs/xfs/xfs_iget.c 2011-10-27 22:40:11.904690190 +0200
@@ -124,23 +124,8 @@ xfs_inode_free(
xfs_idestroy_fork(ip, XFS_ATTR_FORK);
if (ip->i_itemp) {
- /*
- * Only if we are shutting down the fs will we see an
- * inode still in the AIL. If it is there, we should remove
- * it to prevent a use-after-free from occurring.
- */
- xfs_log_item_t *lip = &ip->i_itemp->ili_item;
- struct xfs_ail *ailp = lip->li_ailp;
+ ASSERT(!(ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL));
- ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) ||
- XFS_FORCED_SHUTDOWN(ip->i_mount));
- if (lip->li_flags & XFS_LI_IN_AIL) {
- spin_lock(&ailp->xa_lock);
- if (lip->li_flags & XFS_LI_IN_AIL)
- xfs_trans_ail_delete(ailp, lip);
- else
- spin_unlock(&ailp->xa_lock);
- }
xfs_inode_item_destroy(ip);
ip->i_itemp = NULL;
}
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-10-27 22:39:59.613171175 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-10-27 22:40:11.904690190 +0200
@@ -2407,7 +2407,6 @@ xfs_iflush(
xfs_inode_t *ip,
uint flags)
{
- xfs_inode_log_item_t *iip;
xfs_buf_t *bp;
xfs_dinode_t *dip;
xfs_mount_t *mp;
@@ -2420,7 +2419,6 @@ xfs_iflush(
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > ip->i_df.if_ext_max);
- iip = ip->i_itemp;
mp = ip->i_mount;
/*
@@ -2457,13 +2455,14 @@ xfs_iflush(
/*
* This may have been unpinned because the filesystem is shutting
* down forcibly. If that's the case we must not write this inode
- * to disk, because the log record didn't make it to disk!
+ * to disk, because the log record didn't make it to disk.
+ *
+ * We also have to remove the log item from the AIL in this case,
+ * as we wait for an empty AIL as part of the unmount process.
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
- if (iip)
- iip->ili_format.ilf_fields = 0;
- xfs_ifunlock(ip);
- return XFS_ERROR(EIO);
+ error = XFS_ERROR(EIO);
+ goto abort_out;
}
/*
@@ -2510,11 +2509,13 @@ corrupt_out:
xfs_buf_relse(bp);
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
cluster_corrupt_out:
+ error = XFS_ERROR(EFSCORRUPTED);
+abort_out:
/*
* Unlocks the flush lock
*/
xfs_iflush_abort(ip);
- return XFS_ERROR(EFSCORRUPTED);
+ return error;
}
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 37/45] xfs: implement freezing by emptying the AIL
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (32 preceding siblings ...)
2011-10-28 9:54 ` [PATCH 36/45] xfs: remove log item from AIL in xfs_iflush " Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 38/45] xfs: explicitly empty the AIL on unmount Christoph Hellwig
` (7 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-empty-ail-on-freeze --]
[-- Type: text/plain, Size: 7827 bytes --]
Now that we write back all metadata either synchronously or through the AIL
we can simply implement metadata freezing in terms of emptying the AIL.
The implementation for this is fairly simply and straight-forward: A new
routine is added that increments a counter that tells xfsaild to not stop
until the AIL is empty and then waits on a wakeup from
xfs_trans_ail_delete_bulk to signal that the AIL is empty.
As usual the devil is in the details, in this case the filesystem shutdown
code. Currently we are a bit sloppy there and do not continue ail pushing
in that case, and thus never reach the code in the log item implementations
that can unwind in case of a shutdown filesystem. Also the code to
abort inode and dquot flushes was rather sloppy before and did not remove
the log items from the AIL, which had to be fixed as well.
As an upside we can now remove the radix tree based inode writeback
completely.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_sync.c | 90 ++++--------------------------------------------
fs/xfs/xfs_trans_ail.c | 50 ++++++++++++++++++++++----
fs/xfs/xfs_trans_priv.h | 3 +
3 files changed, 54 insertions(+), 89 deletions(-)
Index: xfs/fs/xfs/xfs_sync.c
===================================================================
--- xfs.orig/fs/xfs/xfs_sync.c 2011-10-27 22:40:10.705172023 +0200
+++ xfs/fs/xfs/xfs_sync.c 2011-10-27 22:40:12.489171652 +0200
@@ -241,45 +241,6 @@ xfs_sync_inode_data(
return error;
}
-STATIC int
-xfs_sync_inode_attr(
- struct xfs_inode *ip,
- struct xfs_perag *pag,
- int flags)
-{
- int error = 0;
-
- xfs_ilock(ip, XFS_ILOCK_SHARED);
- if (xfs_inode_clean(ip))
- goto out_unlock;
- if (!xfs_iflock_nowait(ip)) {
- if (!(flags & SYNC_WAIT))
- goto out_unlock;
- xfs_iflock(ip);
- }
-
- if (xfs_inode_clean(ip)) {
- xfs_ifunlock(ip);
- goto out_unlock;
- }
-
- error = xfs_iflush(ip, flags);
-
- /*
- * We don't want to try again on non-blocking flushes that can't run
- * again immediately. If an inode really must be written, then that's
- * what the SYNC_WAIT flag is for.
- */
- if (error == EAGAIN) {
- ASSERT(!(flags & SYNC_WAIT));
- error = 0;
- }
-
- out_unlock:
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- return error;
-}
-
/*
* Write out pagecache data for the whole filesystem.
*/
@@ -300,19 +261,6 @@ xfs_sync_data(
return 0;
}
-/*
- * Write out inode metadata (attributes) for the whole filesystem.
- */
-STATIC int
-xfs_sync_attr(
- struct xfs_mount *mp,
- int flags)
-{
- ASSERT((flags & ~SYNC_WAIT) == 0);
-
- return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags);
-}
-
STATIC int
xfs_sync_fsdata(
struct xfs_mount *mp)
@@ -379,33 +327,6 @@ xfs_quiesce_data(
return error ? error : error2;
}
-STATIC void
-xfs_quiesce_fs(
- struct xfs_mount *mp)
-{
- int count = 0, pincount;
-
- xfs_reclaim_inodes(mp, 0);
- xfs_flush_buftarg(mp->m_ddev_targp, 0);
-
- /*
- * This loop must run at least twice. The first instance of the loop
- * will flush most meta data but that will generate more meta data
- * (typically directory updates). Which then must be flushed and
- * logged before we can write the unmount record. We also so sync
- * reclaim of inodes to catch any that the above delwri flush skipped.
- */
- do {
- xfs_reclaim_inodes(mp, SYNC_WAIT);
- xfs_sync_attr(mp, SYNC_WAIT);
- pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
- if (!pincount) {
- delay(50);
- count++;
- }
- } while (count < 2);
-}
-
/*
* Second stage of a quiesce. The data is already synced, now we have to take
* care of the metadata. New transactions are already blocked, so we need to
@@ -421,8 +342,8 @@ xfs_quiesce_attr(
while (atomic_read(&mp->m_active_trans) > 0)
delay(100);
- /* flush inodes and push all remaining buffers out to disk */
- xfs_quiesce_fs(mp);
+ /* flush all pending changes from the AIL */
+ xfs_ail_push_all_sync(mp->m_ail);
/*
* Just warn here till VFS can correctly support
@@ -436,7 +357,12 @@ xfs_quiesce_attr(
xfs_warn(mp, "xfs_attr_quiesce: failed to log sb changes. "
"Frozen image may not be consistent.");
xfs_log_unmount_write(mp);
- xfs_unmountfs_writesb(mp);
+
+ /*
+ * At this point we might have modified the superblock again and thus
+ * added an item to the AIL, thus flush it again.
+ */
+ xfs_ail_push_all_sync(mp->m_ail);
}
static void
Index: xfs/fs/xfs/xfs_trans_ail.c
===================================================================
--- xfs.orig/fs/xfs/xfs_trans_ail.c 2011-10-27 22:39:32.544671415 +0200
+++ xfs/fs/xfs/xfs_trans_ail.c 2011-10-27 22:40:12.489171652 +0200
@@ -383,9 +383,8 @@ xfsaild_push(
spin_lock(&ailp->xa_lock);
}
- target = ailp->xa_target;
lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn);
- if (!lip || XFS_FORCED_SHUTDOWN(mp)) {
+ if (!lip) {
/*
* AIL is empty or our push has reached the end.
*/
@@ -397,6 +396,15 @@ xfsaild_push(
XFS_STATS_INC(xs_push_ail);
/*
+ * If we are draining the AIL push all items, not just the current
+ * threshold.
+ */
+ if (atomic_read(&ailp->xa_wait_empty))
+ target = xfs_ail_max(ailp)->li_lsn;
+ else
+ target = ailp->xa_target;
+
+ /*
* While the item we are looking at is below the given threshold
* try to flush it out. We'd like not to stop until we've at least
* tried to push on everything in the AIL with an LSN less than
@@ -466,11 +474,6 @@ xfsaild_push(
}
spin_lock(&ailp->xa_lock);
- /* should we bother continuing? */
- if (XFS_FORCED_SHUTDOWN(mp))
- break;
- ASSERT(mp->m_log);
-
count++;
/*
@@ -611,6 +614,34 @@ xfs_ail_push_all(
}
/*
+ * Push out all items in the AIL immediately and wait until the AIL is empty.
+ */
+void
+xfs_ail_push_all_sync(
+ struct xfs_ail *ailp)
+{
+ DEFINE_WAIT(wait);
+
+ /*
+ * We use a counter instead of a flag here to support multiple
+ * processes calling into sync at the same time.
+ */
+ atomic_inc(&ailp->xa_wait_empty);
+ do {
+ prepare_to_wait(&ailp->xa_empty, &wait, TASK_UNINTERRUPTIBLE);
+
+ wake_up_process(ailp->xa_task);
+
+ if (!xfs_ail_min_lsn(ailp))
+ break;
+ schedule();
+ } while (xfs_ail_min_lsn(ailp));
+ atomic_dec(&ailp->xa_wait_empty);
+
+ finish_wait(&ailp->xa_empty, &wait);
+}
+
+/*
* This is to be called when an item is unlocked that may have
* been in the AIL. It will wake up the first member of the AIL
* wait list if this item's unlocking might allow it to progress.
@@ -802,6 +833,9 @@ xfs_trans_ail_delete_bulk(
tail_lsn = mlip ? mlip->li_lsn : 0;
spin_unlock(&ailp->xa_lock);
xfs_log_move_tail(ailp->xa_mount, tail_lsn);
+
+ if (!mlip)
+ wake_up_all(&ailp->xa_empty);
}
/*
@@ -832,6 +866,8 @@ xfs_trans_ail_init(
INIT_LIST_HEAD(&ailp->xa_ail);
INIT_LIST_HEAD(&ailp->xa_cursors);
spin_lock_init(&ailp->xa_lock);
+ init_waitqueue_head(&ailp->xa_empty);
+ atomic_set(&ailp->xa_wait_empty, 0);
ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
ailp->xa_mount->m_fsname);
Index: xfs/fs/xfs/xfs_trans_priv.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trans_priv.h 2011-10-27 22:39:32.560674824 +0200
+++ xfs/fs/xfs/xfs_trans_priv.h 2011-10-27 22:40:12.489171652 +0200
@@ -71,6 +71,8 @@ struct xfs_ail {
spinlock_t xa_lock;
xfs_lsn_t xa_last_pushed_lsn;
int xa_log_flush;
+ wait_queue_head_t xa_empty;
+ atomic_t xa_wait_empty;
};
/*
@@ -102,6 +104,7 @@ xfs_trans_ail_delete(
void xfs_ail_push(struct xfs_ail *, xfs_lsn_t);
void xfs_ail_push_all(struct xfs_ail *);
+void xfs_ail_push_all_sync(struct xfs_ail *);
xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp);
void xfs_trans_unlocked_item(struct xfs_ail *,
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 38/45] xfs: explicitly empty the AIL on unmount
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (33 preceding siblings ...)
2011-10-28 9:55 ` [PATCH 37/45] xfs: implement freezing by emptying the AIL Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 39/45] xfs: do not write the buffer from xfs_iflush Christoph Hellwig
` (6 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-explicitly-empty-ail-on-umount --]
[-- Type: text/plain, Size: 4005 bytes --]
Just like during a freeze we can make sure all metadata has been written back
on unmount by synchronously emptying the AIL. Unlike during freeze we still
keep a synchronous inode reclaim pass to make sure we relclaim all clean
inodes as well.
After this the last caller of xfs_unmountfs_writesb is gone and it can be
removed.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_mount.c | 56 +++++++++++------------------------------------------
fs/xfs/xfs_mount.h | 1
2 files changed, 12 insertions(+), 45 deletions(-)
Index: xfs/fs/xfs/xfs_mount.c
===================================================================
--- xfs.orig/fs/xfs/xfs_mount.c 2011-10-27 22:40:10.132675928 +0200
+++ xfs/fs/xfs/xfs_mount.c 2011-10-27 22:40:13.126174145 +0200
@@ -22,6 +22,7 @@
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
@@ -1544,15 +1545,15 @@ xfs_unmountfs(
xfs_log_force(mp, XFS_LOG_SYNC);
/*
- * Do a delwri reclaim pass first so that as many dirty inodes are
- * queued up for IO as possible. Then flush the buffers before making
- * a synchronous path to catch all the remaining inodes are reclaimed.
- * This makes the reclaim process as quick as possible by avoiding
- * synchronous writeout and blocking on inodes already in the delwri
- * state as much as possible.
+ * Flush all pending changes from the AIL.
+ */
+ xfs_ail_push_all_sync(mp->m_ail);
+
+ /*
+ * And reclaim all inodes. At this point there should be no dirty
+ * inode, and none should be pinned or locked, but use synchronous
+ * reclaim just to be sure.
*/
- xfs_reclaim_inodes(mp, 0);
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
xfs_reclaim_inodes(mp, SYNC_WAIT);
xfs_qm_unmount(mp);
@@ -1588,15 +1589,12 @@ xfs_unmountfs(
if (error)
xfs_warn(mp, "Unable to update superblock counters. "
"Freespace may not be correct on next mount.");
- xfs_unmountfs_writesb(mp);
/*
- * Make sure all buffers have been flushed and completed before
- * unmounting the log.
+ * At this point we might have modified the superblock again and thus
+ * added an item to the AIL, thus flush it again.
*/
- error = xfs_flush_buftarg(mp->m_ddev_targp, 1);
- if (error)
- xfs_warn(mp, "%d busy buffers during unmount.", error);
+ xfs_ail_push_all_sync(mp->m_ail);
xfs_wait_buftarg(mp->m_ddev_targp);
xfs_log_unmount_write(mp);
@@ -1657,36 +1655,6 @@ xfs_log_sbcount(xfs_mount_t *mp)
return error;
}
-int
-xfs_unmountfs_writesb(xfs_mount_t *mp)
-{
- xfs_buf_t *sbp;
- int error = 0;
-
- /*
- * skip superblock write if fs is read-only, or
- * if we are doing a forced umount.
- */
- if (!((mp->m_flags & XFS_MOUNT_RDONLY) ||
- XFS_FORCED_SHUTDOWN(mp))) {
-
- sbp = xfs_getsb(mp, 0);
-
- XFS_BUF_UNDONE(sbp);
- XFS_BUF_UNREAD(sbp);
- xfs_buf_delwri_dequeue(sbp);
- XFS_BUF_WRITE(sbp);
- XFS_BUF_UNASYNC(sbp);
- ASSERT(sbp->b_target == mp->m_ddev_targp);
- xfsbdstrat(mp, sbp);
- error = xfs_buf_iowait(sbp);
- if (error)
- xfs_buf_ioerror_alert(sbp, __func__);
- xfs_buf_relse(sbp);
- }
- return error;
-}
-
/*
* xfs_mod_sb() can be used to copy arbitrary changes to the
* in-core superblock into the superblock buffer to be logged.
Index: xfs/fs/xfs/xfs_mount.h
===================================================================
--- xfs.orig/fs/xfs/xfs_mount.h 2011-10-27 22:39:57.502188861 +0200
+++ xfs/fs/xfs/xfs_mount.h 2011-10-27 22:40:13.130172675 +0200
@@ -379,7 +379,6 @@ extern __uint64_t xfs_default_resblks(xf
extern int xfs_mountfs(xfs_mount_t *mp);
extern void xfs_unmountfs(xfs_mount_t *);
-extern int xfs_unmountfs_writesb(xfs_mount_t *);
extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
uint, int);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 39/45] xfs: do not write the buffer from xfs_iflush
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (34 preceding siblings ...)
2011-10-28 9:55 ` [PATCH 38/45] xfs: explicitly empty the AIL on unmount Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 40/45] xfs: do not write the buffer from xfs_qm_dqflush Christoph Hellwig
` (5 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-iflush-dont-write-buffer --]
[-- Type: text/plain, Size: 6934 bytes --]
Instead of writing the buffer directly from inside xfs_iflush return it to
the caller and let the caller decide what to do with it. While we're at
it also remove the pincount check that all non-blocking callers already
implement and the new now unused flags parameter.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_inode.c | 56 +++++++++++++++---------------------------------
fs/xfs/xfs_inode.h | 2 -
fs/xfs/xfs_inode_item.c | 17 +++++++++++++-
fs/xfs/xfs_sync.c | 12 +++++-----
4 files changed, 41 insertions(+), 46 deletions(-)
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-10-27 22:40:11.904690190 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-10-27 22:40:13.673170747 +0200
@@ -2394,22 +2394,24 @@ cluster_corrupt_out:
}
/*
- * xfs_iflush() will write a modified inode's changes out to the
- * inode's on disk home. The caller must have the inode lock held
- * in at least shared mode and the inode flush completion must be
- * active as well. The inode lock will still be held upon return from
- * the call and the caller is free to unlock it.
- * The inode flush will be completed when the inode reaches the disk.
- * The flags indicate how the inode's buffer should be written out.
+ * Format a modified inode's changes out to the backing buffer.
+ *
+ * The caller must have the inode lock (shared or exclusive) and inode flush
+ * lock held. The inode lock will still be held upon return from the call
+ * and the caller is free to unlock it. The inode flush lock will be released
+ * when the inode reaches the disk.
+ *
+ * The caller must write out the buffer returned in *bpp and unlocked it using
+ * xfs_buf_relse.
*/
int
xfs_iflush(
- xfs_inode_t *ip,
- uint flags)
+ struct xfs_inode *ip,
+ struct xfs_buf **bpp)
{
- xfs_buf_t *bp;
- xfs_dinode_t *dip;
- xfs_mount_t *mp;
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_buf *bp;
+ struct xfs_dinode *dip;
int error;
XFS_STATS_INC(xs_iflush_count);
@@ -2419,24 +2421,8 @@ xfs_iflush(
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > ip->i_df.if_ext_max);
- mp = ip->i_mount;
+ *bpp = NULL;
- /*
- * We can't flush the inode until it is unpinned, so wait for it if we
- * are allowed to block. We know no one new can pin it, because we are
- * holding the inode lock shared and you need to hold it exclusively to
- * pin the inode.
- *
- * If we are not allowed to block, force the log out asynchronously so
- * that when we come back the inode will be unpinned. If other inodes
- * in the same cluster are dirty, they will probably write the inode
- * out for us if they occur after the log force completes.
- */
- if (!(flags & SYNC_WAIT) && xfs_ipincount(ip)) {
- xfs_iunpin(ip);
- xfs_ifunlock(ip);
- return EAGAIN;
- }
xfs_iunpin_wait(ip);
/*
@@ -2468,8 +2454,7 @@ xfs_iflush(
/*
* Get the buffer containing the on-disk inode.
*/
- error = xfs_itobp(mp, NULL, ip, &dip, &bp,
- (flags & SYNC_TRYLOCK) ? XBF_TRYLOCK : XBF_LOCK);
+ error = xfs_itobp(mp, NULL, ip, &dip, &bp, XBF_TRYLOCK);
if (error || !bp) {
xfs_ifunlock(ip);
return error;
@@ -2497,13 +2482,8 @@ xfs_iflush(
if (error)
goto cluster_corrupt_out;
- if (flags & SYNC_WAIT)
- error = xfs_bwrite(bp);
- else
- xfs_buf_delwri_queue(bp);
-
- xfs_buf_relse(bp);
- return error;
+ *bpp = bp;
+ return 0;
corrupt_out:
xfs_buf_relse(bp);
Index: xfs/fs/xfs/xfs_inode.h
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.h 2011-10-27 22:39:59.613171175 +0200
+++ xfs/fs/xfs/xfs_inode.h 2011-10-27 22:40:13.673170747 +0200
@@ -530,7 +530,7 @@ int xfs_iunlink(struct xfs_trans *, xfs
void xfs_iext_realloc(xfs_inode_t *, int, int);
void xfs_iunpin_wait(xfs_inode_t *);
-int xfs_iflush(xfs_inode_t *, uint);
+int xfs_iflush(struct xfs_inode *, struct xfs_buf **);
void xfs_lock_inodes(xfs_inode_t **, int, uint);
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
Index: xfs/fs/xfs/xfs_inode_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode_item.c 2011-10-27 22:39:59.621171049 +0200
+++ xfs/fs/xfs/xfs_inode_item.c 2011-10-27 22:40:13.681172022 +0200
@@ -552,6 +552,15 @@ xfs_inode_item_trylock(
if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
return XFS_ITEM_LOCKED;
+ /*
+ * Re-check the pincount now that we stabilized the value by
+ * taking the ilock.
+ */
+ if (xfs_ipincount(ip) > 0) {
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ return XFS_ITEM_PINNED;
+ }
+
if (!xfs_iflock_nowait(ip)) {
/*
* inode has already been flushed to the backing buffer,
@@ -716,6 +725,8 @@ xfs_inode_item_push(
{
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
struct xfs_inode *ip = iip->ili_inode;
+ struct xfs_buf *bp = NULL;
+ int error;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
ASSERT(xfs_isiflocked(ip));
@@ -740,7 +751,11 @@ xfs_inode_item_push(
* will pull the inode from the AIL, mark it clean and unlock the flush
* lock.
*/
- (void) xfs_iflush(ip, SYNC_TRYLOCK);
+ error = xfs_iflush(ip, &bp);
+ if (!error) {
+ xfs_buf_delwri_queue(bp);
+ xfs_buf_relse(bp);
+ }
xfs_iunlock(ip, XFS_ILOCK_SHARED);
}
Index: xfs/fs/xfs/xfs_sync.c
===================================================================
--- xfs.orig/fs/xfs/xfs_sync.c 2011-10-27 22:40:12.489171652 +0200
+++ xfs/fs/xfs/xfs_sync.c 2011-10-27 22:40:13.685172888 +0200
@@ -645,10 +645,6 @@ xfs_reclaim_inode_grab(
* (*) dgc: I don't think the clean, pinned state is possible but it gets
* handled anyway given the order of checks implemented.
*
- * As can be seen from the table, the return value of xfs_iflush() is not
- * sufficient to correctly decide the reclaim action here. The checks in
- * xfs_iflush() might look like duplicates, but they are not.
- *
* Also, because we get the flush lock first, we know that any inode that has
* been flushed delwri has had the flush completed by the time we check that
* the inode is clean.
@@ -676,7 +672,8 @@ xfs_reclaim_inode(
struct xfs_perag *pag,
int sync_mode)
{
- int error;
+ struct xfs_buf *bp = NULL;
+ int error;
restart:
error = 0;
@@ -727,12 +724,15 @@ restart:
* just unlock the inode, back off and try again. Hopefully the next
* pass through will see the stale flag set on the inode.
*/
- error = xfs_iflush(ip, SYNC_TRYLOCK | sync_mode);
+ error = xfs_iflush(ip, &bp);
if (error == EAGAIN) {
xfs_iunlock(ip, XFS_ILOCK_EXCL);
/* backoff longer than in xfs_ifree_cluster */
delay(2);
goto restart;
+ } else if (!error) {
+ error = xfs_bwrite(bp);
+ xfs_buf_relse(bp);
}
xfs_iflock(ip);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 40/45] xfs: do not write the buffer from xfs_qm_dqflush
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (35 preceding siblings ...)
2011-10-28 9:55 ` [PATCH 39/45] xfs: do not write the buffer from xfs_iflush Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 41/45] xfs: do not add buffers to the delwri queue until pushed Christoph Hellwig
` (4 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-dqflush-dont-write-buffer --]
[-- Type: text/plain, Size: 6251 bytes --]
Instead of writing the buffer directly from inside xfs_qm_dqflush return it
to the caller and let the caller decide what to do with it. While we're at
it also remove the pincount check that all non-blocking callers already
implement and the new now unused flags parameter. Also remove the
XFS_DQ_IS_DIRTY check that all callers already do for us.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 35 ++++++++++++-----------------------
fs/xfs/xfs_dquot.h | 2 +-
fs/xfs/xfs_dquot_item.c | 19 +++++++++++++++++--
fs/xfs/xfs_qm.c | 30 ++++++++++++++++++++++--------
4 files changed, 52 insertions(+), 34 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:11.298171586 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:14.809173098 +0200
@@ -984,8 +984,8 @@ xfs_qm_dqflush_done(
*/
int
xfs_qm_dqflush(
- xfs_dquot_t *dqp,
- uint flags)
+ struct xfs_dquot *dqp,
+ struct xfs_buf **bpp)
{
struct xfs_mount *mp = dqp->q_mount;
struct xfs_buf *bp;
@@ -997,14 +997,8 @@ xfs_qm_dqflush(
trace_xfs_dqflush(dqp);
- /*
- * If not dirty, or it's pinned and we are not supposed to block, nada.
- */
- if (!XFS_DQ_IS_DIRTY(dqp) ||
- ((flags & SYNC_TRYLOCK) && atomic_read(&dqp->q_pincount) > 0)) {
- xfs_dqfunlock(dqp);
- return 0;
- }
+ *bpp = NULL;
+
xfs_qm_dqunpin_wait(dqp);
/*
@@ -1084,20 +1078,10 @@ xfs_qm_dqflush(
xfs_log_force(mp, 0);
}
- if (flags & SYNC_WAIT)
- error = xfs_bwrite(bp);
- else
- xfs_buf_delwri_queue(bp);
-
- xfs_buf_relse(bp);
-
trace_xfs_dqflush_done(dqp);
- /*
- * dqp is still locked, but caller is free to unlock it now.
- */
+ *bpp = bp;
return error;
-
}
void
@@ -1174,13 +1158,18 @@ xfs_qm_dqpurge(
* we're unmounting, we do care, so we flush it and wait.
*/
if (XFS_DQ_IS_DIRTY(dqp)) {
- int error;
+ struct xfs_buf *bp = NULL;
+ int error;
/*
* We don't care about getting disk errors here. We need
* to purge this dquot anyway, so we go ahead regardless.
*/
- error = xfs_qm_dqflush(dqp, SYNC_WAIT);
+ error = xfs_qm_dqflush(dqp, &bp);
+ if (!error && bp) {
+ error = xfs_bwrite(bp);
+ xfs_buf_relse(bp);
+ }
if (error)
xfs_warn(mp, "%s: dquot %p flush failed",
__func__, dqp);
Index: xfs/fs/xfs/xfs_dquot.h
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.h 2011-10-27 22:40:07.534173092 +0200
+++ xfs/fs/xfs/xfs_dquot.h 2011-10-27 22:40:14.809173098 +0200
@@ -132,7 +132,7 @@ static inline void xfs_dqunlock_nonotify
extern int xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
uint, struct xfs_dquot **);
extern void xfs_qm_dqdestroy(xfs_dquot_t *);
-extern int xfs_qm_dqflush(xfs_dquot_t *, uint);
+extern int xfs_qm_dqflush(struct xfs_dquot *, struct xfs_buf **);
extern void xfs_qm_dqpurge(xfs_dquot_t *);
extern void xfs_qm_dqunpin_wait(xfs_dquot_t *);
extern void xfs_qm_adjust_dqtimers(xfs_mount_t *,
Index: xfs/fs/xfs/xfs_dquot_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot_item.c 2011-10-27 22:40:02.254174248 +0200
+++ xfs/fs/xfs/xfs_dquot_item.c 2011-10-27 22:40:14.813173372 +0200
@@ -120,10 +120,12 @@ xfs_qm_dquot_logitem_push(
struct xfs_log_item *lip)
{
struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
+ struct xfs_buf *bp = NULL;
int error;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
ASSERT(!completion_done(&dqp->q_flush));
+ ASSERT(atomic_read(&dqp->q_pincount) == 0);
/*
* Since we were able to lock the dquot's flush lock and
@@ -134,10 +136,14 @@ xfs_qm_dquot_logitem_push(
* lock without sleeping, then there must not have been
* anyone in the process of flushing the dquot.
*/
- error = xfs_qm_dqflush(dqp, SYNC_TRYLOCK);
- if (error)
+ error = xfs_qm_dqflush(dqp, &bp);
+ if (error) {
xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p",
__func__, error, dqp);
+ } else if (bp) {
+ xfs_buf_delwri_queue(bp);
+ xfs_buf_relse(bp);
+ }
xfs_dqunlock(dqp);
}
@@ -240,6 +246,15 @@ xfs_qm_dquot_logitem_trylock(
if (!xfs_dqlock_nowait(dqp))
return XFS_ITEM_LOCKED;
+ /*
+ * Re-check the pincount now that we stabilized the value by
+ * taking the quota lock.
+ */
+ if (atomic_read(&dqp->q_pincount) > 0) {
+ xfs_dqunlock(dqp);
+ return XFS_ITEM_PINNED;
+ }
+
if (!xfs_dqflock_nowait(dqp)) {
/*
* dquot has already been flushed to the backing buffer,
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:09.097172140 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:14.813173372 +0200
@@ -394,6 +394,8 @@ xfs_qm_dqflush_all(
again:
mutex_lock(&q->qi_dqlist_lock);
list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
+ struct xfs_buf *bp = NULL;
+
xfs_dqlock(dqp);
if ((dqp->dq_flags & XFS_DQ_FREEING) ||
!XFS_DQ_IS_DIRTY(dqp)) {
@@ -418,7 +420,11 @@ again:
* across a disk write.
*/
mutex_unlock(&q->qi_dqlist_lock);
- error = xfs_qm_dqflush(dqp, 0);
+ error = xfs_qm_dqflush(dqp, &bp);
+ if (!error && bp) {
+ xfs_buf_delwri_queue(bp);
+ xfs_buf_relse(bp);
+ }
xfs_dqunlock(dqp);
if (error)
return error;
@@ -1645,16 +1651,24 @@ xfs_qm_dqreclaim_one(
if (XFS_DQ_IS_DIRTY(dqp)) {
if (!write_dirty)
goto out_busy;
+ else {
+ struct xfs_buf *bp = NULL;
- trace_xfs_dqreclaim_dirty(dqp);
- mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
- error = xfs_qm_dqflush(dqp, SYNC_WAIT);
- if (error) {
- xfs_warn(mp, "%s: dquot %p flush failed",
- __func__, dqp);
+ trace_xfs_dqreclaim_dirty(dqp);
+
+ mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+ error = xfs_qm_dqflush(dqp, &bp);
+ if (!error && bp) {
+ xfs_buf_delwri_queue(bp);
+ xfs_buf_relse(bp);
+ }
+ if (error) {
+ xfs_warn(mp, "%s: dquot %p flush failed",
+ __func__, dqp);
+ }
+ mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
}
- mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
}
xfs_dqfunlock(dqp);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 41/45] xfs: do not add buffers to the delwri queue until pushed
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (36 preceding siblings ...)
2011-10-28 9:55 ` [PATCH 40/45] xfs: do not write the buffer from xfs_qm_dqflush Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 42/45] xfs: on-stack delayed write buffer lists Christoph Hellwig
` (3 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-buf-item-write-later --]
[-- Type: text/plain, Size: 2183 bytes --]
Instead of adding buffers to the delwri list as soon as they are logged,
even if they can't be written until commited because they are pinned
defer adding them to the delwri list until xfsaild pushes them. This
makes the code more similar to other log items and prepares for writing
buffers directly from xfsaild.
The complication here is that we need to fail buffers that were added
but not logged yet in xfs_buf_item_unpin, borrowing code from
xfs_bioerror.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_buf_item.c | 11 ++++++++---
fs/xfs/xfs_trans_buf.c | 2 --
2 files changed, 8 insertions(+), 5 deletions(-)
Index: xfs/fs/xfs/xfs_buf_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_buf_item.c 2011-10-27 22:39:42.528674212 +0200
+++ xfs/fs/xfs/xfs_buf_item.c 2011-10-27 22:40:15.630172342 +0200
@@ -460,6 +460,12 @@ xfs_buf_item_unpin(
ASSERT(bp->b_fspriv == NULL);
}
xfs_buf_relse(bp);
+ } else if (freed && remove) {
+ xfs_buf_lock(bp);
+ xfs_buf_ioerror(bp, EIO);
+ XFS_BUF_UNDONE(bp);
+ xfs_buf_stale(bp);
+ xfs_buf_ioend(bp, 0);
}
}
@@ -604,9 +610,7 @@ xfs_buf_item_committed(
}
/*
- * The buffer is locked, but is not a delayed write buffer. This happens
- * if we race with IO completion and hence we don't want to try to write it
- * again. Just release the buffer.
+ * The buffer is locked, but is not a delayed write buffer.
*/
STATIC void
xfs_buf_item_push(
@@ -620,6 +624,7 @@ xfs_buf_item_push(
trace_xfs_buf_item_push(bip);
+ xfs_buf_delwri_queue(bp);
xfs_buf_relse(bp);
}
Index: xfs/fs/xfs/xfs_trans_buf.c
===================================================================
--- xfs.orig/fs/xfs/xfs_trans_buf.c 2011-10-27 22:39:32.056672629 +0200
+++ xfs/fs/xfs/xfs_trans_buf.c 2011-10-27 22:40:15.630172342 +0200
@@ -649,8 +649,6 @@ xfs_trans_log_buf(xfs_trans_t *tp,
bp->b_iodone = xfs_buf_iodone_callbacks;
bip->bli_item.li_cb = xfs_buf_iodone;
- xfs_buf_delwri_queue(bp);
-
trace_xfs_trans_log_buf(bip);
/*
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 42/45] xfs: on-stack delayed write buffer lists
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (37 preceding siblings ...)
2011-10-28 9:55 ` [PATCH 41/45] xfs: do not add buffers to the delwri queue until pushed Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 43/45] xfs: do not try to unpin the inode buffer in xfs_iflush Christoph Hellwig
` (2 subsequent siblings)
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-kill-xfsbufd --]
[-- Type: text/plain, Size: 69494 bytes --]
Queue delwri buffers on a local on-stack list instead of a per-buftarg one,
and write back the buffers per-process instead of by waking up xfsbufd.
This is now easily doable given that we have very few places left that write
delwri buffers:
- log recovery:
Only done at mount time, and already forcing out the buffers
synchronously using xfs_flush_buftarg
- quotacheck:
Same story.
- dquot reclaim:
This should switch to some form of synchronous writeout, but that
will require more surgery to the quota code.
- xfsaild:
This is the main beneficiary of the change. By keeping a local list
of buffers to write we reduce latency of writing out buffers, and
more importably we can remove all the delwri list promotions which
were hitting the buffer cache hard under sustained metadata loads.
The implementation is very straight forward - xfs_buf_delwri_queue now gets
a new list_head pointer that it adds the delwri buffers to, and all callers
need to eventually submit the list using xfs_buf_delwi_submit or
xfs_buf_delwi_submit_nowait. Buffers that already are on a delwri list are
skipped in xfs_buf_delwri_queue, assuming they already are on another delwri
list. The biggest change to pass down the buffer list was done to the AIL
pushing. Now that we operate on buffers the trylock, push and pushbuf log
item methods are merged into a single push routine, which tries to lock the
item, and if possible add the buffer that needs writeback to the buffer list.
This leads to much simpler code than the previous split but requires the
individual IOP_PUSH instances to unlock and reacquire the AIL around calls
to blocking routines.
Given that xfsailds now also handles writing out buffers the conditions for
log forcing and the sleep times needed some small changes. The most
important one is that we consider an AIL busy as long we still have buffers
to push, and the other one is that we do increment the pushed LSN for
buffers that are under flushing at this moment, but still count them towards
the stuck items for restart purposes. Without this we could hammer on stuck
items without ever forcing the log and not make progress under heavy random
delete workloads on fast flash storage devices.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_buf.c | 340 ++++++++++++++++------------------------------
fs/xfs/xfs_buf.h | 29 ---
fs/xfs/xfs_buf_item.c | 92 +++---------
fs/xfs/xfs_dquot.c | 50 ------
fs/xfs/xfs_dquot.h | 1
fs/xfs/xfs_dquot_item.c | 167 ++++++----------------
fs/xfs/xfs_extfree_item.c | 36 +---
fs/xfs/xfs_inode.c | 4
fs/xfs/xfs_inode_item.c | 156 +++++----------------
fs/xfs/xfs_log_recover.c | 46 +++---
fs/xfs/xfs_qm.c | 61 +++-----
fs/xfs/xfs_super.c | 16 --
fs/xfs/xfs_sync.c | 7
fs/xfs/xfs_trace.h | 7
fs/xfs/xfs_trans.h | 18 --
fs/xfs/xfs_trans_ail.c | 107 ++++++--------
fs/xfs/xfs_trans_buf.c | 86 +++--------
fs/xfs/xfs_trans_priv.h | 1
18 files changed, 399 insertions(+), 825 deletions(-)
Index: xfs/fs/xfs/xfs_log_recover.c
===================================================================
--- xfs.orig/fs/xfs/xfs_log_recover.c 2011-10-27 22:39:31.754174668 +0200
+++ xfs/fs/xfs/xfs_log_recover.c 2011-10-27 22:40:16.206172914 +0200
@@ -2103,6 +2103,7 @@ xlog_recover_do_dquot_buffer(
STATIC int
xlog_recover_buffer_pass2(
xlog_t *log,
+ struct list_head *buffer_list,
xlog_recover_item_t *item)
{
xfs_buf_log_format_t *buf_f = item->ri_buf[0].i_addr;
@@ -2173,7 +2174,7 @@ xlog_recover_buffer_pass2(
} else {
ASSERT(bp->b_target->bt_mount == mp);
bp->b_iodone = xlog_recover_iodone;
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
}
xfs_buf_relse(bp);
@@ -2183,6 +2184,7 @@ xlog_recover_buffer_pass2(
STATIC int
xlog_recover_inode_pass2(
xlog_t *log,
+ struct list_head *buffer_list,
xlog_recover_item_t *item)
{
xfs_inode_log_format_t *in_f;
@@ -2436,7 +2438,7 @@ xlog_recover_inode_pass2(
write_inode_buffer:
ASSERT(bp->b_target->bt_mount == mp);
bp->b_iodone = xlog_recover_iodone;
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
error:
if (need_free)
@@ -2477,6 +2479,7 @@ xlog_recover_quotaoff_pass1(
STATIC int
xlog_recover_dquot_pass2(
xlog_t *log,
+ struct list_head *buffer_list,
xlog_recover_item_t *item)
{
xfs_mount_t *mp = log->l_mp;
@@ -2558,7 +2561,7 @@ xlog_recover_dquot_pass2(
ASSERT(dq_f->qlf_size == 2);
ASSERT(bp->b_target->bt_mount == mp);
bp->b_iodone = xlog_recover_iodone;
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
return (0);
@@ -2712,21 +2715,22 @@ STATIC int
xlog_recover_commit_pass2(
struct log *log,
struct xlog_recover *trans,
+ struct list_head *buffer_list,
xlog_recover_item_t *item)
{
trace_xfs_log_recover_item_recover(log, trans, item, XLOG_RECOVER_PASS2);
switch (ITEM_TYPE(item)) {
case XFS_LI_BUF:
- return xlog_recover_buffer_pass2(log, item);
+ return xlog_recover_buffer_pass2(log, buffer_list, item);
case XFS_LI_INODE:
- return xlog_recover_inode_pass2(log, item);
+ return xlog_recover_inode_pass2(log, buffer_list, item);
case XFS_LI_EFI:
return xlog_recover_efi_pass2(log, item, trans->r_lsn);
case XFS_LI_EFD:
return xlog_recover_efd_pass2(log, item);
case XFS_LI_DQUOT:
- return xlog_recover_dquot_pass2(log, item);
+ return xlog_recover_dquot_pass2(log, buffer_list, item);
case XFS_LI_QUOTAOFF:
/* nothing to do in pass2 */
return 0;
@@ -2750,8 +2754,9 @@ xlog_recover_commit_trans(
struct xlog_recover *trans,
int pass)
{
- int error = 0;
+ int error = 0, error2;
xlog_recover_item_t *item;
+ LIST_HEAD (buffer_list);
hlist_del(&trans->r_list);
@@ -2760,16 +2765,27 @@ xlog_recover_commit_trans(
return error;
list_for_each_entry(item, &trans->r_itemq, ri_list) {
- if (pass == XLOG_RECOVER_PASS1)
+ switch (pass) {
+ case XLOG_RECOVER_PASS1:
error = xlog_recover_commit_pass1(log, trans, item);
- else
- error = xlog_recover_commit_pass2(log, trans, item);
+ break;
+ case XLOG_RECOVER_PASS2:
+ error = xlog_recover_commit_pass2(log, trans,
+ &buffer_list, item);
+ break;
+ default:
+ ASSERT(0);
+ }
+
if (error)
- return error;
+ goto out;
}
xlog_recover_free_trans(trans);
- return 0;
+
+out:
+ error2 = xfs_buf_delwri_submit(&buffer_list);
+ return error ? error : error2;
}
STATIC int
@@ -3650,11 +3666,8 @@ xlog_do_recover(
* First replay the images in the log.
*/
error = xlog_do_log_recovery(log, head_blk, tail_blk);
- if (error) {
+ if (error)
return error;
- }
-
- xfs_flush_buftarg(log->l_mp->m_ddev_targp, 1);
/*
* If IO errors happened during recovery, bail out.
@@ -3681,7 +3694,6 @@ xlog_do_recover(
bp = xfs_getsb(log->l_mp, 0);
XFS_BUF_UNDONE(bp);
ASSERT(!(XFS_BUF_ISWRITE(bp)));
- ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
XFS_BUF_READ(bp);
XFS_BUF_UNASYNC(bp);
xfsbdstrat(log->l_mp, bp);
Index: xfs/fs/xfs/xfs_buf.c
===================================================================
--- xfs.orig/fs/xfs/xfs_buf.c 2011-10-27 22:39:57.490177027 +0200
+++ xfs/fs/xfs/xfs_buf.c 2011-10-27 22:40:16.210189457 +0200
@@ -42,7 +42,6 @@
#include "xfs_trace.h"
static kmem_zone_t *xfs_buf_zone;
-STATIC int xfsbufd(void *);
static struct workqueue_struct *xfslogd_workqueue;
@@ -144,8 +143,11 @@ void
xfs_buf_stale(
struct xfs_buf *bp)
{
+ ASSERT(xfs_buf_islocked(bp));
+
bp->b_flags |= XBF_STALE;
- xfs_buf_delwri_dequeue(bp);
+ bp->b_flags &= ~_XBF_DELWRI_Q;
+
atomic_set(&(bp)->b_lru_ref, 0);
if (!list_empty(&bp->b_lru)) {
struct xfs_buftarg *btp = bp->b_target;
@@ -592,10 +594,10 @@ _xfs_buf_read(
{
int status;
- ASSERT(!(flags & (XBF_DELWRI|XBF_WRITE)));
+ ASSERT(!(flags & XBF_WRITE));
ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL);
- bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_DELWRI | XBF_READ_AHEAD);
+ bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_READ_AHEAD);
bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD);
status = xfs_buf_iorequest(bp);
@@ -855,7 +857,7 @@ xfs_buf_rele(
spin_unlock(&pag->pag_buf_lock);
} else {
xfs_buf_lru_del(bp);
- ASSERT(!(bp->b_flags & (XBF_DELWRI|_XBF_DELWRI_Q)));
+ ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
rb_erase(&bp->b_rbnode, &pag->pag_buf_tree);
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
@@ -915,13 +917,6 @@ xfs_buf_lock(
trace_xfs_buf_lock_done(bp, _RET_IP_);
}
-/*
- * Releases the lock on the buffer object.
- * If the buffer is marked delwri but is not queued, do so before we
- * unlock the buffer as we need to set flags correctly. We also need to
- * take a reference for the delwri queue because the unlocker is going to
- * drop their's and they don't know we just queued it.
- */
void
xfs_buf_unlock(
struct xfs_buf *bp)
@@ -1019,10 +1014,11 @@ xfs_bwrite(
{
int error;
+ ASSERT(xfs_buf_islocked(bp));
+
bp->b_flags |= XBF_WRITE;
- bp->b_flags &= ~(XBF_ASYNC | XBF_READ);
+ bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q);
- xfs_buf_delwri_dequeue(bp);
xfs_bdstrat_cb(bp);
error = xfs_buf_iowait(bp);
@@ -1254,7 +1250,7 @@ xfs_buf_iorequest(
{
trace_xfs_buf_iorequest(bp, _RET_IP_);
- ASSERT(!(bp->b_flags & XBF_DELWRI));
+ ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
if (bp->b_flags & XBF_WRITE)
xfs_buf_wait_unpin(bp);
@@ -1435,11 +1431,9 @@ xfs_free_buftarg(
{
unregister_shrinker(&btp->bt_shrinker);
- xfs_flush_buftarg(btp, 1);
if (mp->m_flags & XFS_MOUNT_BARRIER)
xfs_blkdev_issue_flush(btp);
- kthread_stop(btp->bt_task);
kmem_free(btp);
}
@@ -1491,20 +1485,6 @@ xfs_setsize_buftarg(
return xfs_setsize_buftarg_flags(btp, blocksize, sectorsize, 1);
}
-STATIC int
-xfs_alloc_delwri_queue(
- xfs_buftarg_t *btp,
- const char *fsname)
-{
- INIT_LIST_HEAD(&btp->bt_delwri_queue);
- spin_lock_init(&btp->bt_delwri_lock);
- btp->bt_flags = 0;
- btp->bt_task = kthread_run(xfsbufd, btp, "xfsbufd/%s", fsname);
- if (IS_ERR(btp->bt_task))
- return PTR_ERR(btp->bt_task);
- return 0;
-}
-
xfs_buftarg_t *
xfs_alloc_buftarg(
struct xfs_mount *mp,
@@ -1527,8 +1507,6 @@ xfs_alloc_buftarg(
spin_lock_init(&btp->bt_lru_lock);
if (xfs_setsize_buftarg_early(btp, bdev))
goto error;
- if (xfs_alloc_delwri_queue(btp, fsname))
- goto error;
btp->bt_shrinker.shrink = xfs_buftarg_shrink;
btp->bt_shrinker.seeks = DEFAULT_SEEKS;
register_shrinker(&btp->bt_shrinker);
@@ -1539,125 +1517,52 @@ error:
return NULL;
}
-
/*
- * Delayed write buffer handling
+ * Add a buffer to the delayed write list.
+ *
+ * This queues a buffer for writeout if it hasn't already been. Note that
+ * neither this routine nor the buffer list submission functions perform
+ * any internal synchronization. It is expected that the lists are
+ * thread-local in the callers.
+ *
+ * Returns true if we queued up the buffer, or false if it already had
+ * been on the buffer list.
*/
-void
+bool
xfs_buf_delwri_queue(
- xfs_buf_t *bp)
+ struct xfs_buf *bp,
+ struct list_head *list)
{
- struct xfs_buftarg *btp = bp->b_target;
-
- trace_xfs_buf_delwri_queue(bp, _RET_IP_);
-
+ ASSERT(xfs_buf_islocked(bp));
ASSERT(!(bp->b_flags & XBF_READ));
- spin_lock(&btp->bt_delwri_lock);
- if (!list_empty(&bp->b_list)) {
- /* if already in the queue, move it to the tail */
- ASSERT(bp->b_flags & _XBF_DELWRI_Q);
- list_move_tail(&bp->b_list, &btp->bt_delwri_queue);
- } else {
- /* start xfsbufd as it is about to have something to do */
- if (list_empty(&btp->bt_delwri_queue))
- wake_up_process(bp->b_target->bt_task);
-
- atomic_inc(&bp->b_hold);
- bp->b_flags |= XBF_DELWRI | _XBF_DELWRI_Q | XBF_ASYNC;
- list_add_tail(&bp->b_list, &btp->bt_delwri_queue);
- }
- bp->b_queuetime = jiffies;
- spin_unlock(&btp->bt_delwri_lock);
-}
-
-void
-xfs_buf_delwri_dequeue(
- xfs_buf_t *bp)
-{
- int dequeued = 0;
-
- spin_lock(&bp->b_target->bt_delwri_lock);
- if ((bp->b_flags & XBF_DELWRI) && !list_empty(&bp->b_list)) {
- ASSERT(bp->b_flags & _XBF_DELWRI_Q);
- list_del_init(&bp->b_list);
- dequeued = 1;
+ /*
+ * If the buffer is already marked delwri it already is queued up
+ * by someone else for imediate writeout. Just ignore it in that
+ * case.
+ */
+ if (bp->b_flags & _XBF_DELWRI_Q) {
+ trace_xfs_buf_delwri_queued(bp, _RET_IP_);
+ return false;
}
- bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q);
- spin_unlock(&bp->b_target->bt_delwri_lock);
-
- if (dequeued)
- xfs_buf_rele(bp);
-
- trace_xfs_buf_delwri_dequeue(bp, _RET_IP_);
-}
-/*
- * If a delwri buffer needs to be pushed before it has aged out, then promote
- * it to the head of the delwri queue so that it will be flushed on the next
- * xfsbufd run. We do this by resetting the queuetime of the buffer to be older
- * than the age currently needed to flush the buffer. Hence the next time the
- * xfsbufd sees it is guaranteed to be considered old enough to flush.
- */
-void
-xfs_buf_delwri_promote(
- struct xfs_buf *bp)
-{
- struct xfs_buftarg *btp = bp->b_target;
- long age = xfs_buf_age_centisecs * msecs_to_jiffies(10) + 1;
-
- ASSERT(bp->b_flags & XBF_DELWRI);
- ASSERT(bp->b_flags & _XBF_DELWRI_Q);
+ trace_xfs_buf_delwri_queue(bp, _RET_IP_);
/*
- * Check the buffer age before locking the delayed write queue as we
- * don't need to promote buffers that are already past the flush age.
+ * If a buffer gets written out synchronously while it is on a delwri
+ * list we lazily remove it, aka only the _XBF_DELWRI_Q flag gets
+ * cleared, but it remains referenced and on the list. In a rare
+ * corner case it might get readded to a delwri list after the
+ * synchronous writeout, in which case we need just need to re-add
+ * the flag here.
*/
- if (bp->b_queuetime < jiffies - age)
- return;
- bp->b_queuetime = jiffies - age;
- spin_lock(&btp->bt_delwri_lock);
- list_move(&bp->b_list, &btp->bt_delwri_queue);
- spin_unlock(&btp->bt_delwri_lock);
-}
-
-/*
- * Move as many buffers as specified to the supplied list
- * idicating if we skipped any buffers to prevent deadlocks.
- */
-STATIC int
-xfs_buf_delwri_split(
- xfs_buftarg_t *target,
- struct list_head *list,
- unsigned long age)
-{
- xfs_buf_t *bp, *n;
- int skipped = 0;
- int force;
-
- force = test_and_clear_bit(XBT_FORCE_FLUSH, &target->bt_flags);
- INIT_LIST_HEAD(list);
- spin_lock(&target->bt_delwri_lock);
- list_for_each_entry_safe(bp, n, &target->bt_delwri_queue, b_list) {
- ASSERT(bp->b_flags & XBF_DELWRI);
-
- if (!xfs_buf_ispinned(bp) && xfs_buf_trylock(bp)) {
- if (!force &&
- time_before(jiffies, bp->b_queuetime + age)) {
- xfs_buf_unlock(bp);
- break;
- }
-
- bp->b_flags &= ~(XBF_DELWRI | _XBF_DELWRI_Q);
- bp->b_flags |= XBF_WRITE;
- list_move_tail(&bp->b_list, list);
- trace_xfs_buf_delwri_split(bp, _RET_IP_);
- } else
- skipped++;
+ bp->b_flags |= _XBF_DELWRI_Q;
+ if (list_empty(&bp->b_list)) {
+ atomic_inc(&bp->b_hold);
+ list_add_tail(&bp->b_list, list);
}
- spin_unlock(&target->bt_delwri_lock);
- return skipped;
+ return true;
}
/*
@@ -1683,103 +1588,106 @@ xfs_buf_cmp(
return 0;
}
-STATIC int
-xfsbufd(
- void *data)
-{
- xfs_buftarg_t *target = (xfs_buftarg_t *)data;
+static int
+__xfs_buf_delwri_submit(
+ struct list_head *submit_list,
+ struct list_head *list,
+ bool wait)
+{
+ struct blk_plug plug;
+ struct xfs_buf *bp, *n;
+ int pinned = 0;
+
+ list_for_each_entry_safe(bp, n, list, b_list) {
+ if (!wait) {
+ if (xfs_buf_ispinned(bp)) {
+ pinned++;
+ continue;
+ }
+ if (!xfs_buf_trylock(bp))
+ continue;
+ } else {
+ xfs_buf_lock(bp);
+ }
- current->flags |= PF_MEMALLOC;
+ /*
+ * Someone else might have written the buffer synchronously
+ * in the meantime. In that case only the _XBF_DELWRI_Q flag
+ * got cleared, and we have to drop the reference and remove
+ * it from the list here.
+ */
+ if (!(bp->b_flags & _XBF_DELWRI_Q)) {
+ list_del_init(&bp->b_list);
+ xfs_buf_relse(bp);
+ continue;
+ }
- set_freezable();
+ list_move_tail(&bp->b_list, submit_list);
+ trace_xfs_buf_delwri_split(bp, _RET_IP_);
+ }
- do {
- long age = xfs_buf_age_centisecs * msecs_to_jiffies(10);
- long tout = xfs_buf_timer_centisecs * msecs_to_jiffies(10);
- struct list_head tmp;
- struct blk_plug plug;
+ list_sort(NULL, submit_list, xfs_buf_cmp);
- if (unlikely(freezing(current))) {
- set_bit(XBT_FORCE_SLEEP, &target->bt_flags);
- refrigerator();
- } else {
- clear_bit(XBT_FORCE_SLEEP, &target->bt_flags);
- }
+ blk_start_plug(&plug);
+ list_for_each_entry_safe(bp, n, submit_list, b_list) {
+ bp->b_flags &= ~_XBF_DELWRI_Q;
+ bp->b_flags |= XBF_WRITE;
- /* sleep for a long time if there is nothing to do. */
- if (list_empty(&target->bt_delwri_queue))
- tout = MAX_SCHEDULE_TIMEOUT;
- schedule_timeout_interruptible(tout);
-
- xfs_buf_delwri_split(target, &tmp, age);
- list_sort(NULL, &tmp, xfs_buf_cmp);
-
- blk_start_plug(&plug);
- while (!list_empty(&tmp)) {
- struct xfs_buf *bp;
- bp = list_first_entry(&tmp, struct xfs_buf, b_list);
+ if (!wait) {
+ bp->b_flags |= XBF_ASYNC;
list_del_init(&bp->b_list);
- xfs_bdstrat_cb(bp);
}
- blk_finish_plug(&plug);
- } while (!kthread_should_stop());
+ xfs_bdstrat_cb(bp);
+ }
+ blk_finish_plug(&plug);
- return 0;
+ return pinned;
}
/*
- * Go through all incore buffers, and release buffers if they belong to
- * the given device. This is used in filesystem error handling to
- * preserve the consistency of its metadata.
+ * Write out buffer list asynchronously.
+ *
+ * This will take the buffer list, write all non-locked and non-pinned buffers
+ * out and not wait for I/O completion on any of the buffers. This interface
+ * is only safely useable for callers that can track I/O completion by higher
+ * level means, e.g. AIL pushing.
*/
int
-xfs_flush_buftarg(
- xfs_buftarg_t *target,
- int wait)
-{
- xfs_buf_t *bp;
- int pincount = 0;
- LIST_HEAD(tmp_list);
- LIST_HEAD(wait_list);
- struct blk_plug plug;
+xfs_buf_delwri_submit_nowait(
+ struct list_head *list)
+{
+ LIST_HEAD (submit_list);
+ return __xfs_buf_delwri_submit(&submit_list, list, false);
+}
- flush_workqueue(xfslogd_workqueue);
+/*
+ * Write out buffer list synchronously.
+ *
+ * This will take the buffer list, write all buffers out and wait for I/O
+ * completion on all of the buffers.
+ */
+int
+xfs_buf_delwri_submit(
+ struct list_head *list)
+{
+ LIST_HEAD (submit_list);
+ int error = 0, error2;
+ struct xfs_buf *bp;
- set_bit(XBT_FORCE_FLUSH, &target->bt_flags);
- pincount = xfs_buf_delwri_split(target, &tmp_list, 0);
+ __xfs_buf_delwri_submit(&submit_list, list, true);
- /*
- * Dropped the delayed write list lock, now walk the temporary list.
- * All I/O is issued async and then if we need to wait for completion
- * we do that after issuing all the IO.
- */
- list_sort(NULL, &tmp_list, xfs_buf_cmp);
+ /* Wait for IO to complete. */
+ while (!list_empty(&submit_list)) {
+ bp = list_first_entry(&submit_list, struct xfs_buf, b_list);
- blk_start_plug(&plug);
- while (!list_empty(&tmp_list)) {
- bp = list_first_entry(&tmp_list, struct xfs_buf, b_list);
- ASSERT(target == bp->b_target);
list_del_init(&bp->b_list);
- if (wait) {
- bp->b_flags &= ~XBF_ASYNC;
- list_add(&bp->b_list, &wait_list);
- }
- xfs_bdstrat_cb(bp);
- }
- blk_finish_plug(&plug);
-
- if (wait) {
- /* Wait for IO to complete. */
- while (!list_empty(&wait_list)) {
- bp = list_first_entry(&wait_list, struct xfs_buf, b_list);
-
- list_del_init(&bp->b_list);
- xfs_buf_iowait(bp);
- xfs_buf_relse(bp);
- }
+ error2 = xfs_buf_iowait(bp);
+ xfs_buf_relse(bp);
+ if (!error)
+ error = error2;
}
- return pincount;
+ return error;
}
int __init
Index: xfs/fs/xfs/xfs_buf.h
===================================================================
--- xfs.orig/fs/xfs/xfs_buf.h 2011-10-27 22:39:31.778172132 +0200
+++ xfs/fs/xfs/xfs_buf.h 2011-10-27 22:40:16.210189457 +0200
@@ -50,8 +50,7 @@ typedef enum {
#define XBF_MAPPED (1 << 3) /* buffer mapped (b_addr valid) */
#define XBF_ASYNC (1 << 4) /* initiator will not wait for completion */
#define XBF_DONE (1 << 5) /* all pages in the buffer uptodate */
-#define XBF_DELWRI (1 << 6) /* buffer has dirty pages */
-#define XBF_STALE (1 << 7) /* buffer has been staled, do not find it */
+#define XBF_STALE (1 << 6) /* buffer has been staled, do not find it */
/* I/O hints for the BIO layer */
#define XBF_SYNCIO (1 << 10)/* treat this buffer as synchronous I/O */
@@ -66,7 +65,7 @@ typedef enum {
/* flags used only internally */
#define _XBF_PAGES (1 << 20)/* backed by refcounted pages */
#define _XBF_KMEM (1 << 21)/* backed by heap memory */
-#define _XBF_DELWRI_Q (1 << 22)/* buffer on delwri queue */
+#define _XBF_DELWRI_Q (1 << 22)/* buffer on a delwri queue */
typedef unsigned int xfs_buf_flags_t;
@@ -77,7 +76,6 @@ typedef unsigned int xfs_buf_flags_t;
{ XBF_MAPPED, "MAPPED" }, \
{ XBF_ASYNC, "ASYNC" }, \
{ XBF_DONE, "DONE" }, \
- { XBF_DELWRI, "DELWRI" }, \
{ XBF_STALE, "STALE" }, \
{ XBF_SYNCIO, "SYNCIO" }, \
{ XBF_FUA, "FUA" }, \
@@ -89,11 +87,6 @@ typedef unsigned int xfs_buf_flags_t;
{ _XBF_KMEM, "KMEM" }, \
{ _XBF_DELWRI_Q, "DELWRI_Q" }
-typedef enum {
- XBT_FORCE_SLEEP = 0,
- XBT_FORCE_FLUSH = 1,
-} xfs_buftarg_flags_t;
-
typedef struct xfs_buftarg {
dev_t bt_dev;
struct block_device *bt_bdev;
@@ -103,12 +96,6 @@ typedef struct xfs_buftarg {
unsigned int bt_sshift;
size_t bt_smask;
- /* per device delwri queue */
- struct task_struct *bt_task;
- struct list_head bt_delwri_queue;
- spinlock_t bt_delwri_lock;
- unsigned long bt_flags;
-
/* LRU control structures */
struct shrinker bt_shrinker;
struct list_head bt_lru;
@@ -152,7 +139,6 @@ typedef struct xfs_buf {
struct xfs_trans *b_transp;
struct page **b_pages; /* array of page pointers */
struct page *b_page_array[XB_PAGES]; /* inline pages */
- unsigned long b_queuetime; /* time buffer was queued */
atomic_t b_pin_count; /* pin count */
atomic_t b_io_remaining; /* #outstanding I/O requests */
unsigned int b_page_count; /* size of page array */
@@ -222,24 +208,22 @@ static inline int xfs_buf_geterror(xfs_b
extern xfs_caddr_t xfs_buf_offset(xfs_buf_t *, size_t);
/* Delayed Write Buffer Routines */
-extern void xfs_buf_delwri_queue(struct xfs_buf *);
-extern void xfs_buf_delwri_dequeue(struct xfs_buf *);
-extern void xfs_buf_delwri_promote(struct xfs_buf *);
+extern bool xfs_buf_delwri_queue(struct xfs_buf *, struct list_head *);
+extern int xfs_buf_delwri_submit(struct list_head *);
+extern int xfs_buf_delwri_submit_nowait(struct list_head *);
/* Buffer Daemon Setup Routines */
extern int xfs_buf_init(void);
extern void xfs_buf_terminate(void);
#define XFS_BUF_ZEROFLAGS(bp) \
- ((bp)->b_flags &= ~(XBF_READ|XBF_WRITE|XBF_ASYNC|XBF_DELWRI| \
+ ((bp)->b_flags &= ~(XBF_READ|XBF_WRITE|XBF_ASYNC| \
XBF_SYNCIO|XBF_FUA|XBF_FLUSH))
void xfs_buf_stale(struct xfs_buf *bp);
#define XFS_BUF_UNSTALE(bp) ((bp)->b_flags &= ~XBF_STALE)
#define XFS_BUF_ISSTALE(bp) ((bp)->b_flags & XBF_STALE)
-#define XFS_BUF_ISDELAYWRITE(bp) ((bp)->b_flags & XBF_DELWRI)
-
#define XFS_BUF_DONE(bp) ((bp)->b_flags |= XBF_DONE)
#define XFS_BUF_UNDONE(bp) ((bp)->b_flags &= ~XBF_DONE)
#define XFS_BUF_ISDONE(bp) ((bp)->b_flags & XBF_DONE)
@@ -289,7 +273,6 @@ extern xfs_buftarg_t *xfs_alloc_buftarg(
extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *);
extern void xfs_wait_buftarg(xfs_buftarg_t *);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
-extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
#define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev)
#define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev)
Index: xfs/fs/xfs/xfs_buf_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_buf_item.c 2011-10-27 22:40:15.630172342 +0200
+++ xfs/fs/xfs/xfs_buf_item.c 2011-10-27 22:40:16.210189457 +0200
@@ -418,7 +418,6 @@ xfs_buf_item_unpin(
if (freed && stale) {
ASSERT(bip->bli_flags & XFS_BLI_STALE);
ASSERT(xfs_buf_islocked(bp));
- ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
ASSERT(XFS_BUF_ISSTALE(bp));
ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
@@ -470,33 +469,33 @@ xfs_buf_item_unpin(
}
/*
- * This is called to attempt to lock the buffer associated with this
- * buf log item. Don't sleep on the buffer lock. If we can't get
- * the lock right away, return 0. If we can get the lock, take a
- * reference to the buffer. If this is a delayed write buffer that
- * needs AIL help to be written back, invoke the pushbuf routine
- * rather than the normal success path.
+ * This is called to attempt to flush the buffer associated with this log item.
+ *
+ * We try to do the whole thing non-blocking, and tell the caller to try again
+ * later if the item is pinned or locked.
*/
STATIC uint
-xfs_buf_item_trylock(
- struct xfs_log_item *lip)
+xfs_buf_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
struct xfs_buf_log_item *bip = BUF_ITEM(lip);
struct xfs_buf *bp = bip->bli_buf;
+ uint rval = XFS_ITEM_SUCCESS;
if (xfs_buf_ispinned(bp))
return XFS_ITEM_PINNED;
if (!xfs_buf_trylock(bp))
return XFS_ITEM_LOCKED;
- /* take a reference to the buffer. */
- xfs_buf_hold(bp);
-
ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
- trace_xfs_buf_item_trylock(bip);
- if (XFS_BUF_ISDELAYWRITE(bp))
- return XFS_ITEM_PUSHBUF;
- return XFS_ITEM_SUCCESS;
+
+ trace_xfs_buf_item_push(bip);
+
+ if (!xfs_buf_delwri_queue(bp, buffer_list))
+ rval = XFS_ITEM_FLUSHING;
+ xfs_buf_unlock(bp);
+ return rval;
}
/*
@@ -609,48 +608,6 @@ xfs_buf_item_committed(
return lsn;
}
-/*
- * The buffer is locked, but is not a delayed write buffer.
- */
-STATIC void
-xfs_buf_item_push(
- struct xfs_log_item *lip)
-{
- struct xfs_buf_log_item *bip = BUF_ITEM(lip);
- struct xfs_buf *bp = bip->bli_buf;
-
- ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
- ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
-
- trace_xfs_buf_item_push(bip);
-
- xfs_buf_delwri_queue(bp);
- xfs_buf_relse(bp);
-}
-
-/*
- * The buffer is locked and is a delayed write buffer. Promote the buffer
- * in the delayed write queue as the caller knows that they must invoke
- * the xfsbufd to get this buffer written. We have to unlock the buffer
- * to allow the xfsbufd to write it, too.
- */
-STATIC bool
-xfs_buf_item_pushbuf(
- struct xfs_log_item *lip)
-{
- struct xfs_buf_log_item *bip = BUF_ITEM(lip);
- struct xfs_buf *bp = bip->bli_buf;
-
- ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
- ASSERT(XFS_BUF_ISDELAYWRITE(bp));
-
- trace_xfs_buf_item_pushbuf(bip);
-
- xfs_buf_delwri_promote(bp);
- xfs_buf_relse(bp);
- return true;
-}
-
STATIC void
xfs_buf_item_committing(
struct xfs_log_item *lip,
@@ -666,11 +623,9 @@ static const struct xfs_item_ops xfs_buf
.iop_format = xfs_buf_item_format,
.iop_pin = xfs_buf_item_pin,
.iop_unpin = xfs_buf_item_unpin,
- .iop_trylock = xfs_buf_item_trylock,
.iop_unlock = xfs_buf_item_unlock,
.iop_committed = xfs_buf_item_committed,
.iop_push = xfs_buf_item_push,
- .iop_pushbuf = xfs_buf_item_pushbuf,
.iop_committing = xfs_buf_item_committing
};
@@ -992,17 +947,24 @@ xfs_buf_iodone_callbacks(
* During sync or umount we'll write all pending buffers again
* synchronous, which will catch these errors if they keep hanging
* around.
+ *
+ * XXX(hch): that won't nessecarily help us to pick up the errors
+ * with the current code..
*/
if (XFS_BUF_ISASYNC(bp)) {
+ ASSERT(bp->b_iodone != NULL);
+
+ trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
+
xfs_buf_ioerror(bp, 0); /* errno of 0 unsets the flag */
if (!XFS_BUF_ISSTALE(bp)) {
- xfs_buf_delwri_queue(bp);
- XFS_BUF_DONE(bp);
+ bp->b_flags |= XBF_WRITE | XBF_ASYNC | XBF_DONE;
+ xfs_bdstrat_cb(bp);
+ } else {
+ xfs_buf_relse(bp);
}
- ASSERT(bp->b_iodone != NULL);
- trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
- xfs_buf_relse(bp);
+
return;
}
Index: xfs/fs/xfs/xfs_dquot_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot_item.c 2011-10-27 22:40:14.813173372 +0200
+++ xfs/fs/xfs/xfs_dquot_item.c 2011-10-27 22:40:16.218216695 +0200
@@ -109,44 +109,6 @@ xfs_qm_dquot_logitem_unpin(
wake_up(&dqp->q_pinwait);
}
-/*
- * Given the logitem, this writes the corresponding dquot entry to disk
- * asynchronously. This is called with the dquot entry securely locked;
- * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot
- * at the end.
- */
-STATIC void
-xfs_qm_dquot_logitem_push(
- struct xfs_log_item *lip)
-{
- struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
- struct xfs_buf *bp = NULL;
- int error;
-
- ASSERT(XFS_DQ_IS_LOCKED(dqp));
- ASSERT(!completion_done(&dqp->q_flush));
- ASSERT(atomic_read(&dqp->q_pincount) == 0);
-
- /*
- * Since we were able to lock the dquot's flush lock and
- * we found it on the AIL, the dquot must be dirty. This
- * is because the dquot is removed from the AIL while still
- * holding the flush lock in xfs_dqflush_done(). Thus, if
- * we found it in the AIL and were able to obtain the flush
- * lock without sleeping, then there must not have been
- * anyone in the process of flushing the dquot.
- */
- error = xfs_qm_dqflush(dqp, &bp);
- if (error) {
- xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p",
- __func__, error, dqp);
- } else if (bp) {
- xfs_buf_delwri_queue(bp);
- xfs_buf_relse(bp);
- }
- xfs_dqunlock(dqp);
-}
-
STATIC xfs_lsn_t
xfs_qm_dquot_logitem_committed(
struct xfs_log_item *lip,
@@ -179,66 +141,23 @@ xfs_qm_dqunpin_wait(
}
/*
- * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that
- * the dquot is locked by us, but the flush lock isn't. So, here we are
- * going to see if the relevant dquot buffer is incore, waiting on DELWRI.
- * If so, we want to push it out to help us take this item off the AIL as soon
- * as possible.
+ * This is called to attempt to flush the dquot associated with this log item.
+ * We try to do the whole thing non-blocking, and tell the caller to try again
+ * later if the item is pinned or locked.
*
- * We must not be holding the AIL lock at this point. Calling incore() to
- * search the buffer cache can be a time consuming thing, and AIL lock is a
- * spinlock.
- */
-STATIC bool
-xfs_qm_dquot_logitem_pushbuf(
- struct xfs_log_item *lip)
-{
- struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip);
- struct xfs_dquot *dqp = qlip->qli_dquot;
- struct xfs_buf *bp;
- bool ret = true;
-
- ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
- /*
- * If flushlock isn't locked anymore, chances are that the
- * inode flush completed and the inode was taken off the AIL.
- * So, just get out.
- */
- if (completion_done(&dqp->q_flush) ||
- !(lip->li_flags & XFS_LI_IN_AIL)) {
- xfs_dqunlock(dqp);
- return true;
- }
-
- bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno,
- dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
- xfs_dqunlock(dqp);
- if (!bp)
- return true;
- if (XFS_BUF_ISDELAYWRITE(bp))
- xfs_buf_delwri_promote(bp);
- if (xfs_buf_ispinned(bp))
- ret = false;
- xfs_buf_relse(bp);
- return ret;
-}
-
-/*
- * This is called to attempt to lock the dquot associated with this
- * dquot log item. Don't sleep on the dquot lock or the flush lock.
- * If the flush lock is already held, indicating that the dquot has
- * been or is in the process of being flushed, then see if we can
- * find the dquot's buffer in the buffer cache without sleeping. If
- * we can and it is marked delayed write, then we want to send it out.
- * We delay doing so until the push routine, though, to avoid sleeping
- * in any device strategy routines.
+ * We drop the AIL lock across the call to xfs_qm_dqflush as it might block
+ * when reading the dquot from disk, and generally might take far too many
+ * other locks to keep a sane locking hierachy.
*/
STATIC uint
-xfs_qm_dquot_logitem_trylock(
- struct xfs_log_item *lip)
+xfs_qm_dquot_logitem_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
+ struct xfs_buf *bp = NULL;
+ uint rval = XFS_ITEM_SUCCESS;
+ int error;
if (atomic_read(&dqp->q_pincount) > 0)
return XFS_ITEM_PINNED;
@@ -251,20 +170,41 @@ xfs_qm_dquot_logitem_trylock(
* taking the quota lock.
*/
if (atomic_read(&dqp->q_pincount) > 0) {
- xfs_dqunlock(dqp);
- return XFS_ITEM_PINNED;
+ rval = XFS_ITEM_PINNED;
+ goto out_unlock;
}
+ /*
+ * Someone else is already flushing the dquot. Nothing we can do
+ * here but wait for the flush to finish and remove the item from
+ * the AIL.
+ */
if (!xfs_dqflock_nowait(dqp)) {
- /*
- * dquot has already been flushed to the backing buffer,
- * leave it locked, pushbuf routine will unlock it.
- */
- return XFS_ITEM_PUSHBUF;
+ rval = XFS_ITEM_FLUSHING;
+ goto out_unlock;
}
- ASSERT(lip->li_flags & XFS_LI_IN_AIL);
- return XFS_ITEM_SUCCESS;
+ /*
+ * Given that xfs_qm_dqflush might block on memory allocation
+ * and/or reading the dquot from disk drop the AIL lock before
+ * calling it.
+ */
+ spin_unlock(&lip->li_ailp->xa_lock);
+
+ error = xfs_qm_dqflush(dqp, &bp);
+ if (error) {
+ xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p",
+ __func__, error, dqp);
+ } else if (bp) {
+ if (!xfs_buf_delwri_queue(bp, buffer_list))
+ rval = XFS_ITEM_FLUSHING;
+ xfs_buf_relse(bp);
+ }
+
+ spin_lock(&lip->li_ailp->xa_lock);
+out_unlock:
+ xfs_dqunlock(dqp);
+ return rval;
}
/*
@@ -315,11 +255,9 @@ static const struct xfs_item_ops xfs_dqu
.iop_format = xfs_qm_dquot_logitem_format,
.iop_pin = xfs_qm_dquot_logitem_pin,
.iop_unpin = xfs_qm_dquot_logitem_unpin,
- .iop_trylock = xfs_qm_dquot_logitem_trylock,
.iop_unlock = xfs_qm_dquot_logitem_unlock,
.iop_committed = xfs_qm_dquot_logitem_committed,
.iop_push = xfs_qm_dquot_logitem_push,
- .iop_pushbuf = xfs_qm_dquot_logitem_pushbuf,
.iop_committing = xfs_qm_dquot_logitem_committing
};
@@ -414,11 +352,13 @@ xfs_qm_qoff_logitem_unpin(
}
/*
- * Quotaoff items have no locking, so just return success.
+ * There isn't much you can do to push on an quotaoff item. It is simply
+ * stuck waiting for the log to be flushed to disk.
*/
STATIC uint
-xfs_qm_qoff_logitem_trylock(
- struct xfs_log_item *lip)
+xfs_qm_qoff_logitem_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
return XFS_ITEM_LOCKED;
}
@@ -445,17 +385,6 @@ xfs_qm_qoff_logitem_committed(
return lsn;
}
-/*
- * There isn't much you can do to push on an quotaoff item. It is simply
- * stuck waiting for the log to be flushed to disk.
- */
-STATIC void
-xfs_qm_qoff_logitem_push(
- struct xfs_log_item *lip)
-{
-}
-
-
STATIC xfs_lsn_t
xfs_qm_qoffend_logitem_committed(
struct xfs_log_item *lip,
@@ -503,7 +432,6 @@ static const struct xfs_item_ops xfs_qm_
.iop_format = xfs_qm_qoff_logitem_format,
.iop_pin = xfs_qm_qoff_logitem_pin,
.iop_unpin = xfs_qm_qoff_logitem_unpin,
- .iop_trylock = xfs_qm_qoff_logitem_trylock,
.iop_unlock = xfs_qm_qoff_logitem_unlock,
.iop_committed = xfs_qm_qoffend_logitem_committed,
.iop_push = xfs_qm_qoff_logitem_push,
@@ -518,7 +446,6 @@ static const struct xfs_item_ops xfs_qm_
.iop_format = xfs_qm_qoff_logitem_format,
.iop_pin = xfs_qm_qoff_logitem_pin,
.iop_unpin = xfs_qm_qoff_logitem_unpin,
- .iop_trylock = xfs_qm_qoff_logitem_trylock,
.iop_unlock = xfs_qm_qoff_logitem_unlock,
.iop_committed = xfs_qm_qoff_logitem_committed,
.iop_push = xfs_qm_qoff_logitem_push,
Index: xfs/fs/xfs/xfs_extfree_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_extfree_item.c 2011-10-27 22:39:42.528674212 +0200
+++ xfs/fs/xfs/xfs_extfree_item.c 2011-10-27 22:40:16.218216695 +0200
@@ -154,8 +154,9 @@ xfs_efi_item_unpin(
* This should help in getting the EFI out of the AIL.
*/
STATIC uint
-xfs_efi_item_trylock(
- struct xfs_log_item *lip)
+xfs_efi_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
return XFS_ITEM_PINNED;
}
@@ -190,17 +191,6 @@ xfs_efi_item_committed(
}
/*
- * There isn't much you can do to push on an efi item. It is simply
- * stuck waiting for all of its corresponding efd items to be
- * committed to disk.
- */
-STATIC void
-xfs_efi_item_push(
- struct xfs_log_item *lip)
-{
-}
-
-/*
* The EFI dependency tracking op doesn't do squat. It can't because
* it doesn't know where the free extent is coming from. The dependency
* tracking has to be handled by the "enclosing" metadata object. For
@@ -222,7 +212,6 @@ static const struct xfs_item_ops xfs_efi
.iop_format = xfs_efi_item_format,
.iop_pin = xfs_efi_item_pin,
.iop_unpin = xfs_efi_item_unpin,
- .iop_trylock = xfs_efi_item_trylock,
.iop_unlock = xfs_efi_item_unlock,
.iop_committed = xfs_efi_item_committed,
.iop_push = xfs_efi_item_push,
@@ -404,11 +393,13 @@ xfs_efd_item_unpin(
}
/*
- * Efd items have no locking, so just return success.
+ * There isn't much you can do to push on an efd item. It is simply
+ * stuck waiting for the log to be flushed to disk.
*/
STATIC uint
-xfs_efd_item_trylock(
- struct xfs_log_item *lip)
+xfs_efd_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
return XFS_ITEM_LOCKED;
}
@@ -451,16 +442,6 @@ xfs_efd_item_committed(
}
/*
- * There isn't much you can do to push on an efd item. It is simply
- * stuck waiting for the log to be flushed to disk.
- */
-STATIC void
-xfs_efd_item_push(
- struct xfs_log_item *lip)
-{
-}
-
-/*
* The EFD dependency tracking op doesn't do squat. It can't because
* it doesn't know where the free extent is coming from. The dependency
* tracking has to be handled by the "enclosing" metadata object. For
@@ -482,7 +463,6 @@ static const struct xfs_item_ops xfs_efd
.iop_format = xfs_efd_item_format,
.iop_pin = xfs_efd_item_pin,
.iop_unpin = xfs_efd_item_unpin,
- .iop_trylock = xfs_efd_item_trylock,
.iop_unlock = xfs_efd_item_unlock,
.iop_committed = xfs_efd_item_committed,
.iop_push = xfs_efd_item_push,
Index: xfs/fs/xfs/xfs_inode_item.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode_item.c 2011-10-27 22:40:13.681172022 +0200
+++ xfs/fs/xfs/xfs_inode_item.c 2011-10-27 22:40:16.218216695 +0200
@@ -527,24 +527,25 @@ xfs_inode_item_unpin(
}
/*
- * This is called to attempt to lock the inode associated with this
- * inode log item, in preparation for the push routine which does the actual
- * iflush. Don't sleep on the inode lock or the flush lock.
+ * This is called to attempt to flush the inode associated with this log item.
*
- * If the flush lock is already held, indicating that the inode has
- * been or is in the process of being flushed, then (ideally) we'd like to
- * see if the inode's buffer is still incore, and if so give it a nudge.
- * We delay doing so until the pushbuf routine, though, to avoid holding
- * the AIL lock across a call to the blackhole which is the buffer cache.
- * Also we don't want to sleep in any device strategy routines, which can happen
- * if we do the subsequent bawrite in here.
+ * We try to do the whole thing non-blocking, and tell the caller to try again
+ * later if the item is pinned or locked.
+ *
+ * We drop the AIL lock across the call to xfs_iflush as it might block when
+ * reading the inode cluster from disk, and generally might take far too many
+ * other locks to keep a sane locking hierachy.
*/
STATIC uint
-xfs_inode_item_trylock(
- struct xfs_log_item *lip)
+xfs_inode_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
struct xfs_inode *ip = iip->ili_inode;
+ struct xfs_buf *bp = NULL;
+ uint rval = XFS_ITEM_SUCCESS;
+ int error;
if (xfs_ipincount(ip) > 0)
return XFS_ITEM_PINNED;
@@ -557,20 +558,23 @@ xfs_inode_item_trylock(
* taking the ilock.
*/
if (xfs_ipincount(ip) > 0) {
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- return XFS_ITEM_PINNED;
+ rval = XFS_ITEM_PINNED;
+ goto out_unlock;
}
+ /*
+ * Someone else is already flushing the inode. Nothing we can do
+ * here but wait for the flush to finish and remove the item from
+ * the AIL.
+ */
if (!xfs_iflock_nowait(ip)) {
- /*
- * inode has already been flushed to the backing buffer,
- * leave it locked in shared mode, pushbuf routine will
- * unlock it.
- */
- return XFS_ITEM_PUSHBUF;
+ rval = XFS_ITEM_FLUSHING;
+ goto out_unlock;
}
- /* Stale items should force out the iclog */
+ /*
+ * Stale inode items should force out the iclog.
+ */
if (ip->i_flags & XFS_ISTALE) {
xfs_ifunlock(ip);
/*
@@ -585,10 +589,27 @@ xfs_inode_item_trylock(
if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
ASSERT(iip->ili_format.ilf_fields != 0);
ASSERT(iip->ili_logged == 0);
- ASSERT(lip->li_flags & XFS_LI_IN_AIL);
}
#endif
- return XFS_ITEM_SUCCESS;
+
+ /*
+ * Given that xfs_iflush might block on memory allocation
+ * and/or reading the dquot from disk drop the AIL lock before
+ * calling it.
+ */
+ spin_unlock(&lip->li_ailp->xa_lock);
+
+ error = xfs_iflush(ip, &bp);
+ if (!error) {
+ if (!xfs_buf_delwri_queue(bp, buffer_list))
+ rval = XFS_ITEM_FLUSHING;
+ xfs_buf_relse(bp);
+ }
+
+ spin_lock(&lip->li_ailp->xa_lock);
+out_unlock:
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ return rval;
}
/*
@@ -673,93 +694,6 @@ xfs_inode_item_committed(
}
/*
- * This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK
- * failed to get the inode flush lock but did get the inode locked SHARED.
- * Here we're trying to see if the inode buffer is incore, and if so whether it's
- * marked delayed write. If that's the case, we'll promote it and that will
- * allow the caller to write the buffer by triggering the xfsbufd to run.
- */
-STATIC bool
-xfs_inode_item_pushbuf(
- struct xfs_log_item *lip)
-{
- struct xfs_inode_log_item *iip = INODE_ITEM(lip);
- struct xfs_inode *ip = iip->ili_inode;
- struct xfs_buf *bp;
- bool ret = true;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
-
- /*
- * If a flush is not in progress anymore, chances are that the
- * inode was taken off the AIL. So, just get out.
- */
- if (!xfs_isiflocked(ip) ||
- !(lip->li_flags & XFS_LI_IN_AIL)) {
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- return true;
- }
-
- bp = xfs_incore(ip->i_mount->m_ddev_targp, iip->ili_format.ilf_blkno,
- iip->ili_format.ilf_len, XBF_TRYLOCK);
-
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- if (!bp)
- return true;
- if (XFS_BUF_ISDELAYWRITE(bp))
- xfs_buf_delwri_promote(bp);
- if (xfs_buf_ispinned(bp))
- ret = false;
- xfs_buf_relse(bp);
- return ret;
-}
-
-/*
- * This is called to asynchronously write the inode associated with this
- * inode log item out to disk. The inode will already have been locked by
- * a successful call to xfs_inode_item_trylock().
- */
-STATIC void
-xfs_inode_item_push(
- struct xfs_log_item *lip)
-{
- struct xfs_inode_log_item *iip = INODE_ITEM(lip);
- struct xfs_inode *ip = iip->ili_inode;
- struct xfs_buf *bp = NULL;
- int error;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
- ASSERT(xfs_isiflocked(ip));
-
- /*
- * Since we were able to lock the inode's flush lock and
- * we found it on the AIL, the inode must be dirty. This
- * is because the inode is removed from the AIL while still
- * holding the flush lock in xfs_iflush_done(). Thus, if
- * we found it in the AIL and were able to obtain the flush
- * lock without sleeping, then there must not have been
- * anyone in the process of flushing the inode.
- */
- ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) ||
- iip->ili_format.ilf_fields != 0);
-
- /*
- * Push the inode to it's backing buffer. This will not remove the
- * inode from the AIL - a further push will be required to trigger a
- * buffer push. However, this allows all the dirty inodes to be pushed
- * to the buffer before it is pushed to disk. The buffer IO completion
- * will pull the inode from the AIL, mark it clean and unlock the flush
- * lock.
- */
- error = xfs_iflush(ip, &bp);
- if (!error) {
- xfs_buf_delwri_queue(bp);
- xfs_buf_relse(bp);
- }
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
-}
-
-/*
* XXX rcc - this one really has to do something. Probably needs
* to stamp in a new field in the incore inode.
*/
@@ -779,11 +713,9 @@ static const struct xfs_item_ops xfs_ino
.iop_format = xfs_inode_item_format,
.iop_pin = xfs_inode_item_pin,
.iop_unpin = xfs_inode_item_unpin,
- .iop_trylock = xfs_inode_item_trylock,
.iop_unlock = xfs_inode_item_unlock,
.iop_committed = xfs_inode_item_committed,
.iop_push = xfs_inode_item_push,
- .iop_pushbuf = xfs_inode_item_pushbuf,
.iop_committing = xfs_inode_item_committing
};
Index: xfs/fs/xfs/xfs_trace.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trace.h 2011-10-27 22:40:08.610173785 +0200
+++ xfs/fs/xfs/xfs_trace.h 2011-10-27 22:40:16.222187321 +0200
@@ -328,7 +328,7 @@ DEFINE_BUF_EVENT(xfs_buf_unlock);
DEFINE_BUF_EVENT(xfs_buf_iowait);
DEFINE_BUF_EVENT(xfs_buf_iowait_done);
DEFINE_BUF_EVENT(xfs_buf_delwri_queue);
-DEFINE_BUF_EVENT(xfs_buf_delwri_dequeue);
+DEFINE_BUF_EVENT(xfs_buf_delwri_queued);
DEFINE_BUF_EVENT(xfs_buf_delwri_split);
DEFINE_BUF_EVENT(xfs_buf_get_uncached);
DEFINE_BUF_EVENT(xfs_bdstrat_shut);
@@ -486,12 +486,10 @@ DEFINE_BUF_ITEM_EVENT(xfs_buf_item_forma
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_pin);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unpin);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unpin_stale);
-DEFINE_BUF_ITEM_EVENT(xfs_buf_item_trylock);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock_stale);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_committed);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_push);
-DEFINE_BUF_ITEM_EVENT(xfs_buf_item_pushbuf);
DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf);
DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf_recur);
DEFINE_BUF_ITEM_EVENT(xfs_trans_getsb);
@@ -880,10 +878,9 @@ DEFINE_EVENT(xfs_log_item_class, name, \
TP_PROTO(struct xfs_log_item *lip), \
TP_ARGS(lip))
DEFINE_LOG_ITEM_EVENT(xfs_ail_push);
-DEFINE_LOG_ITEM_EVENT(xfs_ail_pushbuf);
-DEFINE_LOG_ITEM_EVENT(xfs_ail_pushbuf_pinned);
DEFINE_LOG_ITEM_EVENT(xfs_ail_pinned);
DEFINE_LOG_ITEM_EVENT(xfs_ail_locked);
+DEFINE_LOG_ITEM_EVENT(xfs_ail_flushing);
DECLARE_EVENT_CLASS(xfs_file_class,
Index: xfs/fs/xfs/xfs_trans.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trans.h 2011-10-27 22:39:42.536670491 +0200
+++ xfs/fs/xfs/xfs_trans.h 2011-10-27 22:40:16.230218778 +0200
@@ -346,11 +346,9 @@ struct xfs_item_ops {
void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
void (*iop_pin)(xfs_log_item_t *);
void (*iop_unpin)(xfs_log_item_t *, int remove);
- uint (*iop_trylock)(xfs_log_item_t *);
+ uint (*iop_push)(struct xfs_log_item *, struct list_head *);
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
- void (*iop_push)(xfs_log_item_t *);
- bool (*iop_pushbuf)(xfs_log_item_t *);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
};
@@ -358,20 +356,18 @@ struct xfs_item_ops {
#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp)
#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip)
#define IOP_UNPIN(ip, remove) (*(ip)->li_ops->iop_unpin)(ip, remove)
-#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip)
+#define IOP_PUSH(ip, list) (*(ip)->li_ops->iop_push)(ip, list)
#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)
#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
-#define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip)
-#define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip)
#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn)
/*
- * Return values for the IOP_TRYLOCK() routines.
+ * Return values for the IOP_PUSH() routines.
*/
-#define XFS_ITEM_SUCCESS 0
-#define XFS_ITEM_PINNED 1
-#define XFS_ITEM_LOCKED 2
-#define XFS_ITEM_PUSHBUF 3
+#define XFS_ITEM_SUCCESS 0
+#define XFS_ITEM_PINNED 1
+#define XFS_ITEM_LOCKED 2
+#define XFS_ITEM_FLUSHING 3
/*
* This is the type of function which can be given to xfs_trans_callback()
Index: xfs/fs/xfs/xfs_trans_ail.c
===================================================================
--- xfs.orig/fs/xfs/xfs_trans_ail.c 2011-10-27 22:40:12.489171652 +0200
+++ xfs/fs/xfs/xfs_trans_ail.c 2011-10-27 22:40:16.230218778 +0200
@@ -364,25 +364,24 @@ xfsaild_push(
xfs_log_item_t *lip;
xfs_lsn_t lsn;
xfs_lsn_t target;
- long tout = 10;
+ long tout;
int stuck = 0;
+ int flushing = 0;
int count = 0;
- int push_xfsbufd = 0;
/*
* If last time we ran we encountered pinned items, force the log first
* and wait for it before pushing again.
*/
- spin_lock(&ailp->xa_lock);
- if (ailp->xa_last_pushed_lsn == 0 && ailp->xa_log_flush &&
- !list_empty(&ailp->xa_ail)) {
+ if (ailp->xa_log_flush && ailp->xa_last_pushed_lsn == 0 &&
+ (!list_empty(&ailp->xa_buf_list) || xfs_ail_min_lsn(ailp))) {
ailp->xa_log_flush = 0;
- spin_unlock(&ailp->xa_lock);
+
XFS_STATS_INC(xs_push_ail_flush);
xfs_log_force(mp, XFS_LOG_SYNC);
- spin_lock(&ailp->xa_lock);
}
+ spin_lock(&ailp->xa_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn);
if (!lip) {
/*
@@ -418,42 +417,35 @@ xfsaild_push(
lsn = lip->li_lsn;
while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) {
int lock_result;
+
/*
- * If we can lock the item without sleeping, unlock the AIL
- * lock and flush the item. Then re-grab the AIL lock so we
- * can look for the next item on the AIL. List changes are
- * handled by the AIL lookup functions internally
- *
- * If we can't lock the item, either its holder will flush it
- * or it is already being flushed or it is being relogged. In
- * any of these case it is being taken care of and we can just
- * skip to the next item in the list.
+ * Try to push them item without blocking on locks. Note that
+ * IOP_PUSH may unlocked and reacquire the ail lock, but the
+ * AIL cursor routines can handle that just fine.
*/
- lock_result = IOP_TRYLOCK(lip);
- spin_unlock(&ailp->xa_lock);
+ lock_result = IOP_PUSH(lip, &ailp->xa_buf_list);
switch (lock_result) {
case XFS_ITEM_SUCCESS:
XFS_STATS_INC(xs_push_ail_success);
trace_xfs_ail_push(lip);
- IOP_PUSH(lip);
ailp->xa_last_pushed_lsn = lsn;
break;
-
- case XFS_ITEM_PUSHBUF:
- XFS_STATS_INC(xs_push_ail_pushbuf);
- trace_xfs_ail_pushbuf(lip);
-
- if (!IOP_PUSHBUF(lip)) {
- trace_xfs_ail_pushbuf_pinned(lip);
- stuck++;
- ailp->xa_log_flush++;
- } else {
- ailp->xa_last_pushed_lsn = lsn;
- }
- push_xfsbufd = 1;
+ case XFS_ITEM_FLUSHING:
+ XFS_STATS_INC(xs_push_ail_flushing);
+ trace_xfs_ail_flushing(lip);
+
+ /*
+ * We do not want to break out of the loop early just
+ * because we have too many items that are already
+ * beeing flushed - this could happen for to easily
+ * e.g. because of inode flush clustering. But when
+ * we have an almost empty AIL that only contains
+ * locked buffers we must not stop pushing things.
+ */
+ flushing++;
+ ailp->xa_last_pushed_lsn = lsn;
break;
-
case XFS_ITEM_PINNED:
XFS_STATS_INC(xs_push_ail_pinned);
trace_xfs_ail_pinned(lip);
@@ -461,19 +453,17 @@ xfsaild_push(
stuck++;
ailp->xa_log_flush++;
break;
-
case XFS_ITEM_LOCKED:
XFS_STATS_INC(xs_push_ail_locked);
trace_xfs_ail_locked(lip);
+
stuck++;
break;
-
default:
ASSERT(0);
break;
}
- spin_lock(&ailp->xa_lock);
count++;
/*
@@ -499,42 +489,36 @@ xfsaild_push(
xfs_trans_ail_cursor_done(ailp, &cur);
spin_unlock(&ailp->xa_lock);
- if (push_xfsbufd) {
- /* we've got delayed write buffers to flush */
- wake_up_process(mp->m_ddev_targp->bt_task);
- }
+ if (xfs_buf_delwri_submit_nowait(&ailp->xa_buf_list))
+ ailp->xa_log_flush++;
- /* assume we have more work to do in a short while */
+ if (!count || XFS_LSN_CMP(lsn, target) >= 0) {
out_done:
- if (!count) {
- /* We're past our target or empty, so idle */
- ailp->xa_last_pushed_lsn = 0;
- ailp->xa_log_flush = 0;
-
- tout = 50;
- } else if (XFS_LSN_CMP(lsn, target) >= 0) {
/*
- * We reached the target so wait a bit longer for I/O to
- * complete and remove pushed items from the AIL before we
- * start the next scan from the start of the AIL.
+ * We reached the target or the AIL is empty, so wait a bit
+ * longer for I/O to complete and remove pushed items from the
+ * AIL before we start the next scan from the start of the AIL.
*/
tout = 50;
ailp->xa_last_pushed_lsn = 0;
- } else if ((stuck * 100) / count > 90) {
+ } else if (((stuck + flushing) * 100) / count > 90) {
/*
- * Either there is a lot of contention on the AIL or we
- * are stuck due to operations in progress. "Stuck" in this
- * case is defined as >90% of the items we tried to push
- * were stuck.
+ * Either there is a lot of contention on the AIL or we are
+ * stuck due to operations in progress. "Stuck" in this case
+ * is defined as >90% of the items we tried to push were stuck.
*
* Backoff a bit more to allow some I/O to complete before
- * restarting from the start of the AIL. This prevents us
- * from spinning on the same items, and if they are pinned will
- * all the restart to issue a log force to unpin the stuck
- * items.
+ * restarting from the start of the AIL. This prevents us from
+ * spinning on the same items, and if they are pinned will all
+ * the restart to issue a log force to unpin the stuck items.
*/
tout = 20;
ailp->xa_last_pushed_lsn = 0;
+ } else {
+ /*
+ * Assume we have more work to do in a short while.
+ */
+ tout = 10;
}
return tout;
@@ -547,6 +531,8 @@ xfsaild(
struct xfs_ail *ailp = data;
long tout = 0; /* milliseconds */
+ current->flags |= PF_MEMALLOC;
+
while (!kthread_should_stop()) {
if (tout && tout <= 20)
__set_current_state(TASK_KILLABLE);
@@ -866,6 +852,7 @@ xfs_trans_ail_init(
INIT_LIST_HEAD(&ailp->xa_ail);
INIT_LIST_HEAD(&ailp->xa_cursors);
spin_lock_init(&ailp->xa_lock);
+ INIT_LIST_HEAD(&ailp->xa_buf_list);
init_waitqueue_head(&ailp->xa_empty);
atomic_set(&ailp->xa_wait_empty, 0);
Index: xfs/fs/xfs/xfs_trans_buf.c
===================================================================
--- xfs.orig/fs/xfs/xfs_trans_buf.c 2011-10-27 22:40:15.630172342 +0200
+++ xfs/fs/xfs/xfs_trans_buf.c 2011-10-27 22:40:16.234188505 +0200
@@ -165,14 +165,6 @@ xfs_trans_get_buf(xfs_trans_t *tp,
XFS_BUF_DONE(bp);
}
- /*
- * If the buffer is stale then it was binval'ed
- * since last read. This doesn't matter since the
- * caller isn't allowed to use the data anyway.
- */
- else if (XFS_BUF_ISSTALE(bp))
- ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
-
ASSERT(bp->b_transp == tp);
bip = bp->b_fspriv;
ASSERT(bip != NULL);
@@ -418,19 +410,6 @@ xfs_trans_read_buf(
return 0;
shutdown_abort:
- /*
- * the theory here is that buffer is good but we're
- * bailing out because the filesystem is being forcibly
- * shut down. So we should leave the b_flags alone since
- * the buffer's not staled and just get out.
- */
-#if defined(DEBUG)
- if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp))
- xfs_notice(mp, "about to pop assert, bp == 0x%p", bp);
-#endif
- ASSERT((bp->b_flags & (XBF_STALE|XBF_DELWRI)) !=
- (XBF_STALE|XBF_DELWRI));
-
trace_xfs_trans_read_buf_shut(bp, _RET_IP_);
xfs_buf_relse(bp);
*bpp = NULL;
@@ -672,22 +651,33 @@ xfs_trans_log_buf(xfs_trans_t *tp,
/*
- * This called to invalidate a buffer that is being used within
- * a transaction. Typically this is because the blocks in the
- * buffer are being freed, so we need to prevent it from being
- * written out when we're done. Allowing it to be written again
- * might overwrite data in the free blocks if they are reallocated
- * to a file.
- *
- * We prevent the buffer from being written out by clearing the
- * B_DELWRI flag. We can't always
- * get rid of the buf log item at this point, though, because
- * the buffer may still be pinned by another transaction. If that
- * is the case, then we'll wait until the buffer is committed to
- * disk for the last time (we can tell by the ref count) and
- * free it in xfs_buf_item_unpin(). Until it is cleaned up we
- * will keep the buffer locked so that the buffer and buf log item
- * are not reused.
+ * Invalidate a buffer that is being used within a transaction.
+ *
+ * Typically this is because the blocks in the buffer are being freed, so we
+ * need to prevent it from being written out when we're done. Allowing it
+ * to be written again might overwrite data in the free blocks if they are
+ * reallocated to a file.
+ *
+ * We prevent the buffer from being written out by marking it stale. We can't
+ * get rid of the buf log item at this point because the buffer may still be
+ * pinned by another transaction. If that is the case, then we'll wait until
+ * the buffer is committed to disk for the last time (we can tell by the ref
+ * count) and free it in xfs_buf_item_unpin(). Until that happens we will
+ * keep the buffer locked so that the buffer and buf log item are not reused.
+ *
+ * We also set the XFS_BLF_CANCEL flag in the buf log format structure and log
+ * the buf item. This will be used at recovery time to determine that copies
+ * of the buffer in the log before this should not be replayed.
+ *
+ * We mark the item descriptor and the transaction dirty so that we'll hold
+ * the buffer until after the commit.
+ *
+ * Since we're invalidating the buffer, we also clear the state about which
+ * parts of the buffer have been logged. We also clear the flag indicating
+ * that this is an inode buffer since the data in the buffer will no longer
+ * be valid.
+ *
+ * We set the stale bit in the buffer as well since we're getting rid of it.
*/
void
xfs_trans_binval(
@@ -707,7 +697,6 @@ xfs_trans_binval(
* If the buffer is already invalidated, then
* just return.
*/
- ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
ASSERT(XFS_BUF_ISSTALE(bp));
ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY)));
ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_INODE_BUF));
@@ -717,27 +706,8 @@ xfs_trans_binval(
return;
}
- /*
- * Clear the dirty bit in the buffer and set the STALE flag
- * in the buf log item. The STALE flag will be used in
- * xfs_buf_item_unpin() to determine if it should clean up
- * when the last reference to the buf item is given up.
- * We set the XFS_BLF_CANCEL flag in the buf log format structure
- * and log the buf item. This will be used at recovery time
- * to determine that copies of the buffer in the log before
- * this should not be replayed.
- * We mark the item descriptor and the transaction dirty so
- * that we'll hold the buffer until after the commit.
- *
- * Since we're invalidating the buffer, we also clear the state
- * about which parts of the buffer have been logged. We also
- * clear the flag indicating that this is an inode buffer since
- * the data in the buffer will no longer be valid.
- *
- * We set the stale bit in the buffer as well since we're getting
- * rid of it.
- */
xfs_buf_stale(bp);
+
bip->bli_flags |= XFS_BLI_STALE;
bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY);
bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:14.813173372 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:16.238187917 +0200
@@ -387,7 +387,8 @@ xfs_qm_dqflush_all(
struct xfs_quotainfo *q = mp->m_quotainfo;
int recl;
struct xfs_dquot *dqp;
- int error;
+ int error = 0, error2;
+ LIST_HEAD (buffer_list);
if (!q)
return 0;
@@ -405,16 +406,8 @@ again:
/* XXX a sentinel would be better */
recl = q->qi_dqreclaims;
- if (!xfs_dqflock_nowait(dqp)) {
- /*
- * If we can't grab the flush lock then check
- * to see if the dquot has been flushed delayed
- * write. If so, grab its buffer and send it
- * out immediately. We'll be able to acquire
- * the flush lock when the I/O completes.
- */
- xfs_dqflock_pushbuf_wait(dqp);
- }
+ xfs_dqflock(dqp);
+
/*
* Let go of the mplist lock. We don't want to hold it
* across a disk write.
@@ -422,12 +415,12 @@ again:
mutex_unlock(&q->qi_dqlist_lock);
error = xfs_qm_dqflush(dqp, &bp);
if (!error && bp) {
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, &buffer_list);
xfs_buf_relse(bp);
}
xfs_dqunlock(dqp);
if (error)
- return error;
+ goto out;
mutex_lock(&q->qi_dqlist_lock);
if (recl != q->qi_dqreclaims) {
@@ -438,8 +431,9 @@ again:
}
mutex_unlock(&q->qi_dqlist_lock);
- /* return ! busy */
- return 0;
+out:
+ error2 = xfs_buf_delwri_submit(&buffer_list);
+ return error ? error : error2;
}
/*
@@ -1085,8 +1079,9 @@ xfs_qm_dqiter_bufs(
uint flags)
{
xfs_buf_t *bp;
- int error;
+ int error = 0, error2;
int type;
+ LIST_HEAD (buffer_list);
ASSERT(blkcnt > 0);
type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER :
@@ -1110,7 +1105,7 @@ xfs_qm_dqiter_bufs(
break;
xfs_qm_reset_dqcounts(mp, bp, firstid, type);
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, &buffer_list);
xfs_buf_relse(bp);
/*
* goto the next block.
@@ -1118,7 +1113,9 @@ xfs_qm_dqiter_bufs(
bno++;
firstid += mp->m_quotainfo->qi_dqperchunk;
}
- return error;
+
+ error2 = xfs_buf_delwri_submit(&buffer_list);
+ return error ? error : error2;
}
/*
@@ -1469,9 +1466,11 @@ xfs_qm_quotacheck(
} while (!done);
/*
- * We've made all the changes that we need to make incore.
- * Flush them down to disk buffers if everything was updated
- * successfully.
+ * We didn't log anything, because if we crashed, we'll have to
+ * start the quotacheck from scratch anyway. However, we must make
+ * sure that our dquot changes are secure before we put the
+ * quotacheck'd stamp on the superblock. So, here we do a synchronous
+ * write of all buffers that we modified.
*/
if (!error)
error = xfs_qm_dqflush_all(mp);
@@ -1489,15 +1488,6 @@ xfs_qm_quotacheck(
}
/*
- * We didn't log anything, because if we crashed, we'll have to
- * start the quotacheck from scratch anyway. However, we must make
- * sure that our dquot changes are secure before we put the
- * quotacheck'd stamp on the superblock. So, here we do a synchronous
- * flush.
- */
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
-
- /*
* If one type of quotas is off, then it will lose its
* quotachecked status, since we won't be doing accounting for
* that type anymore.
@@ -1644,29 +1634,30 @@ xfs_qm_dqreclaim_one(
/*
* We have the flush lock so we know that this is not in the
- * process of being flushed. So, if this is dirty, flush it
- * DELWRI so that we don't get a freelist infested with
- * dirty dquots.
+ * process of being flushed. So, if this is dirty, write it
+ * out so that we don't get a freelist infested with dirty
+ * dquots.
*/
if (XFS_DQ_IS_DIRTY(dqp)) {
if (!write_dirty)
goto out_busy;
else {
struct xfs_buf *bp = NULL;
-
+ LIST_HEAD (buffer_list);
trace_xfs_dqreclaim_dirty(dqp);
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
error = xfs_qm_dqflush(dqp, &bp);
if (!error && bp) {
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, &buffer_list);
xfs_buf_relse(bp);
}
if (error) {
xfs_warn(mp, "%s: dquot %p flush failed",
__func__, dqp);
}
+ xfs_buf_delwri_submit(&buffer_list);
mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
}
}
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:14.809173098 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:16.244688077 +0200
@@ -1135,22 +1135,7 @@ xfs_qm_dqpurge(
struct xfs_dqhash *qh = dqp->q_hash;
xfs_dqlock(dqp);
-
- /*
- * If we're turning off quotas, we have to make sure that, for
- * example, we don't delete quota disk blocks while dquots are
- * in the process of getting written to those disk blocks.
- * This dquot might well be on AIL, and we can't leave it there
- * if we're turning off quotas. Basically, we need this flush
- * lock, and are willing to block on it.
- */
- if (!xfs_dqflock_nowait(dqp)) {
- /*
- * Block on the flush lock after nudging dquot buffer,
- * if it is incore.
- */
- xfs_dqflock_pushbuf_wait(dqp);
- }
+ xfs_dqflock(dqp);
/*
* If we are turning this type of quotas off, we don't care
@@ -1202,36 +1187,3 @@ xfs_qm_dqpurge(
xfs_qm_dqdestroy(dqp);
}
-
-/*
- * Give the buffer a little push if it is incore and
- * wait on the flush lock.
- */
-void
-xfs_dqflock_pushbuf_wait(
- xfs_dquot_t *dqp)
-{
- xfs_mount_t *mp = dqp->q_mount;
- xfs_buf_t *bp;
-
- /*
- * Check to see if the dquot has been flushed delayed
- * write. If so, grab its buffer and send it
- * out immediately. We'll be able to acquire
- * the flush lock when the I/O completes.
- */
- bp = xfs_incore(mp->m_ddev_targp, dqp->q_blkno,
- mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
- if (!bp)
- goto out_lock;
-
- if (XFS_BUF_ISDELAYWRITE(bp)) {
- if (xfs_buf_ispinned(bp))
- xfs_log_force(mp, 0);
- xfs_buf_delwri_promote(bp);
- wake_up_process(bp->b_target->bt_task);
- }
- xfs_buf_relse(bp);
-out_lock:
- xfs_dqflock(dqp);
-}
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-10-27 22:40:13.673170747 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-10-27 22:40:16.244688077 +0200
@@ -2357,11 +2357,11 @@ cluster_corrupt_out:
*/
rcu_read_unlock();
/*
- * Clean up the buffer. If it was B_DELWRI, just release it --
+ * Clean up the buffer. If it was delwri, just release it --
* brelse can handle it with no problems. If not, shut down the
* filesystem before releasing the buffer.
*/
- bufwasdelwri = XFS_BUF_ISDELAYWRITE(bp);
+ bufwasdelwri = (bp->b_flags & _XBF_DELWRI_Q);
if (bufwasdelwri)
xfs_buf_relse(bp);
Index: xfs/fs/xfs/xfs_trans_priv.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trans_priv.h 2011-10-27 22:40:12.489171652 +0200
+++ xfs/fs/xfs/xfs_trans_priv.h 2011-10-27 22:40:16.248721987 +0200
@@ -71,6 +71,7 @@ struct xfs_ail {
spinlock_t xa_lock;
xfs_lsn_t xa_last_pushed_lsn;
int xa_log_flush;
+ struct list_head xa_buf_list;
wait_queue_head_t xa_empty;
atomic_t xa_wait_empty;
};
Index: xfs/fs/xfs/xfs_super.c
===================================================================
--- xfs.orig/fs/xfs/xfs_super.c 2011-10-27 22:40:01.238188776 +0200
+++ xfs/fs/xfs/xfs_super.c 2011-10-27 22:40:16.248721987 +0200
@@ -974,15 +974,7 @@ xfs_fs_put_super(
xfs_syncd_stop(mp);
- /*
- * Blow away any referenced inode in the filestreams cache.
- * This can and will cause log traffic as inodes go inactive
- * here.
- */
xfs_filestream_unmount(mp);
-
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
-
xfs_unmountfs(mp);
xfs_freesb(mp);
xfs_icsb_destroy_counters(mp);
@@ -1398,15 +1390,7 @@ out_destroy_workqueues:
out_syncd_stop:
xfs_syncd_stop(mp);
out_unmount:
- /*
- * Blow away any referenced inode in the filestreams cache.
- * This can and will cause log traffic as inodes go inactive
- * here.
- */
xfs_filestream_unmount(mp);
-
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
-
xfs_unmountfs(mp);
goto out_free_sb;
}
Index: xfs/fs/xfs/xfs_sync.c
===================================================================
--- xfs.orig/fs/xfs/xfs_sync.c 2011-10-27 22:40:13.685172888 +0200
+++ xfs/fs/xfs/xfs_sync.c 2011-10-27 22:40:16.257172598 +0200
@@ -313,17 +313,10 @@ xfs_quiesce_data(
/* write superblock and hoover up shutdown errors */
error = xfs_sync_fsdata(mp);
- /* make sure all delwri buffers are written out */
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
-
/* mark the log as covered if needed */
if (xfs_log_need_covered(mp))
error2 = xfs_fs_log_dummy(mp);
- /* flush data-only devices */
- if (mp->m_rtdev_targp)
- xfs_flush_buftarg(mp->m_rtdev_targp, 1);
-
return error ? error : error2;
}
Index: xfs/fs/xfs/xfs_dquot.h
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.h 2011-10-27 22:40:14.809173098 +0200
+++ xfs/fs/xfs/xfs_dquot.h 2011-10-27 22:40:16.261181282 +0200
@@ -145,7 +145,6 @@ extern void xfs_qm_dqput(xfs_dquot_t *)
extern void xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
extern void xfs_dqunlock(struct xfs_dquot *);
-extern void xfs_dqflock_pushbuf_wait(struct xfs_dquot *dqp);
static inline struct xfs_dquot *xfs_qm_dqhold(struct xfs_dquot *dqp)
{
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 43/45] xfs: do not try to unpin the inode buffer in xfs_iflush
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (38 preceding siblings ...)
2011-10-28 9:55 ` [PATCH 42/45] xfs: on-stack delayed write buffer lists Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 44/45] xfs: do not try to unpin the inode buffer in xfs_qm_dq_flush Christoph Hellwig
2011-10-28 9:55 ` [PATCH 45/45] xfs: force the log in xfs_buf_wait_unpin Christoph Hellwig
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-iflush-dont-force-log --]
[-- Type: text/plain, Size: 1661 bytes --]
Instead of trying to unpin a pinned inode buffer by forcing the log in
xfs_iflush let the caller handle it. In case of AIL pushing we already
handle it more efficiently by forcing the log synchronously once after
cycling through all AIL entries.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_inode.c | 7 -------
fs/xfs/xfs_sync.c | 7 +++++++
2 files changed, 7 insertions(+), 7 deletions(-)
Index: xfs/fs/xfs/xfs_inode.c
===================================================================
--- xfs.orig/fs/xfs/xfs_inode.c 2011-10-27 22:40:16.244688077 +0200
+++ xfs/fs/xfs/xfs_inode.c 2011-10-27 22:40:16.821171772 +0200
@@ -2468,13 +2468,6 @@ xfs_iflush(
goto corrupt_out;
/*
- * If the buffer is pinned then push on the log now so we won't
- * get stuck waiting in the write for too long.
- */
- if (xfs_buf_ispinned(bp))
- xfs_log_force(mp, 0);
-
- /*
* inode clustering:
* see if other inodes can be gathered into this write
*/
Index: xfs/fs/xfs/xfs_sync.c
===================================================================
--- xfs.orig/fs/xfs/xfs_sync.c 2011-10-27 22:40:16.257172598 +0200
+++ xfs/fs/xfs/xfs_sync.c 2011-10-27 22:40:16.821171772 +0200
@@ -724,6 +724,13 @@ restart:
delay(2);
goto restart;
} else if (!error) {
+ /*
+ * If the buffer is pinned then push on the log now so we
+ * won't get stuck waiting in the write for too long.
+ */
+ if (xfs_buf_ispinned(bp))
+ xfs_log_force(ip->i_mount, 0);
+
error = xfs_bwrite(bp);
xfs_buf_relse(bp);
}
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 44/45] xfs: do not try to unpin the inode buffer in xfs_qm_dq_flush
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (39 preceding siblings ...)
2011-10-28 9:55 ` [PATCH 43/45] xfs: do not try to unpin the inode buffer in xfs_iflush Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
2011-10-28 9:55 ` [PATCH 45/45] xfs: force the log in xfs_buf_wait_unpin Christoph Hellwig
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs-dqflush-dont-force-log --]
[-- Type: text/plain, Size: 3453 bytes --]
Instead of trying to unpin a pinned dquot buffer by forcing the log in
xfs_iflush let the caller handle it. In case of AIL pushing we already
handle it more efficiently by forcing the log synchronously once after
cycling through all AIL entries.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_dquot.c | 16 +++++++---------
fs/xfs/xfs_qm.c | 16 ++++++++++++++++
fs/xfs/xfs_trace.h | 1 -
3 files changed, 23 insertions(+), 10 deletions(-)
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:16.244688077 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:18.049202868 +0200
@@ -1069,15 +1069,6 @@ xfs_qm_dqflush(
xfs_buf_attach_iodone(bp, xfs_qm_dqflush_done,
&dqp->q_logitem.qli_item);
- /*
- * If the buffer is pinned then push on the log so we won't
- * get stuck waiting in the write for too long.
- */
- if (xfs_buf_ispinned(bp)) {
- trace_xfs_dqflush_force(dqp);
- xfs_log_force(mp, 0);
- }
-
trace_xfs_dqflush_done(dqp);
*bpp = bp;
@@ -1152,6 +1143,13 @@ xfs_qm_dqpurge(
*/
error = xfs_qm_dqflush(dqp, &bp);
if (!error && bp) {
+ /*
+ * If the buffer is pinned then push on the log so we
+ * won't get stuck waiting in the write for too long.
+ */
+ if (xfs_buf_ispinned(bp))
+ xfs_log_force(mp, 0);
+
error = xfs_bwrite(bp);
xfs_buf_relse(bp);
}
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:16.238187917 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:18.049202868 +0200
@@ -388,6 +388,7 @@ xfs_qm_dqflush_all(
int recl;
struct xfs_dquot *dqp;
int error = 0, error2;
+ int pinned = 0;
LIST_HEAD (buffer_list);
if (!q)
@@ -415,6 +416,12 @@ again:
mutex_unlock(&q->qi_dqlist_lock);
error = xfs_qm_dqflush(dqp, &bp);
if (!error && bp) {
+ /*
+ * If the buffer is pinned then push on the log so we
+ * won't get stuck waiting in the write for too long.
+ */
+ if (xfs_buf_ispinned(bp))
+ pinned++;
xfs_buf_delwri_queue(bp, &buffer_list);
xfs_buf_relse(bp);
}
@@ -432,6 +439,8 @@ again:
mutex_unlock(&q->qi_dqlist_lock);
out:
+ if (pinned)
+ xfs_log_force(mp, 0);
error2 = xfs_buf_delwri_submit(&buffer_list);
return error ? error : error2;
}
@@ -1650,6 +1659,13 @@ xfs_qm_dqreclaim_one(
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
error = xfs_qm_dqflush(dqp, &bp);
if (!error && bp) {
+ /*
+ * If the buffer is pinned then push on the
+ * log so we won't get stuck waiting in the
+ * write for too long.
+ */
+ if (xfs_buf_ispinned(bp))
+ xfs_log_force(mp, 0);
xfs_buf_delwri_queue(bp, &buffer_list);
xfs_buf_relse(bp);
}
Index: xfs/fs/xfs/xfs_trace.h
===================================================================
--- xfs.orig/fs/xfs/xfs_trace.h 2011-10-27 22:40:16.222187321 +0200
+++ xfs/fs/xfs/xfs_trace.h 2011-10-27 22:40:18.057171146 +0200
@@ -747,7 +747,6 @@ DEFINE_DQUOT_EVENT(xfs_dqput_wait);
DEFINE_DQUOT_EVENT(xfs_dqput_free);
DEFINE_DQUOT_EVENT(xfs_dqrele);
DEFINE_DQUOT_EVENT(xfs_dqflush);
-DEFINE_DQUOT_EVENT(xfs_dqflush_force);
DEFINE_DQUOT_EVENT(xfs_dqflush_done);
DECLARE_EVENT_CLASS(xfs_loggrant_class,
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* [PATCH 45/45] xfs: force the log in xfs_buf_wait_unpin
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
` (40 preceding siblings ...)
2011-10-28 9:55 ` [PATCH 44/45] xfs: do not try to unpin the inode buffer in xfs_qm_dq_flush Christoph Hellwig
@ 2011-10-28 9:55 ` Christoph Hellwig
41 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-10-28 9:55 UTC (permalink / raw)
To: xfs
[-- Attachment #1: xfs_buf_wait_unpin-force-log --]
[-- Type: text/plain, Size: 4230 bytes --]
For the log if we are waiting for a buffered to be unpinned for writing
it out. Currently all synchronous callers already do this unless they
might never encounter a pinned buffer, and non-blocking writes already
have a check for the pincount.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/xfs_buf.c | 5 +++++
fs/xfs/xfs_dquot.c | 7 -------
fs/xfs/xfs_qm.c | 16 ----------------
fs/xfs/xfs_sync.c | 17 -----------------
4 files changed, 5 insertions(+), 40 deletions(-)
Index: xfs/fs/xfs/xfs_sync.c
===================================================================
--- xfs.orig/fs/xfs/xfs_sync.c 2011-10-27 22:40:16.821171772 +0200
+++ xfs/fs/xfs/xfs_sync.c 2011-10-27 22:40:19.445176345 +0200
@@ -268,17 +268,7 @@ xfs_sync_fsdata(
struct xfs_buf *bp;
int error;
- /*
- * If the buffer is pinned then push on the log so we won't get stuck
- * waiting in the write for someone, maybe ourselves, to flush the log.
- *
- * Even though we just pushed the log above, we did not have the
- * superblock buffer locked at that point so it can become pinned in
- * between there and here.
- */
bp = xfs_getsb(mp, 0);
- if (xfs_buf_ispinned(bp))
- xfs_log_force(mp, 0);
error = xfs_bwrite(bp);
xfs_buf_relse(bp);
return error;
@@ -724,13 +714,6 @@ restart:
delay(2);
goto restart;
} else if (!error) {
- /*
- * If the buffer is pinned then push on the log now so we
- * won't get stuck waiting in the write for too long.
- */
- if (xfs_buf_ispinned(bp))
- xfs_log_force(ip->i_mount, 0);
-
error = xfs_bwrite(bp);
xfs_buf_relse(bp);
}
Index: xfs/fs/xfs/xfs_buf.c
===================================================================
--- xfs.orig/fs/xfs/xfs_buf.c 2011-10-27 22:40:16.210189457 +0200
+++ xfs/fs/xfs/xfs_buf.c 2011-10-27 22:40:19.445176345 +0200
@@ -936,6 +936,11 @@ xfs_buf_wait_unpin(
if (atomic_read(&bp->b_pin_count) == 0)
return;
+ /*
+ * Give the log a push so we don't wait here too long.
+ */
+ xfs_log_force(bp->b_target->bt_mount, 0);
+
add_wait_queue(&bp->b_waiters, &wait);
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
Index: xfs/fs/xfs/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/xfs_dquot.c 2011-10-27 22:40:18.049202868 +0200
+++ xfs/fs/xfs/xfs_dquot.c 2011-10-27 22:40:19.449175026 +0200
@@ -1143,13 +1143,6 @@ xfs_qm_dqpurge(
*/
error = xfs_qm_dqflush(dqp, &bp);
if (!error && bp) {
- /*
- * If the buffer is pinned then push on the log so we
- * won't get stuck waiting in the write for too long.
- */
- if (xfs_buf_ispinned(bp))
- xfs_log_force(mp, 0);
-
error = xfs_bwrite(bp);
xfs_buf_relse(bp);
}
Index: xfs/fs/xfs/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/xfs_qm.c 2011-10-27 22:40:18.049202868 +0200
+++ xfs/fs/xfs/xfs_qm.c 2011-10-27 22:40:19.453172157 +0200
@@ -388,7 +388,6 @@ xfs_qm_dqflush_all(
int recl;
struct xfs_dquot *dqp;
int error = 0, error2;
- int pinned = 0;
LIST_HEAD (buffer_list);
if (!q)
@@ -416,12 +415,6 @@ again:
mutex_unlock(&q->qi_dqlist_lock);
error = xfs_qm_dqflush(dqp, &bp);
if (!error && bp) {
- /*
- * If the buffer is pinned then push on the log so we
- * won't get stuck waiting in the write for too long.
- */
- if (xfs_buf_ispinned(bp))
- pinned++;
xfs_buf_delwri_queue(bp, &buffer_list);
xfs_buf_relse(bp);
}
@@ -439,8 +432,6 @@ again:
mutex_unlock(&q->qi_dqlist_lock);
out:
- if (pinned)
- xfs_log_force(mp, 0);
error2 = xfs_buf_delwri_submit(&buffer_list);
return error ? error : error2;
}
@@ -1659,13 +1650,6 @@ xfs_qm_dqreclaim_one(
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
error = xfs_qm_dqflush(dqp, &bp);
if (!error && bp) {
- /*
- * If the buffer is pinned then push on the
- * log so we won't get stuck waiting in the
- * write for too long.
- */
- if (xfs_buf_ispinned(bp))
- xfs_log_force(mp, 0);
xfs_buf_delwri_queue(bp, &buffer_list);
xfs_buf_relse(bp);
}
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 10/45] fix: force shutdown handling in xfs_end_io
2011-10-28 9:54 ` [PATCH 10/45] fix: force shutdown handling in xfs_end_io Christoph Hellwig
@ 2011-11-05 8:11 ` Christoph Hellwig
0 siblings, 0 replies; 44+ messages in thread
From: Christoph Hellwig @ 2011-11-05 8:11 UTC (permalink / raw)
To: xfs
Btw, this probably is another candidates for 3.2.
On Fri, Oct 28, 2011 at 05:54:33AM -0400, Christoph Hellwig wrote:
> Only ioend->io_error gets propagated back to e.g. AIO completions.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
>
> ---
> fs/xfs/xfs_aops.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> Index: xfs/fs/xfs/xfs_aops.c
> ===================================================================
> --- xfs.orig/fs/xfs/xfs_aops.c 2011-10-27 22:39:56.068672482 +0200
> +++ xfs/fs/xfs/xfs_aops.c 2011-10-27 22:39:56.902173367 +0200
> @@ -184,7 +184,7 @@ xfs_end_io(
> int error = 0;
>
> if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
> - error = -EIO;
> + ioend->io_error = -EIO;
> goto done;
> }
> if (ioend->io_error)
>
> _______________________________________________
> xfs mailing list
> xfs@oss.sgi.com
> http://oss.sgi.com/mailman/listinfo/xfs
---end quoted text---
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 44+ messages in thread
end of thread, other threads:[~2011-11-05 8:11 UTC | newest]
Thread overview: 44+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-28 9:54 [PATCH 00/45] write back all metadata via the AIL (and remove xfsbufd) Christoph Hellwig
2011-10-28 9:54 ` [PATCH 01/45] xfs: constify xfs_item_ops Christoph Hellwig
2011-10-28 9:54 ` [PATCH 02/45] xfs: make i_flags an unsigned long Christoph Hellwig
2011-10-28 9:54 ` [PATCH 03/45] xfs: replace i_flock with a sleeping bitlock Christoph Hellwig
2011-10-28 9:54 ` [PATCH 04/45] xfs: replace i_pin_wait with a bit waitqueue Christoph Hellwig
2011-10-28 9:54 ` [PATCH 05/45] xfs: remove the unused dm_attrs structure Christoph Hellwig
2011-10-28 9:54 ` [PATCH 06/45] xfs: remove xfs_itruncate_data Christoph Hellwig
2011-10-28 9:54 ` [PATCH 07/45] xfs: cleanup xfs_iomap_eof_align_last_fsb Christoph Hellwig
2011-10-28 9:54 ` [PATCH 08/45] xfs: remove the i_size field in struct xfs_inode Christoph Hellwig
2011-10-28 9:54 ` [PATCH 09/45] xfs: remove the i_new_size " Christoph Hellwig
2011-10-28 9:54 ` [PATCH 10/45] fix: force shutdown handling in xfs_end_io Christoph Hellwig
2011-11-05 8:11 ` Christoph Hellwig
2011-10-28 9:54 ` [PATCH 11/45] xfs: use per-filesystem I/O completion workqueues Christoph Hellwig
2011-10-28 9:54 ` [PATCH 12/45] xfs: do not require an ioend for new EOF calculation Christoph Hellwig
2011-10-28 9:54 ` [PATCH 16/45] xfs: untange SYNC_WAIT and SYNC_TRYLOCK meanings for xfs_qm_dqflush Christoph Hellwig
2011-10-28 9:54 ` [PATCH 17/45] xfs: make sure to really flush all dquots in xfs_qm_quotacheck Christoph Hellwig
2011-10-28 9:54 ` [PATCH 18/45] xfs: remove xfs_qm_sync Christoph Hellwig
2011-10-28 9:54 ` [PATCH 19/45] xfs: remove the sync_mode argument to xfs_qm_dqflush_all Christoph Hellwig
2011-10-28 9:54 ` [PATCH 20/45] xfs: cleanup dquot locking helpers Christoph Hellwig
2011-10-28 9:54 ` [PATCH 21/45] xfs: cleanup xfs_qm_dqlookup Christoph Hellwig
2011-10-28 9:54 ` [PATCH 22/45] xfs: remove XFS_DQ_INACTIVE Christoph Hellwig
2011-10-28 9:54 ` [PATCH 23/45] xfs: implement lazy removal for the dquot freelist Christoph Hellwig
2011-10-28 9:54 ` [PATCH 24/45] xfs: flatten the dquot lock ordering Christoph Hellwig
2011-10-28 9:54 ` [PATCH 25/45] xfs: nest the qm_dqfrlist_lock insise the dquot qlock Christoph Hellwig
2011-10-28 9:54 ` [PATCH 26/45] xfs: simplify xfs_qm_dqattach_grouphint Christoph Hellwig
2011-10-28 9:54 ` [PATCH 27/45] xfs: add a xfs_dqhold helper Christoph Hellwig
2011-10-28 9:54 ` [PATCH 28/45] xfs: kill xfs_qm_dqinit_core Christoph Hellwig
2011-10-28 9:54 ` [PATCH 29/45] xfs: kill xfs_qm_idtodq Christoph Hellwig
2011-10-28 9:54 ` [PATCH 30/45] xfs: remove XFS_QMOPT_DQSUSER Christoph Hellwig
2011-10-28 9:54 ` [PATCH 31/45] xfs: simplify xfs_qm_detach_gdquots Christoph Hellwig
2011-10-28 9:54 ` [PATCH 32/45] xfs: use a normal shrinker for the dquot freelist Christoph Hellwig
2011-10-28 9:54 ` [PATCH 33/45] xfs: reclaim clean dquots first Christoph Hellwig
2011-10-28 9:54 ` [PATCH 34/45] xfs: do flush inodes during asynchronous inode reclaim Christoph Hellwig
2011-10-28 9:54 ` [PATCH 35/45] xfs: remove log item from AIL in xfs_qm_dqflush after a shutdown Christoph Hellwig
2011-10-28 9:54 ` [PATCH 36/45] xfs: remove log item from AIL in xfs_iflush " Christoph Hellwig
2011-10-28 9:55 ` [PATCH 37/45] xfs: implement freezing by emptying the AIL Christoph Hellwig
2011-10-28 9:55 ` [PATCH 38/45] xfs: explicitly empty the AIL on unmount Christoph Hellwig
2011-10-28 9:55 ` [PATCH 39/45] xfs: do not write the buffer from xfs_iflush Christoph Hellwig
2011-10-28 9:55 ` [PATCH 40/45] xfs: do not write the buffer from xfs_qm_dqflush Christoph Hellwig
2011-10-28 9:55 ` [PATCH 41/45] xfs: do not add buffers to the delwri queue until pushed Christoph Hellwig
2011-10-28 9:55 ` [PATCH 42/45] xfs: on-stack delayed write buffer lists Christoph Hellwig
2011-10-28 9:55 ` [PATCH 43/45] xfs: do not try to unpin the inode buffer in xfs_iflush Christoph Hellwig
2011-10-28 9:55 ` [PATCH 44/45] xfs: do not try to unpin the inode buffer in xfs_qm_dq_flush Christoph Hellwig
2011-10-28 9:55 ` [PATCH 45/45] xfs: force the log in xfs_buf_wait_unpin Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox