Commit d5c86f89 authored by Stephen Lord's avatar Stephen Lord

Encapsulate the setting and clearing of PF_FSTRANS around xfs

transactions. This is used to protect against nested transactions
which can cause deadlocks. Also ensures we keep the state set
for the duration of a chain of rolling transactions.
parent 95d4199b
......@@ -1031,7 +1031,6 @@ count_page_state(
* the page, we have to check the process flags first, if we
* are already in a transaction or disk I/O during allocations
* is off, we need to fail the writepage and redirty the page.
* We also need to set PF_NOIO ourselves.
*/
STATIC int
......@@ -1067,7 +1066,7 @@ linvfs_writepage(
* then mark the page dirty again and leave the page
* as is.
*/
if ((current->flags & (PF_FSTRANS)) && need_trans)
if (PFLAGS_TEST_FSTRANS() && need_trans)
goto out_fail;
/*
......
......@@ -315,20 +315,14 @@ xfs_alloc_buftarg(
return btp;
}
STATIC __inline__ unsigned int gfp_mask(void)
{
/* If we're not in a transaction, FS activity is ok */
if (current->flags & PF_FSTRANS) return GFP_NOFS;
return GFP_KERNEL;
}
STATIC struct inode *
linvfs_alloc_inode(
struct super_block *sb)
{
vnode_t *vp;
vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_cachep, gfp_mask());
vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_cachep,
kmem_flags_convert(KM_SLEEP));
if (!vp)
return NULL;
return LINVFS_GET_IP(vp);
......
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -53,14 +53,32 @@
#define KM_NOSLEEP 0x0002
#define KM_NOFS 0x0004
typedef unsigned long xfs_pflags_t;
#define PFLAGS_TEST_FSTRANS() (current->flags & PF_FSTRANS)
#define PFLAGS_SET_FSTRANS(STATEP) do { \
*(STATEP) = current->flags; \
current->flags |= PF_FSTRANS; \
} while (0)
#define PFLAGS_RESTORE(STATEP) do { \
current->flags = *(STATEP); \
} while (0)
#define PFLAGS_DUP(OSTATEP, NSTATEP) do { \
*(NSTATEP) = *(OSTATEP); \
} while (0)
/*
* XXX get rid of the unconditional __GFP_NOFAIL by adding
* a KM_FAIL flag and using it where we're allowed to fail.
*/
static __inline unsigned int
flag_convert(int flags)
kmem_flags_convert(int flags)
{
int lflags;
#if DEBUG
if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS))) {
printk(KERN_WARNING
......@@ -69,12 +87,13 @@ flag_convert(int flags)
}
#endif
if (flags & KM_NOSLEEP)
return GFP_ATOMIC;
/* If we're in a transaction, FS activity is not ok */
else if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS))
return GFP_NOFS | __GFP_NOFAIL;
return GFP_KERNEL | __GFP_NOFAIL;
lflags = (flags & KM_NOSLEEP) ? GFP_ATOMIC : (GFP_KERNEL|__GFP_NOFAIL);
/* avoid recusive callbacks to filesystem during transactions */
if (PFLAGS_TEST_FSTRANS())
lflags &= ~__GFP_FS;
return lflags;
}
static __inline void *
......@@ -82,8 +101,8 @@ kmem_alloc(size_t size, int flags)
{
if (unlikely(MAX_SLAB_SIZE < size))
/* Avoid doing filesystem sensitive stuff to get this */
return __vmalloc(size, flag_convert(flags), PAGE_KERNEL);
return kmalloc(size, flag_convert(flags));
return __vmalloc(size, kmem_flags_convert(flags), PAGE_KERNEL);
return kmalloc(size, kmem_flags_convert(flags));
}
static __inline void *
......@@ -128,7 +147,7 @@ kmem_zone_init(int size, char *zone_name)
static __inline void *
kmem_zone_alloc(kmem_zone_t *zone, int flags)
{
return kmem_cache_alloc(zone, flag_convert(flags));
return kmem_cache_alloc(zone, kmem_flags_convert(flags));
}
static __inline void *
......
......@@ -43,6 +43,8 @@
* We don't need to worry about SMP or not here.
*/
#define SPLDECL(s) unsigned long s
typedef spinlock_t lock_t;
#define spinlock_init(lock, name) spin_lock_init(lock)
......
......@@ -80,7 +80,6 @@ struct xfs_iocore;
struct xfs_bmbt_irec;
struct xfs_bmap_free;
#define SPLDECL(s) unsigned long s
#define AIL_LOCK_T lock_t
#define AIL_LOCKINIT(x,y) spinlock_init(x,y)
#define AIL_LOCK_DESTROY(x) spinlock_destroy(x)
......
......@@ -200,6 +200,7 @@ xfs_trans_dup(
tp->t_blk_res = tp->t_blk_res_used;
ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
tp->t_rtx_res = tp->t_rtx_res_used;
PFLAGS_DUP(&tp->t_pflags, &ntp->t_pflags);
XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);
......@@ -238,7 +239,7 @@ xfs_trans_reserve(
rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
/* Mark this thread as being in a transaction */
current->flags |= PF_FSTRANS;
PFLAGS_SET_FSTRANS(&tp->t_pflags);
/*
* Attempt to reserve the needed disk blocks by decrementing
......@@ -249,7 +250,7 @@ xfs_trans_reserve(
error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
-blocks, rsvd);
if (error != 0) {
current->flags &= ~PF_FSTRANS;
PFLAGS_RESTORE(&tp->t_pflags);
return (XFS_ERROR(ENOSPC));
}
tp->t_blk_res += blocks;
......@@ -322,7 +323,7 @@ xfs_trans_reserve(
tp->t_blk_res = 0;
}
current->flags &= ~PF_FSTRANS;
PFLAGS_RESTORE(&tp->t_pflags);
return (error);
}
......@@ -734,13 +735,13 @@ xfs_trans_commit(
if (commit_lsn == -1 && !shutdown)
shutdown = XFS_ERROR(EIO);
}
PFLAGS_RESTORE(&tp->t_pflags);
xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
xfs_trans_free_busy(tp);
xfs_trans_free(tp);
XFS_STATS_INC(xfsstats.xs_trans_empty);
if (commit_lsn_p)
*commit_lsn_p = commit_lsn;
current->flags &= ~PF_FSTRANS;
return (shutdown);
}
#if defined(XLOG_NOLOG) || defined(DEBUG)
......@@ -823,8 +824,8 @@ xfs_trans_commit(
* had pinned, clean up, free trans structure, and return error.
*/
if (error || commit_lsn == -1) {
PFLAGS_RESTORE(&tp->t_pflags);
xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
current->flags &= ~PF_FSTRANS;
return XFS_ERROR(EIO);
}
......@@ -861,6 +862,9 @@ xfs_trans_commit(
*/
error = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));
/* mark this thread as no longer being in a transaction */
PFLAGS_RESTORE(&tp->t_pflags);
/*
* Once all the items of the transaction have been copied
* to the in core log and the callback is attached, the
......@@ -896,9 +900,6 @@ xfs_trans_commit(
XFS_STATS_INC(xfsstats.xs_trans_async);
}
/* mark this thread as no longer being in a transaction */
current->flags &= ~PF_FSTRANS;
return (error);
}
......@@ -1098,12 +1099,13 @@ xfs_trans_cancel(
}
xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags);
}
/* mark this thread as no longer being in a transaction */
PFLAGS_RESTORE(&tp->t_pflags);
xfs_trans_free_items(tp, flags);
xfs_trans_free_busy(tp);
xfs_trans_free(tp);
/* mark this thread as no longer being in a transaction */
current->flags &= ~PF_FSTRANS;
}
......
......@@ -409,6 +409,7 @@ typedef struct xfs_trans {
xfs_trans_header_t t_header; /* header for in-log trans */
unsigned int t_busy_free; /* busy descs free */
xfs_log_busy_chunk_t t_busy; /* busy/async free blocks */
xfs_pflags_t t_pflags; /* saved pflags state */
} xfs_trans_t;
#endif /* __KERNEL__ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment