Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs

* 'for-linus' of git://oss.sgi.com/xfs/xfs: (52 commits)
  fs/xfs: Correct NULL test
  xfs: optimize log flushing in xfs_fsync
  xfs: only clear the suid bit once in xfs_write
  xfs: kill xfs_bawrite
  xfs: log changed inodes instead of writing them synchronously
  xfs: remove invalid barrier optimization from xfs_fsync
  xfs: kill the unused XFS_QMOPT_* flush flags V2
  xfs: Use delay write promotion for dquot flushing
  xfs: Sort delayed write buffers before dispatch
  xfs: Don't issue buffer IO direct from AIL push V2
  xfs: Use delayed write for inodes rather than async V2
  xfs: Make inode reclaim states explicit
  xfs: more reserved blocks fixups
  xfs: turn off sign warnings
  xfs: don't hold onto reserved blocks on remount,ro
  xfs: quota limit statvfs available blocks
  xfs: replace KM_LARGE with explicit vmalloc use
  xfs: cleanup up xfs_log_force calling conventions
  xfs: kill XLOG_VEC_SET_TYPE
  xfs: remove duplicate buffer flags
  ...
This commit is contained in:
Linus Torvalds 2010-02-26 17:18:52 -08:00
commit b305956abc
79 changed files with 1672 additions and 1602 deletions

View file

@ -16,7 +16,7 @@
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# #
EXTRA_CFLAGS += -I$(src) -I$(src)/linux-2.6 -funsigned-char EXTRA_CFLAGS += -I$(src) -I$(src)/linux-2.6
XFS_LINUX := linux-2.6 XFS_LINUX := linux-2.6

View file

@ -16,7 +16,6 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
@ -24,8 +23,25 @@
#include "time.h" #include "time.h"
#include "kmem.h" #include "kmem.h"
#define MAX_VMALLOCS 6 /*
#define MAX_SLAB_SIZE 0x20000 * Greedy allocation. May fail and may return vmalloced memory.
*
* Must be freed using kmem_free_large.
*/
void *
kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize)
{
void *ptr;
size_t kmsize = maxsize;
while (!(ptr = kmem_zalloc_large(kmsize))) {
if ((kmsize >>= 1) <= minsize)
kmsize = minsize;
}
if (ptr)
*size = kmsize;
return ptr;
}
void * void *
kmem_alloc(size_t size, unsigned int __nocast flags) kmem_alloc(size_t size, unsigned int __nocast flags)
@ -34,19 +50,8 @@ kmem_alloc(size_t size, unsigned int __nocast flags)
gfp_t lflags = kmem_flags_convert(flags); gfp_t lflags = kmem_flags_convert(flags);
void *ptr; void *ptr;
#ifdef DEBUG
if (unlikely(!(flags & KM_LARGE) && (size > PAGE_SIZE))) {
printk(KERN_WARNING "Large %s attempt, size=%ld\n",
__func__, (long)size);
dump_stack();
}
#endif
do { do {
if (size < MAX_SLAB_SIZE || retries > MAX_VMALLOCS) ptr = kmalloc(size, lflags);
ptr = kmalloc(size, lflags);
else
ptr = __vmalloc(size, lflags, PAGE_KERNEL);
if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP))) if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
return ptr; return ptr;
if (!(++retries % 100)) if (!(++retries % 100))
@ -68,27 +73,6 @@ kmem_zalloc(size_t size, unsigned int __nocast flags)
return ptr; return ptr;
} }
void *
kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize,
unsigned int __nocast flags)
{
void *ptr;
size_t kmsize = maxsize;
unsigned int kmflags = (flags & ~KM_SLEEP) | KM_NOSLEEP;
while (!(ptr = kmem_zalloc(kmsize, kmflags))) {
if ((kmsize <= minsize) && (flags & KM_NOSLEEP))
break;
if ((kmsize >>= 1) <= minsize) {
kmsize = minsize;
kmflags = flags;
}
}
if (ptr)
*size = kmsize;
return ptr;
}
void void
kmem_free(const void *ptr) kmem_free(const void *ptr)
{ {

View file

@ -21,6 +21,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/vmalloc.h>
/* /*
* General memory allocation interfaces * General memory allocation interfaces
@ -30,7 +31,6 @@
#define KM_NOSLEEP 0x0002u #define KM_NOSLEEP 0x0002u
#define KM_NOFS 0x0004u #define KM_NOFS 0x0004u
#define KM_MAYFAIL 0x0008u #define KM_MAYFAIL 0x0008u
#define KM_LARGE 0x0010u
/* /*
* We use a special process flag to avoid recursive callbacks into * We use a special process flag to avoid recursive callbacks into
@ -42,7 +42,7 @@ kmem_flags_convert(unsigned int __nocast flags)
{ {
gfp_t lflags; gfp_t lflags;
BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL|KM_LARGE)); BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL));
if (flags & KM_NOSLEEP) { if (flags & KM_NOSLEEP) {
lflags = GFP_ATOMIC | __GFP_NOWARN; lflags = GFP_ATOMIC | __GFP_NOWARN;
@ -56,10 +56,25 @@ kmem_flags_convert(unsigned int __nocast flags)
extern void *kmem_alloc(size_t, unsigned int __nocast); extern void *kmem_alloc(size_t, unsigned int __nocast);
extern void *kmem_zalloc(size_t, unsigned int __nocast); extern void *kmem_zalloc(size_t, unsigned int __nocast);
extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast);
extern void *kmem_realloc(const void *, size_t, size_t, unsigned int __nocast); extern void *kmem_realloc(const void *, size_t, size_t, unsigned int __nocast);
extern void kmem_free(const void *); extern void kmem_free(const void *);
static inline void *kmem_zalloc_large(size_t size)
{
void *ptr;
ptr = vmalloc(size);
if (ptr)
memset(ptr, 0, size);
return ptr;
}
static inline void kmem_free_large(void *ptr)
{
vfree(ptr);
}
extern void *kmem_zalloc_greedy(size_t *, size_t, size_t);
/* /*
* Zone interfaces * Zone interfaces
*/ */

View file

@ -106,7 +106,7 @@ xfs_get_acl(struct inode *inode, int type)
struct posix_acl *acl; struct posix_acl *acl;
struct xfs_acl *xfs_acl; struct xfs_acl *xfs_acl;
int len = sizeof(struct xfs_acl); int len = sizeof(struct xfs_acl);
char *ea_name; unsigned char *ea_name;
int error; int error;
acl = get_cached_acl(inode, type); acl = get_cached_acl(inode, type);
@ -133,7 +133,8 @@ xfs_get_acl(struct inode *inode, int type)
if (!xfs_acl) if (!xfs_acl)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
error = -xfs_attr_get(ip, ea_name, (char *)xfs_acl, &len, ATTR_ROOT); error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
&len, ATTR_ROOT);
if (error) { if (error) {
/* /*
* If the attribute doesn't exist make sure we have a negative * If the attribute doesn't exist make sure we have a negative
@ -162,7 +163,7 @@ STATIC int
xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
{ {
struct xfs_inode *ip = XFS_I(inode); struct xfs_inode *ip = XFS_I(inode);
char *ea_name; unsigned char *ea_name;
int error; int error;
if (S_ISLNK(inode->i_mode)) if (S_ISLNK(inode->i_mode))
@ -194,7 +195,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
(sizeof(struct xfs_acl_entry) * (sizeof(struct xfs_acl_entry) *
(XFS_ACL_MAX_ENTRIES - acl->a_count)); (XFS_ACL_MAX_ENTRIES - acl->a_count));
error = -xfs_attr_set(ip, ea_name, (char *)xfs_acl, error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
len, ATTR_ROOT); len, ATTR_ROOT);
kfree(xfs_acl); kfree(xfs_acl);
@ -262,7 +263,7 @@ xfs_set_mode(struct inode *inode, mode_t mode)
} }
static int static int
xfs_acl_exists(struct inode *inode, char *name) xfs_acl_exists(struct inode *inode, unsigned char *name)
{ {
int len = sizeof(struct xfs_acl); int len = sizeof(struct xfs_acl);

View file

@ -33,6 +33,7 @@
#include <linux/migrate.h> #include <linux/migrate.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/list_sort.h>
#include "xfs_sb.h" #include "xfs_sb.h"
#include "xfs_inum.h" #include "xfs_inum.h"
@ -1072,22 +1073,30 @@ xfs_buf_ioerror(
} }
int int
xfs_bawrite( xfs_bwrite(
void *mp, struct xfs_mount *mp,
struct xfs_buf *bp) struct xfs_buf *bp)
{ {
trace_xfs_buf_bawrite(bp, _RET_IP_); int iowait = (bp->b_flags & XBF_ASYNC) == 0;
int error = 0;
ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL); bp->b_strat = xfs_bdstrat_cb;
bp->b_mount = mp;
bp->b_flags |= XBF_WRITE;
if (!iowait)
bp->b_flags |= _XBF_RUN_QUEUES;
xfs_buf_delwri_dequeue(bp); xfs_buf_delwri_dequeue(bp);
xfs_buf_iostrategy(bp);
bp->b_flags &= ~(XBF_READ | XBF_DELWRI | XBF_READ_AHEAD); if (iowait) {
bp->b_flags |= (XBF_WRITE | XBF_ASYNC | _XBF_RUN_QUEUES); error = xfs_buf_iowait(bp);
if (error)
xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
xfs_buf_relse(bp);
}
bp->b_mount = mp; return error;
bp->b_strat = xfs_bdstrat_cb;
return xfs_bdstrat_cb(bp);
} }
void void
@ -1106,6 +1115,126 @@ xfs_bdwrite(
xfs_buf_delwri_queue(bp, 1); xfs_buf_delwri_queue(bp, 1);
} }
/*
* Called when we want to stop a buffer from getting written or read.
* We attach the EIO error, muck with its flags, and call biodone
* so that the proper iodone callbacks get called.
*/
STATIC int
xfs_bioerror(
xfs_buf_t *bp)
{
#ifdef XFSERRORDEBUG
ASSERT(XFS_BUF_ISREAD(bp) || bp->b_iodone);
#endif
/*
* No need to wait until the buffer is unpinned, we aren't flushing it.
*/
XFS_BUF_ERROR(bp, EIO);
/*
* We're calling biodone, so delete XBF_DONE flag.
*/
XFS_BUF_UNREAD(bp);
XFS_BUF_UNDELAYWRITE(bp);
XFS_BUF_UNDONE(bp);
XFS_BUF_STALE(bp);
XFS_BUF_CLR_BDSTRAT_FUNC(bp);
xfs_biodone(bp);
return EIO;
}
/*
* Same as xfs_bioerror, except that we are releasing the buffer
* here ourselves, and avoiding the biodone call.
* This is meant for userdata errors; metadata bufs come with
* iodone functions attached, so that we can track down errors.
*/
STATIC int
xfs_bioerror_relse(
struct xfs_buf *bp)
{
int64_t fl = XFS_BUF_BFLAGS(bp);
/*
* No need to wait until the buffer is unpinned.
* We aren't flushing it.
*
* chunkhold expects B_DONE to be set, whether
* we actually finish the I/O or not. We don't want to
* change that interface.
*/
XFS_BUF_UNREAD(bp);
XFS_BUF_UNDELAYWRITE(bp);
XFS_BUF_DONE(bp);
XFS_BUF_STALE(bp);
XFS_BUF_CLR_IODONE_FUNC(bp);
XFS_BUF_CLR_BDSTRAT_FUNC(bp);
if (!(fl & XBF_ASYNC)) {
/*
* Mark b_error and B_ERROR _both_.
* Lot's of chunkcache code assumes that.
* There's no reason to mark error for
* ASYNC buffers.
*/
XFS_BUF_ERROR(bp, EIO);
XFS_BUF_FINISH_IOWAIT(bp);
} else {
xfs_buf_relse(bp);
}
return EIO;
}
/*
* All xfs metadata buffers except log state machine buffers
* get this attached as their b_bdstrat callback function.
* This is so that we can catch a buffer
* after prematurely unpinning it to forcibly shutdown the filesystem.
*/
int
xfs_bdstrat_cb(
struct xfs_buf *bp)
{
if (XFS_FORCED_SHUTDOWN(bp->b_mount)) {
trace_xfs_bdstrat_shut(bp, _RET_IP_);
/*
* Metadata write that didn't get logged but
* written delayed anyway. These aren't associated
* with a transaction, and can be ignored.
*/
if (!bp->b_iodone && !XFS_BUF_ISREAD(bp))
return xfs_bioerror_relse(bp);
else
return xfs_bioerror(bp);
}
xfs_buf_iorequest(bp);
return 0;
}
/*
* Wrapper around bdstrat so that we can stop data from going to disk in case
* we are shutting down the filesystem. Typically user data goes thru this
* path; one of the exceptions is the superblock.
*/
void
xfsbdstrat(
struct xfs_mount *mp,
struct xfs_buf *bp)
{
if (XFS_FORCED_SHUTDOWN(mp)) {
trace_xfs_bdstrat_shut(bp, _RET_IP_);
xfs_bioerror_relse(bp);
return;
}
xfs_buf_iorequest(bp);
}
STATIC void STATIC void
_xfs_buf_ioend( _xfs_buf_ioend(
xfs_buf_t *bp, xfs_buf_t *bp,
@ -1324,7 +1453,7 @@ xfs_buf_iomove(
xfs_buf_t *bp, /* buffer to process */ xfs_buf_t *bp, /* buffer to process */
size_t boff, /* starting buffer offset */ size_t boff, /* starting buffer offset */
size_t bsize, /* length to copy */ size_t bsize, /* length to copy */
caddr_t data, /* data address */ void *data, /* data address */
xfs_buf_rw_t mode) /* read/write/zero flag */ xfs_buf_rw_t mode) /* read/write/zero flag */
{ {
size_t bend, cpoff, csize; size_t bend, cpoff, csize;
@ -1406,8 +1535,8 @@ xfs_alloc_bufhash(
btp->bt_hashshift = external ? 3 : 8; /* 8 or 256 buckets */ btp->bt_hashshift = external ? 3 : 8; /* 8 or 256 buckets */
btp->bt_hashmask = (1 << btp->bt_hashshift) - 1; btp->bt_hashmask = (1 << btp->bt_hashshift) - 1;
btp->bt_hash = kmem_zalloc((1 << btp->bt_hashshift) * btp->bt_hash = kmem_zalloc_large((1 << btp->bt_hashshift) *
sizeof(xfs_bufhash_t), KM_SLEEP | KM_LARGE); sizeof(xfs_bufhash_t));
for (i = 0; i < (1 << btp->bt_hashshift); i++) { for (i = 0; i < (1 << btp->bt_hashshift); i++) {
spin_lock_init(&btp->bt_hash[i].bh_lock); spin_lock_init(&btp->bt_hash[i].bh_lock);
INIT_LIST_HEAD(&btp->bt_hash[i].bh_list); INIT_LIST_HEAD(&btp->bt_hash[i].bh_list);
@ -1418,7 +1547,7 @@ STATIC void
xfs_free_bufhash( xfs_free_bufhash(
xfs_buftarg_t *btp) xfs_buftarg_t *btp)
{ {
kmem_free(btp->bt_hash); kmem_free_large(btp->bt_hash);
btp->bt_hash = NULL; btp->bt_hash = NULL;
} }
@ -1623,6 +1752,11 @@ xfs_buf_delwri_queue(
list_del(&bp->b_list); list_del(&bp->b_list);
} }
if (list_empty(dwq)) {
/* start xfsbufd as it is about to have something to do */
wake_up_process(bp->b_target->bt_task);
}
bp->b_flags |= _XBF_DELWRI_Q; bp->b_flags |= _XBF_DELWRI_Q;
list_add_tail(&bp->b_list, dwq); list_add_tail(&bp->b_list, dwq);
bp->b_queuetime = jiffies; bp->b_queuetime = jiffies;
@ -1654,6 +1788,35 @@ xfs_buf_delwri_dequeue(
trace_xfs_buf_delwri_dequeue(bp, _RET_IP_); 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);
/*
* 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 (bp->b_queuetime < jiffies - age)
return;
bp->b_queuetime = jiffies - age;
spin_lock(&btp->bt_delwrite_lock);
list_move(&bp->b_list, &btp->bt_delwrite_queue);
spin_unlock(&btp->bt_delwrite_lock);
}
STATIC void STATIC void
xfs_buf_runall_queues( xfs_buf_runall_queues(
struct workqueue_struct *queue) struct workqueue_struct *queue)
@ -1672,6 +1835,8 @@ xfsbufd_wakeup(
list_for_each_entry(btp, &xfs_buftarg_list, bt_list) { list_for_each_entry(btp, &xfs_buftarg_list, bt_list) {
if (test_bit(XBT_FORCE_SLEEP, &btp->bt_flags)) if (test_bit(XBT_FORCE_SLEEP, &btp->bt_flags))
continue; continue;
if (list_empty(&btp->bt_delwrite_queue))
continue;
set_bit(XBT_FORCE_FLUSH, &btp->bt_flags); set_bit(XBT_FORCE_FLUSH, &btp->bt_flags);
wake_up_process(btp->bt_task); wake_up_process(btp->bt_task);
} }
@ -1722,20 +1887,53 @@ xfs_buf_delwri_split(
} }
/*
* Compare function is more complex than it needs to be because
* the return value is only 32 bits and we are doing comparisons
* on 64 bit values
*/
static int
xfs_buf_cmp(
void *priv,
struct list_head *a,
struct list_head *b)
{
struct xfs_buf *ap = container_of(a, struct xfs_buf, b_list);
struct xfs_buf *bp = container_of(b, struct xfs_buf, b_list);
xfs_daddr_t diff;
diff = ap->b_bn - bp->b_bn;
if (diff < 0)
return -1;
if (diff > 0)
return 1;
return 0;
}
void
xfs_buf_delwri_sort(
xfs_buftarg_t *target,
struct list_head *list)
{
list_sort(NULL, list, xfs_buf_cmp);
}
STATIC int STATIC int
xfsbufd( xfsbufd(
void *data) void *data)
{ {
struct list_head tmp; xfs_buftarg_t *target = (xfs_buftarg_t *)data;
xfs_buftarg_t *target = (xfs_buftarg_t *)data;
int count;
xfs_buf_t *bp;
current->flags |= PF_MEMALLOC; current->flags |= PF_MEMALLOC;
set_freezable(); set_freezable();
do { do {
long age = xfs_buf_age_centisecs * msecs_to_jiffies(10);
long tout = xfs_buf_timer_centisecs * msecs_to_jiffies(10);
int count = 0;
struct list_head tmp;
if (unlikely(freezing(current))) { if (unlikely(freezing(current))) {
set_bit(XBT_FORCE_SLEEP, &target->bt_flags); set_bit(XBT_FORCE_SLEEP, &target->bt_flags);
refrigerator(); refrigerator();
@ -1743,17 +1941,16 @@ xfsbufd(
clear_bit(XBT_FORCE_SLEEP, &target->bt_flags); clear_bit(XBT_FORCE_SLEEP, &target->bt_flags);
} }
schedule_timeout_interruptible( /* sleep for a long time if there is nothing to do. */
xfs_buf_timer_centisecs * msecs_to_jiffies(10)); if (list_empty(&target->bt_delwrite_queue))
tout = MAX_SCHEDULE_TIMEOUT;
schedule_timeout_interruptible(tout);
xfs_buf_delwri_split(target, &tmp, xfs_buf_delwri_split(target, &tmp, age);
xfs_buf_age_centisecs * msecs_to_jiffies(10)); list_sort(NULL, &tmp, xfs_buf_cmp);
count = 0;
while (!list_empty(&tmp)) { while (!list_empty(&tmp)) {
bp = list_entry(tmp.next, xfs_buf_t, b_list); struct xfs_buf *bp;
ASSERT(target == bp->b_target); bp = list_first_entry(&tmp, struct xfs_buf, b_list);
list_del_init(&bp->b_list); list_del_init(&bp->b_list);
xfs_buf_iostrategy(bp); xfs_buf_iostrategy(bp);
count++; count++;
@ -1779,42 +1976,45 @@ xfs_flush_buftarg(
xfs_buftarg_t *target, xfs_buftarg_t *target,
int wait) int wait)
{ {
struct list_head tmp; xfs_buf_t *bp;
xfs_buf_t *bp, *n;
int pincount = 0; int pincount = 0;
LIST_HEAD(tmp_list);
LIST_HEAD(wait_list);
xfs_buf_runall_queues(xfsconvertd_workqueue); xfs_buf_runall_queues(xfsconvertd_workqueue);
xfs_buf_runall_queues(xfsdatad_workqueue); xfs_buf_runall_queues(xfsdatad_workqueue);
xfs_buf_runall_queues(xfslogd_workqueue); xfs_buf_runall_queues(xfslogd_workqueue);
set_bit(XBT_FORCE_FLUSH, &target->bt_flags); set_bit(XBT_FORCE_FLUSH, &target->bt_flags);
pincount = xfs_buf_delwri_split(target, &tmp, 0); pincount = xfs_buf_delwri_split(target, &tmp_list, 0);
/* /*
* Dropped the delayed write list lock, now walk the temporary list * 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_for_each_entry_safe(bp, n, &tmp, b_list) { list_sort(NULL, &tmp_list, xfs_buf_cmp);
while (!list_empty(&tmp_list)) {
bp = list_first_entry(&tmp_list, struct xfs_buf, b_list);
ASSERT(target == bp->b_target); ASSERT(target == bp->b_target);
if (wait) list_del_init(&bp->b_list);
if (wait) {
bp->b_flags &= ~XBF_ASYNC; bp->b_flags &= ~XBF_ASYNC;
else list_add(&bp->b_list, &wait_list);
list_del_init(&bp->b_list); }
xfs_buf_iostrategy(bp); xfs_buf_iostrategy(bp);
} }
if (wait) if (wait) {
/* Expedite and wait for IO to complete. */
blk_run_address_space(target->bt_mapping); blk_run_address_space(target->bt_mapping);
while (!list_empty(&wait_list)) {
bp = list_first_entry(&wait_list, struct xfs_buf, b_list);
/* list_del_init(&bp->b_list);
* Remaining list items must be flushed before returning xfs_iowait(bp);
*/ xfs_buf_relse(bp);
while (!list_empty(&tmp)) { }
bp = list_entry(tmp.next, xfs_buf_t, b_list);
list_del_init(&bp->b_list);
xfs_iowait(bp);
xfs_buf_relse(bp);
} }
return pincount; return pincount;

View file

@ -232,13 +232,17 @@ extern void xfs_buf_lock(xfs_buf_t *);
extern void xfs_buf_unlock(xfs_buf_t *); extern void xfs_buf_unlock(xfs_buf_t *);
/* Buffer Read and Write Routines */ /* Buffer Read and Write Routines */
extern int xfs_bawrite(void *mp, xfs_buf_t *bp); extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp);
extern void xfs_bdwrite(void *mp, xfs_buf_t *bp); extern void xfs_bdwrite(void *mp, xfs_buf_t *bp);
extern void xfsbdstrat(struct xfs_mount *, struct xfs_buf *);
extern int xfs_bdstrat_cb(struct xfs_buf *);
extern void xfs_buf_ioend(xfs_buf_t *, int); extern void xfs_buf_ioend(xfs_buf_t *, int);
extern void xfs_buf_ioerror(xfs_buf_t *, int); extern void xfs_buf_ioerror(xfs_buf_t *, int);
extern int xfs_buf_iorequest(xfs_buf_t *); extern int xfs_buf_iorequest(xfs_buf_t *);
extern int xfs_buf_iowait(xfs_buf_t *); extern int xfs_buf_iowait(xfs_buf_t *);
extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, xfs_caddr_t, extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
xfs_buf_rw_t); xfs_buf_rw_t);
static inline int xfs_buf_iostrategy(xfs_buf_t *bp) static inline int xfs_buf_iostrategy(xfs_buf_t *bp)
@ -261,6 +265,7 @@ extern int xfs_buf_ispin(xfs_buf_t *);
/* Delayed Write Buffer Routines */ /* Delayed Write Buffer Routines */
extern void xfs_buf_delwri_dequeue(xfs_buf_t *); extern void xfs_buf_delwri_dequeue(xfs_buf_t *);
extern void xfs_buf_delwri_promote(xfs_buf_t *);
/* Buffer Daemon Setup Routines */ /* Buffer Daemon Setup Routines */
extern int xfs_buf_init(void); extern int xfs_buf_init(void);
@ -270,33 +275,19 @@ extern void xfs_buf_terminate(void);
({ char __b[BDEVNAME_SIZE]; bdevname((target)->bt_bdev, __b); __b; }) ({ char __b[BDEVNAME_SIZE]; bdevname((target)->bt_bdev, __b); __b; })
#define XFS_B_ASYNC XBF_ASYNC
#define XFS_B_DELWRI XBF_DELWRI
#define XFS_B_READ XBF_READ
#define XFS_B_WRITE XBF_WRITE
#define XFS_B_STALE XBF_STALE
#define XFS_BUF_TRYLOCK XBF_TRYLOCK
#define XFS_INCORE_TRYLOCK XBF_TRYLOCK
#define XFS_BUF_LOCK XBF_LOCK
#define XFS_BUF_MAPPED XBF_MAPPED
#define BUF_BUSY XBF_DONT_BLOCK
#define XFS_BUF_BFLAGS(bp) ((bp)->b_flags) #define XFS_BUF_BFLAGS(bp) ((bp)->b_flags)
#define XFS_BUF_ZEROFLAGS(bp) ((bp)->b_flags &= \ #define XFS_BUF_ZEROFLAGS(bp) ((bp)->b_flags &= \
~(XBF_READ|XBF_WRITE|XBF_ASYNC|XBF_DELWRI|XBF_ORDERED)) ~(XBF_READ|XBF_WRITE|XBF_ASYNC|XBF_DELWRI|XBF_ORDERED))
#define XFS_BUF_STALE(bp) ((bp)->b_flags |= XFS_B_STALE) #define XFS_BUF_STALE(bp) ((bp)->b_flags |= XBF_STALE)
#define XFS_BUF_UNSTALE(bp) ((bp)->b_flags &= ~XFS_B_STALE) #define XFS_BUF_UNSTALE(bp) ((bp)->b_flags &= ~XBF_STALE)
#define XFS_BUF_ISSTALE(bp) ((bp)->b_flags & XFS_B_STALE) #define XFS_BUF_ISSTALE(bp) ((bp)->b_flags & XBF_STALE)
#define XFS_BUF_SUPER_STALE(bp) do { \ #define XFS_BUF_SUPER_STALE(bp) do { \
XFS_BUF_STALE(bp); \ XFS_BUF_STALE(bp); \
xfs_buf_delwri_dequeue(bp); \ xfs_buf_delwri_dequeue(bp); \
XFS_BUF_DONE(bp); \ XFS_BUF_DONE(bp); \
} while (0) } while (0)
#define XFS_BUF_MANAGE XBF_FS_MANAGED
#define XFS_BUF_UNMANAGE(bp) ((bp)->b_flags &= ~XBF_FS_MANAGED) #define XFS_BUF_UNMANAGE(bp) ((bp)->b_flags &= ~XBF_FS_MANAGED)
#define XFS_BUF_DELAYWRITE(bp) ((bp)->b_flags |= XBF_DELWRI) #define XFS_BUF_DELAYWRITE(bp) ((bp)->b_flags |= XBF_DELWRI)
@ -385,31 +376,11 @@ static inline void xfs_buf_relse(xfs_buf_t *bp)
#define xfs_biomove(bp, off, len, data, rw) \ #define xfs_biomove(bp, off, len, data, rw) \
xfs_buf_iomove((bp), (off), (len), (data), \ xfs_buf_iomove((bp), (off), (len), (data), \
((rw) == XFS_B_WRITE) ? XBRW_WRITE : XBRW_READ) ((rw) == XBF_WRITE) ? XBRW_WRITE : XBRW_READ)
#define xfs_biozero(bp, off, len) \ #define xfs_biozero(bp, off, len) \
xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO) xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO)
static inline int XFS_bwrite(xfs_buf_t *bp)
{
int iowait = (bp->b_flags & XBF_ASYNC) == 0;
int error = 0;
if (!iowait)
bp->b_flags |= _XBF_RUN_QUEUES;
xfs_buf_delwri_dequeue(bp);
xfs_buf_iostrategy(bp);
if (iowait) {
error = xfs_buf_iowait(bp);
xfs_buf_relse(bp);
}
return error;
}
#define XFS_bdstrat(bp) xfs_buf_iorequest(bp)
#define xfs_iowait(bp) xfs_buf_iowait(bp) #define xfs_iowait(bp) xfs_buf_iowait(bp)
#define xfs_baread(target, rablkno, ralen) \ #define xfs_baread(target, rablkno, ralen) \
@ -424,6 +395,7 @@ extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *);
extern void xfs_wait_buftarg(xfs_buftarg_t *); extern void xfs_wait_buftarg(xfs_buftarg_t *);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
extern int xfs_flush_buftarg(xfs_buftarg_t *, int); extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
#ifdef CONFIG_KDB_MODULES #ifdef CONFIG_KDB_MODULES
extern struct list_head *xfs_get_buftarg_list(void); extern struct list_head *xfs_get_buftarg_list(void);
#endif #endif

View file

@ -79,7 +79,7 @@ xfs_flush_pages(
xfs_iflags_clear(ip, XFS_ITRUNCATED); xfs_iflags_clear(ip, XFS_ITRUNCATED);
ret = -filemap_fdatawrite(mapping); ret = -filemap_fdatawrite(mapping);
} }
if (flags & XFS_B_ASYNC) if (flags & XBF_ASYNC)
return ret; return ret;
ret2 = xfs_wait_on_pages(ip, first, last); ret2 = xfs_wait_on_pages(ip, first, last);
if (!ret) if (!ret)

View file

@ -447,12 +447,12 @@ xfs_attrlist_by_handle(
int int
xfs_attrmulti_attr_get( xfs_attrmulti_attr_get(
struct inode *inode, struct inode *inode,
char *name, unsigned char *name,
char __user *ubuf, unsigned char __user *ubuf,
__uint32_t *len, __uint32_t *len,
__uint32_t flags) __uint32_t flags)
{ {
char *kbuf; unsigned char *kbuf;
int error = EFAULT; int error = EFAULT;
if (*len > XATTR_SIZE_MAX) if (*len > XATTR_SIZE_MAX)
@ -476,12 +476,12 @@ xfs_attrmulti_attr_get(
int int
xfs_attrmulti_attr_set( xfs_attrmulti_attr_set(
struct inode *inode, struct inode *inode,
char *name, unsigned char *name,
const char __user *ubuf, const unsigned char __user *ubuf,
__uint32_t len, __uint32_t len,
__uint32_t flags) __uint32_t flags)
{ {
char *kbuf; unsigned char *kbuf;
int error = EFAULT; int error = EFAULT;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
@ -501,7 +501,7 @@ xfs_attrmulti_attr_set(
int int
xfs_attrmulti_attr_remove( xfs_attrmulti_attr_remove(
struct inode *inode, struct inode *inode,
char *name, unsigned char *name,
__uint32_t flags) __uint32_t flags)
{ {
if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
@ -519,7 +519,7 @@ xfs_attrmulti_by_handle(
xfs_fsop_attrmulti_handlereq_t am_hreq; xfs_fsop_attrmulti_handlereq_t am_hreq;
struct dentry *dentry; struct dentry *dentry;
unsigned int i, size; unsigned int i, size;
char *attr_name; unsigned char *attr_name;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM); return -XFS_ERROR(EPERM);
@ -547,7 +547,7 @@ xfs_attrmulti_by_handle(
error = 0; error = 0;
for (i = 0; i < am_hreq.opcount; i++) { for (i = 0; i < am_hreq.opcount; i++) {
ops[i].am_error = strncpy_from_user(attr_name, ops[i].am_error = strncpy_from_user((char *)attr_name,
ops[i].am_attrname, MAXNAMELEN); ops[i].am_attrname, MAXNAMELEN);
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
error = -ERANGE; error = -ERANGE;
@ -1431,6 +1431,9 @@ xfs_file_ioctl(
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (mp->m_flags & XFS_MOUNT_RDONLY)
return -XFS_ERROR(EROFS);
if (copy_from_user(&inout, arg, sizeof(inout))) if (copy_from_user(&inout, arg, sizeof(inout)))
return -XFS_ERROR(EFAULT); return -XFS_ERROR(EFAULT);

View file

@ -45,23 +45,23 @@ xfs_readlink_by_handle(
extern int extern int
xfs_attrmulti_attr_get( xfs_attrmulti_attr_get(
struct inode *inode, struct inode *inode,
char *name, unsigned char *name,
char __user *ubuf, unsigned char __user *ubuf,
__uint32_t *len, __uint32_t *len,
__uint32_t flags); __uint32_t flags);
extern int extern int
xfs_attrmulti_attr_set( xfs_attrmulti_attr_set(
struct inode *inode, struct inode *inode,
char *name, unsigned char *name,
const char __user *ubuf, const unsigned char __user *ubuf,
__uint32_t len, __uint32_t len,
__uint32_t flags); __uint32_t flags);
extern int extern int
xfs_attrmulti_attr_remove( xfs_attrmulti_attr_remove(
struct inode *inode, struct inode *inode,
char *name, unsigned char *name,
__uint32_t flags); __uint32_t flags);
extern struct dentry * extern struct dentry *

View file

@ -411,7 +411,7 @@ xfs_compat_attrmulti_by_handle(
compat_xfs_fsop_attrmulti_handlereq_t am_hreq; compat_xfs_fsop_attrmulti_handlereq_t am_hreq;
struct dentry *dentry; struct dentry *dentry;
unsigned int i, size; unsigned int i, size;
char *attr_name; unsigned char *attr_name;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM); return -XFS_ERROR(EPERM);
@ -440,7 +440,7 @@ xfs_compat_attrmulti_by_handle(
error = 0; error = 0;
for (i = 0; i < am_hreq.opcount; i++) { for (i = 0; i < am_hreq.opcount; i++) {
ops[i].am_error = strncpy_from_user(attr_name, ops[i].am_error = strncpy_from_user((char *)attr_name,
compat_ptr(ops[i].am_attrname), compat_ptr(ops[i].am_attrname),
MAXNAMELEN); MAXNAMELEN);
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)

View file

@ -140,10 +140,10 @@ xfs_init_security(
struct xfs_inode *ip = XFS_I(inode); struct xfs_inode *ip = XFS_I(inode);
size_t length; size_t length;
void *value; void *value;
char *name; unsigned char *name;
int error; int error;
error = security_inode_init_security(inode, dir, &name, error = security_inode_init_security(inode, dir, (char **)&name,
&value, &length); &value, &length);
if (error) { if (error) {
if (error == -EOPNOTSUPP) if (error == -EOPNOTSUPP)

View file

@ -630,18 +630,9 @@ start:
* by root. This keeps people from modifying setuid and * by root. This keeps people from modifying setuid and
* setgid binaries. * setgid binaries.
*/ */
error = -file_remove_suid(file);
if (((xip->i_d.di_mode & S_ISUID) || if (unlikely(error))
((xip->i_d.di_mode & (S_ISGID | S_IXGRP)) == goto out_unlock_internal;
(S_ISGID | S_IXGRP))) &&
!capable(CAP_FSETID)) {
error = xfs_write_clear_setuid(xip);
if (likely(!error))
error = -file_remove_suid(file);
if (unlikely(error)) {
goto out_unlock_internal;
}
}
/* We can write back this queue in page reclaim */ /* We can write back this queue in page reclaim */
current->backing_dev_info = mapping->backing_dev_info; current->backing_dev_info = mapping->backing_dev_info;
@ -783,53 +774,6 @@ write_retry:
return -error; return -error;
} }
/*
* All xfs metadata buffers except log state machine buffers
* get this attached as their b_bdstrat callback function.
* This is so that we can catch a buffer
* after prematurely unpinning it to forcibly shutdown the filesystem.
*/
int
xfs_bdstrat_cb(struct xfs_buf *bp)
{
if (XFS_FORCED_SHUTDOWN(bp->b_mount)) {
trace_xfs_bdstrat_shut(bp, _RET_IP_);
/*
* Metadata write that didn't get logged but
* written delayed anyway. These aren't associated
* with a transaction, and can be ignored.
*/
if (XFS_BUF_IODONE_FUNC(bp) == NULL &&
(XFS_BUF_ISREAD(bp)) == 0)
return (xfs_bioerror_relse(bp));
else
return (xfs_bioerror(bp));
}
xfs_buf_iorequest(bp);
return 0;
}
/*
* Wrapper around bdstrat so that we can stop data from going to disk in case
* we are shutting down the filesystem. Typically user data goes thru this
* path; one of the exceptions is the superblock.
*/
void
xfsbdstrat(
struct xfs_mount *mp,
struct xfs_buf *bp)
{
ASSERT(mp);
if (!XFS_FORCED_SHUTDOWN(mp)) {
xfs_buf_iorequest(bp);
return;
}
trace_xfs_bdstrat_shut(bp, _RET_IP_);
xfs_bioerror_relse(bp);
}
/* /*
* If the underlying (data/log/rt) device is readonly, there are some * If the underlying (data/log/rt) device is readonly, there are some
* operations that cannot proceed. * operations that cannot proceed.

View file

@ -22,9 +22,6 @@ struct xfs_mount;
struct xfs_inode; struct xfs_inode;
struct xfs_buf; struct xfs_buf;
/* errors from xfsbdstrat() must be extracted from the buffer */
extern void xfsbdstrat(struct xfs_mount *, struct xfs_buf *);
extern int xfs_bdstrat_cb(struct xfs_buf *);
extern int xfs_dev_is_read_only(struct xfs_mount *, char *); extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
extern int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); extern int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);

View file

@ -877,12 +877,11 @@ xfsaild(
{ {
struct xfs_ail *ailp = data; struct xfs_ail *ailp = data;
xfs_lsn_t last_pushed_lsn = 0; xfs_lsn_t last_pushed_lsn = 0;
long tout = 0; long tout = 0; /* milliseconds */
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
if (tout) schedule_timeout_interruptible(tout ?
schedule_timeout_interruptible(msecs_to_jiffies(tout)); msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
tout = 1000;
/* swsusp */ /* swsusp */
try_to_freeze(); try_to_freeze();
@ -1022,12 +1021,45 @@ xfs_fs_dirty_inode(
XFS_I(inode)->i_update_core = 1; XFS_I(inode)->i_update_core = 1;
} }
/* STATIC int
* Attempt to flush the inode, this will actually fail xfs_log_inode(
* if the inode is pinned, but we dirty the inode again struct xfs_inode *ip)
* at the point when it is unpinned after a log write, {
* since this is when the inode itself becomes flushable. struct xfs_mount *mp = ip->i_mount;
*/ struct xfs_trans *tp;
int error;
xfs_iunlock(ip, XFS_ILOCK_SHARED);
tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
if (error) {
xfs_trans_cancel(tp, 0);
/* we need to return with the lock hold shared */
xfs_ilock(ip, XFS_ILOCK_SHARED);
return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
/*
* Note - it's possible that we might have pushed ourselves out of the
* way during trans_reserve which would flush the inode. But there's
* no guarantee that the inode buffer has actually gone out yet (it's
* delwri). Plus the buffer could be pinned anyway if it's part of
* an inode in another recent transaction. So we play it safe and
* fire off the transaction anyway.
*/
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_ihold(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp, 0);
xfs_ilock_demote(ip, XFS_ILOCK_EXCL);
return error;
}
STATIC int STATIC int
xfs_fs_write_inode( xfs_fs_write_inode(
struct inode *inode, struct inode *inode,
@ -1035,7 +1067,7 @@ xfs_fs_write_inode(
{ {
struct xfs_inode *ip = XFS_I(inode); struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
int error = 0; int error = EAGAIN;
xfs_itrace_entry(ip); xfs_itrace_entry(ip);
@ -1046,36 +1078,56 @@ xfs_fs_write_inode(
error = xfs_wait_on_pages(ip, 0, -1); error = xfs_wait_on_pages(ip, 0, -1);
if (error) if (error)
goto out; goto out;
}
/* /*
* Bypass inodes which have already been cleaned by * Make sure the inode has hit stable storage. By using the
* the inode flush clustering code inside xfs_iflush * log and the fsync transactions we reduce the IOs we have
*/ * to do here from two (log and inode) to just the log.
if (xfs_inode_clean(ip)) *
goto out; * Note: We still need to do a delwri write of the inode after
* this to flush it to the backing buffer so that bulkstat
/* * works properly if this is the first time the inode has been
* We make this non-blocking if the inode is contended, return * written. Because we hold the ilock atomically over the
* EAGAIN to indicate to the caller that they did not succeed. * transaction commit and the inode flush we are guaranteed
* This prevents the flush path from blocking on inodes inside * that the inode is not pinned when it returns. If the flush
* another operation right now, they get caught later by xfs_sync. * lock is already held, then the inode has already been
*/ * flushed once and we don't need to flush it again. Hence
if (sync) { * the code will only flush the inode if it isn't already
* being flushed.
*/
xfs_ilock(ip, XFS_ILOCK_SHARED); xfs_ilock(ip, XFS_ILOCK_SHARED);
xfs_iflock(ip); if (ip->i_update_core) {
error = xfs_log_inode(ip);
error = xfs_iflush(ip, XFS_IFLUSH_SYNC); if (error)
goto out_unlock;
}
} else { } else {
error = EAGAIN; /*
* We make this non-blocking if the inode is contended, return
* EAGAIN to indicate to the caller that they did not succeed.
* This prevents the flush path from blocking on inodes inside
* another operation right now, they get caught later by xfs_sync.
*/
if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
goto out; goto out;
if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
goto out_unlock;
error = xfs_iflush(ip, XFS_IFLUSH_ASYNC_NOBLOCK);
} }
if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
goto out_unlock;
/*
* Now we have the flush lock and the inode is not pinned, we can check
* if the inode is really clean as we know that there are no pending
* transaction completions, it is not waiting on the delayed write
* queue and there is no IO in progress.
*/
if (xfs_inode_clean(ip)) {
xfs_ifunlock(ip);
error = 0;
goto out_unlock;
}
error = xfs_iflush(ip, 0);
out_unlock: out_unlock:
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
out: out:
@ -1257,6 +1309,29 @@ xfs_fs_statfs(
return 0; return 0;
} }
STATIC void
xfs_save_resvblks(struct xfs_mount *mp)
{
__uint64_t resblks = 0;
mp->m_resblks_save = mp->m_resblks;
xfs_reserve_blocks(mp, &resblks, NULL);
}
STATIC void
xfs_restore_resvblks(struct xfs_mount *mp)
{
__uint64_t resblks;
if (mp->m_resblks_save) {
resblks = mp->m_resblks_save;
mp->m_resblks_save = 0;
} else
resblks = xfs_default_resblks(mp);
xfs_reserve_blocks(mp, &resblks, NULL);
}
STATIC int STATIC int
xfs_fs_remount( xfs_fs_remount(
struct super_block *sb, struct super_block *sb,
@ -1336,11 +1411,27 @@ xfs_fs_remount(
} }
mp->m_update_flags = 0; mp->m_update_flags = 0;
} }
/*
* Fill out the reserve pool if it is empty. Use the stashed
* value if it is non-zero, otherwise go with the default.
*/
xfs_restore_resvblks(mp);
} }
/* rw -> ro */ /* rw -> ro */
if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) { if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) {
/*
* After we have synced the data but before we sync the
* metadata, we need to free up the reserve block pool so that
* the used block count in the superblock on disk is correct at
* the end of the remount. Stash the current reserve pool size
* so that if we get remounted rw, we can return it to the same
* size.
*/
xfs_quiesce_data(mp); xfs_quiesce_data(mp);
xfs_save_resvblks(mp);
xfs_quiesce_attr(mp); xfs_quiesce_attr(mp);
mp->m_flags |= XFS_MOUNT_RDONLY; mp->m_flags |= XFS_MOUNT_RDONLY;
} }
@ -1359,10 +1450,21 @@ xfs_fs_freeze(
{ {
struct xfs_mount *mp = XFS_M(sb); struct xfs_mount *mp = XFS_M(sb);
xfs_save_resvblks(mp);
xfs_quiesce_attr(mp); xfs_quiesce_attr(mp);
return -xfs_fs_log_dummy(mp); return -xfs_fs_log_dummy(mp);
} }
STATIC int
xfs_fs_unfreeze(
struct super_block *sb)
{
struct xfs_mount *mp = XFS_M(sb);
xfs_restore_resvblks(mp);
return 0;
}
STATIC int STATIC int
xfs_fs_show_options( xfs_fs_show_options(
struct seq_file *m, struct seq_file *m,
@ -1585,6 +1687,7 @@ static const struct super_operations xfs_super_operations = {
.put_super = xfs_fs_put_super, .put_super = xfs_fs_put_super,
.sync_fs = xfs_fs_sync_fs, .sync_fs = xfs_fs_sync_fs,
.freeze_fs = xfs_fs_freeze, .freeze_fs = xfs_fs_freeze,
.unfreeze_fs = xfs_fs_unfreeze,
.statfs = xfs_fs_statfs, .statfs = xfs_fs_statfs,
.remount_fs = xfs_fs_remount, .remount_fs = xfs_fs_remount,
.show_options = xfs_fs_show_options, .show_options = xfs_fs_show_options,

View file

@ -90,14 +90,13 @@ xfs_inode_ag_lookup(
STATIC int STATIC int
xfs_inode_ag_walk( xfs_inode_ag_walk(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_agnumber_t ag, struct xfs_perag *pag,
int (*execute)(struct xfs_inode *ip, int (*execute)(struct xfs_inode *ip,
struct xfs_perag *pag, int flags), struct xfs_perag *pag, int flags),
int flags, int flags,
int tag, int tag,
int exclusive) int exclusive)
{ {
struct xfs_perag *pag = &mp->m_perag[ag];
uint32_t first_index; uint32_t first_index;
int last_error = 0; int last_error = 0;
int skipped; int skipped;
@ -141,8 +140,6 @@ restart:
delay(1); delay(1);
goto restart; goto restart;
} }
xfs_put_perag(mp, pag);
return last_error; return last_error;
} }
@ -160,10 +157,16 @@ xfs_inode_ag_iterator(
xfs_agnumber_t ag; xfs_agnumber_t ag;
for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
if (!mp->m_perag[ag].pag_ici_init) struct xfs_perag *pag;
pag = xfs_perag_get(mp, ag);
if (!pag->pag_ici_init) {
xfs_perag_put(pag);
continue; continue;
error = xfs_inode_ag_walk(mp, ag, execute, flags, tag, }
error = xfs_inode_ag_walk(mp, pag, execute, flags, tag,
exclusive); exclusive);
xfs_perag_put(pag);
if (error) { if (error) {
last_error = error; last_error = error;
if (error == EFSCORRUPTED) if (error == EFSCORRUPTED)
@ -231,7 +234,7 @@ xfs_sync_inode_data(
} }
error = xfs_flush_pages(ip, 0, -1, (flags & SYNC_WAIT) ? error = xfs_flush_pages(ip, 0, -1, (flags & SYNC_WAIT) ?
0 : XFS_B_ASYNC, FI_NONE); 0 : XBF_ASYNC, FI_NONE);
xfs_iunlock(ip, XFS_IOLOCK_SHARED); xfs_iunlock(ip, XFS_IOLOCK_SHARED);
out_wait: out_wait:
@ -267,8 +270,7 @@ xfs_sync_inode_attr(
goto out_unlock; goto out_unlock;
} }
error = xfs_iflush(ip, (flags & SYNC_WAIT) ? error = xfs_iflush(ip, flags);
XFS_IFLUSH_SYNC : XFS_IFLUSH_DELWRI);
out_unlock: out_unlock:
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
@ -293,10 +295,7 @@ xfs_sync_data(
if (error) if (error)
return XFS_ERROR(error); return XFS_ERROR(error);
xfs_log_force(mp, 0, xfs_log_force(mp, (flags & SYNC_WAIT) ? XFS_LOG_SYNC : 0);
(flags & SYNC_WAIT) ?
XFS_LOG_FORCE | XFS_LOG_SYNC :
XFS_LOG_FORCE);
return 0; return 0;
} }
@ -322,10 +321,6 @@ xfs_commit_dummy_trans(
struct xfs_inode *ip = mp->m_rootip; struct xfs_inode *ip = mp->m_rootip;
struct xfs_trans *tp; struct xfs_trans *tp;
int error; int error;
int log_flags = XFS_LOG_FORCE;
if (flags & SYNC_WAIT)
log_flags |= XFS_LOG_SYNC;
/* /*
* Put a dummy transaction in the log to tell recovery * Put a dummy transaction in the log to tell recovery
@ -347,11 +342,11 @@ xfs_commit_dummy_trans(
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(ip, XFS_ILOCK_EXCL);
/* the log force ensures this transaction is pushed to disk */ /* the log force ensures this transaction is pushed to disk */
xfs_log_force(mp, 0, log_flags); xfs_log_force(mp, (flags & SYNC_WAIT) ? XFS_LOG_SYNC : 0);
return error; return error;
} }
int STATIC int
xfs_sync_fsdata( xfs_sync_fsdata(
struct xfs_mount *mp, struct xfs_mount *mp,
int flags) int flags)
@ -367,7 +362,7 @@ xfs_sync_fsdata(
if (flags & SYNC_TRYLOCK) { if (flags & SYNC_TRYLOCK) {
ASSERT(!(flags & SYNC_WAIT)); ASSERT(!(flags & SYNC_WAIT));
bp = xfs_getsb(mp, XFS_BUF_TRYLOCK); bp = xfs_getsb(mp, XBF_TRYLOCK);
if (!bp) if (!bp)
goto out; goto out;
@ -387,7 +382,7 @@ xfs_sync_fsdata(
* become pinned in between there and here. * become pinned in between there and here.
*/ */
if (XFS_BUF_ISPINNED(bp)) if (XFS_BUF_ISPINNED(bp))
xfs_log_force(mp, 0, XFS_LOG_FORCE); xfs_log_force(mp, 0);
} }
@ -448,9 +443,6 @@ xfs_quiesce_data(
xfs_sync_data(mp, SYNC_WAIT); xfs_sync_data(mp, SYNC_WAIT);
xfs_qm_sync(mp, SYNC_WAIT); xfs_qm_sync(mp, SYNC_WAIT);
/* drop inode references pinned by filestreams */
xfs_filestream_flush(mp);
/* write superblock and hoover up shutdown errors */ /* write superblock and hoover up shutdown errors */
error = xfs_sync_fsdata(mp, SYNC_WAIT); error = xfs_sync_fsdata(mp, SYNC_WAIT);
@ -467,16 +459,18 @@ xfs_quiesce_fs(
{ {
int count = 0, pincount; int count = 0, pincount;
xfs_reclaim_inodes(mp, 0);
xfs_flush_buftarg(mp->m_ddev_targp, 0); xfs_flush_buftarg(mp->m_ddev_targp, 0);
xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
/* /*
* This loop must run at least twice. The first instance of the loop * 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 * will flush most meta data but that will generate more meta data
* (typically directory updates). Which then must be flushed and * (typically directory updates). Which then must be flushed and
* logged before we can write the unmount record. * 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 { do {
xfs_reclaim_inodes(mp, SYNC_WAIT);
xfs_sync_attr(mp, SYNC_WAIT); xfs_sync_attr(mp, SYNC_WAIT);
pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
if (!pincount) { if (!pincount) {
@ -575,7 +569,7 @@ xfs_flush_inodes(
igrab(inode); igrab(inode);
xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work, &completion); xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work, &completion);
wait_for_completion(&completion); wait_for_completion(&completion);
xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); xfs_log_force(ip->i_mount, XFS_LOG_SYNC);
} }
/* /*
@ -591,8 +585,8 @@ xfs_sync_worker(
int error; int error;
if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); xfs_log_force(mp, 0);
xfs_reclaim_inodes(mp, XFS_IFLUSH_DELWRI_ELSE_ASYNC); xfs_reclaim_inodes(mp, 0);
/* dgc: errors ignored here */ /* dgc: errors ignored here */
error = xfs_qm_sync(mp, SYNC_TRYLOCK); error = xfs_qm_sync(mp, SYNC_TRYLOCK);
error = xfs_sync_fsdata(mp, SYNC_TRYLOCK); error = xfs_sync_fsdata(mp, SYNC_TRYLOCK);
@ -690,16 +684,17 @@ void
xfs_inode_set_reclaim_tag( xfs_inode_set_reclaim_tag(
xfs_inode_t *ip) xfs_inode_t *ip)
{ {
xfs_mount_t *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); struct xfs_perag *pag;
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
read_lock(&pag->pag_ici_lock); read_lock(&pag->pag_ici_lock);
spin_lock(&ip->i_flags_lock); spin_lock(&ip->i_flags_lock);
__xfs_inode_set_reclaim_tag(pag, ip); __xfs_inode_set_reclaim_tag(pag, ip);
__xfs_iflags_set(ip, XFS_IRECLAIMABLE); __xfs_iflags_set(ip, XFS_IRECLAIMABLE);
spin_unlock(&ip->i_flags_lock); spin_unlock(&ip->i_flags_lock);
read_unlock(&pag->pag_ici_lock); read_unlock(&pag->pag_ici_lock);
xfs_put_perag(mp, pag); xfs_perag_put(pag);
} }
void void
@ -712,12 +707,64 @@ __xfs_inode_clear_reclaim_tag(
XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
} }
/*
* 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:
*
*
* inode state iflush ret required action
* --------------- ---------- ---------------
* bad - reclaim
* shutdown EIO unpin and reclaim
* clean, unpinned 0 reclaim
* 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
*
* (*) 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. 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.
*
* Hence the order of actions after gaining the locks should be:
* bad => reclaim
* shutdown => unpin and reclaim
* pinned, delwri => requeue
* pinned, sync => unpin
* stale => reclaim
* clean => reclaim
* dirty, delwri => flush and requeue
* dirty, sync => flush, wait and reclaim
*/
STATIC int STATIC int
xfs_reclaim_inode( xfs_reclaim_inode(
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_perag *pag, struct xfs_perag *pag,
int sync_mode) int sync_mode)
{ {
int error = 0;
/* /*
* The radix tree lock here protects a thread in xfs_iget from racing * The radix tree lock here protects a thread in xfs_iget from racing
* with us starting reclaim on the inode. Once we have the * with us starting reclaim on the inode. Once we have the
@ -735,33 +782,70 @@ xfs_reclaim_inode(
spin_unlock(&ip->i_flags_lock); spin_unlock(&ip->i_flags_lock);
write_unlock(&pag->pag_ici_lock); write_unlock(&pag->pag_ici_lock);
/*
* If the inode is still dirty, then flush it out. If the inode
* is not in the AIL, then it will be OK to flush it delwri as
* long as xfs_iflush() does not keep any references to the inode.
* We leave that decision up to xfs_iflush() since it has the
* knowledge of whether it's OK to simply do a delwri flush of
* the inode or whether we need to wait until the inode is
* pulled from the AIL.
* We get the flush lock regardless, though, just to make sure
* we don't free it while it is being flushed.
*/
xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_iflock(ip); if (!xfs_iflock_nowait(ip)) {
if (!(sync_mode & SYNC_WAIT))
/* goto out;
* In the case of a forced shutdown we rely on xfs_iflush() to
* wait for the inode to be unpinned before returning an error.
*/
if (!is_bad_inode(VFS_I(ip)) && xfs_iflush(ip, sync_mode) == 0) {
/* synchronize with xfs_iflush_done */
xfs_iflock(ip); xfs_iflock(ip);
xfs_ifunlock(ip);
} }
if (is_bad_inode(VFS_I(ip)))
goto reclaim;
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
xfs_iunpin_wait(ip);
goto reclaim;
}
if (xfs_ipincount(ip)) {
if (!(sync_mode & SYNC_WAIT)) {
xfs_ifunlock(ip);
goto out;
}
xfs_iunpin_wait(ip);
}
if (xfs_iflags_test(ip, XFS_ISTALE))
goto reclaim;
if (xfs_inode_clean(ip))
goto reclaim;
/* Now we have an inode that needs flushing */
error = xfs_iflush(ip, sync_mode);
if (sync_mode & SYNC_WAIT) {
xfs_iflock(ip);
goto reclaim;
}
/*
* 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 relcaim the inode and
* pass on the error.
*/
if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount)) {
xfs_fs_cmn_err(CE_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;
reclaim:
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_ireclaim(ip); xfs_ireclaim(ip);
return 0; return error;
} }
int int

View file

@ -37,7 +37,6 @@ void xfs_syncd_stop(struct xfs_mount *mp);
int xfs_sync_attr(struct xfs_mount *mp, int flags); int xfs_sync_attr(struct xfs_mount *mp, int flags);
int xfs_sync_data(struct xfs_mount *mp, int flags); int xfs_sync_data(struct xfs_mount *mp, int flags);
int xfs_sync_fsdata(struct xfs_mount *mp, int flags);
int xfs_quiesce_data(struct xfs_mount *mp); int xfs_quiesce_data(struct xfs_mount *mp);
void xfs_quiesce_attr(struct xfs_mount *mp); void xfs_quiesce_attr(struct xfs_mount *mp);

View file

@ -78,6 +78,33 @@ DECLARE_EVENT_CLASS(xfs_attr_list_class,
) )
) )
#define DEFINE_PERAG_REF_EVENT(name) \
TRACE_EVENT(name, \
TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, \
unsigned long caller_ip), \
TP_ARGS(mp, agno, refcount, caller_ip), \
TP_STRUCT__entry( \
__field(dev_t, dev) \
__field(xfs_agnumber_t, agno) \
__field(int, refcount) \
__field(unsigned long, caller_ip) \
), \
TP_fast_assign( \
__entry->dev = mp->m_super->s_dev; \
__entry->agno = agno; \
__entry->refcount = refcount; \
__entry->caller_ip = caller_ip; \
), \
TP_printk("dev %d:%d agno %u refcount %d caller %pf", \
MAJOR(__entry->dev), MINOR(__entry->dev), \
__entry->agno, \
__entry->refcount, \
(char *)__entry->caller_ip) \
);
DEFINE_PERAG_REF_EVENT(xfs_perag_get)
DEFINE_PERAG_REF_EVENT(xfs_perag_put)
#define DEFINE_ATTR_LIST_EVENT(name) \ #define DEFINE_ATTR_LIST_EVENT(name) \
DEFINE_EVENT(xfs_attr_list_class, name, \ DEFINE_EVENT(xfs_attr_list_class, name, \
TP_PROTO(struct xfs_attr_list_context *ctx), \ TP_PROTO(struct xfs_attr_list_context *ctx), \
@ -456,6 +483,7 @@ DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock_stale); DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock_stale);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_committed); DEFINE_BUF_ITEM_EVENT(xfs_buf_item_committed);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_push); 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);
DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf_recur); DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf_recur);
DEFINE_BUF_ITEM_EVENT(xfs_trans_getsb); DEFINE_BUF_ITEM_EVENT(xfs_trans_getsb);
@ -1414,6 +1442,59 @@ TRACE_EVENT(xfs_dir2_leafn_moveents,
__entry->count) __entry->count)
); );
#define XFS_SWAPEXT_INODES \
{ 0, "target" }, \
{ 1, "temp" }
#define XFS_INODE_FORMAT_STR \
{ 0, "invalid" }, \
{ 1, "local" }, \
{ 2, "extent" }, \
{ 3, "btree" }
DECLARE_EVENT_CLASS(xfs_swap_extent_class,
TP_PROTO(struct xfs_inode *ip, int which),
TP_ARGS(ip, which),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(int, which)
__field(xfs_ino_t, ino)
__field(int, format)
__field(int, nex)
__field(int, max_nex)
__field(int, broot_size)
__field(int, fork_off)
),
TP_fast_assign(
__entry->dev = VFS_I(ip)->i_sb->s_dev;
__entry->which = which;
__entry->ino = ip->i_ino;
__entry->format = ip->i_d.di_format;
__entry->nex = ip->i_d.di_nextents;
__entry->max_nex = ip->i_df.if_ext_max;
__entry->broot_size = ip->i_df.if_broot_bytes;
__entry->fork_off = XFS_IFORK_BOFF(ip);
),
TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %d, "
"Max in-fork extents %d, broot size %d, fork offset %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__print_symbolic(__entry->which, XFS_SWAPEXT_INODES),
__print_symbolic(__entry->format, XFS_INODE_FORMAT_STR),
__entry->nex,
__entry->max_nex,
__entry->broot_size,
__entry->fork_off)
)
#define DEFINE_SWAPEXT_EVENT(name) \
DEFINE_EVENT(xfs_swap_extent_class, name, \
TP_PROTO(struct xfs_inode *ip, int which), \
TP_ARGS(ip, which))
DEFINE_SWAPEXT_EVENT(xfs_swap_extent_before);
DEFINE_SWAPEXT_EVENT(xfs_swap_extent_after);
#endif /* _TRACE_XFS_H */ #endif /* _TRACE_XFS_H */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH

View file

@ -45,7 +45,7 @@ xfs_xattr_get(struct dentry *dentry, const char *name,
value = NULL; value = NULL;
} }
error = -xfs_attr_get(ip, name, value, &asize, xflags); error = -xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
if (error) if (error)
return error; return error;
return asize; return asize;
@ -67,8 +67,9 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
xflags |= ATTR_REPLACE; xflags |= ATTR_REPLACE;
if (!value) if (!value)
return -xfs_attr_remove(ip, name, xflags); return -xfs_attr_remove(ip, (unsigned char *)name, xflags);
return -xfs_attr_set(ip, name, (void *)value, size, xflags); return -xfs_attr_set(ip, (unsigned char *)name,
(void *)value, size, xflags);
} }
static struct xattr_handler xfs_xattr_user_handler = { static struct xattr_handler xfs_xattr_user_handler = {
@ -124,8 +125,13 @@ static const char *xfs_xattr_prefix(int flags)
} }
static int static int
xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags, xfs_xattr_put_listent(
char *name, int namelen, int valuelen, char *value) struct xfs_attr_list_context *context,
int flags,
unsigned char *name,
int namelen,
int valuelen,
unsigned char *value)
{ {
unsigned int prefix_len = xfs_xattr_prefix_len(flags); unsigned int prefix_len = xfs_xattr_prefix_len(flags);
char *offset; char *offset;
@ -148,7 +154,7 @@ xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags,
offset = (char *)context->alist + context->count; offset = (char *)context->alist + context->count;
strncpy(offset, xfs_xattr_prefix(flags), prefix_len); strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
offset += prefix_len; offset += prefix_len;
strncpy(offset, name, namelen); /* real name */ strncpy(offset, (char *)name, namelen); /* real name */
offset += namelen; offset += namelen;
*offset = '\0'; *offset = '\0';
context->count += prefix_len + namelen + 1; context->count += prefix_len + namelen + 1;
@ -156,8 +162,13 @@ xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags,
} }
static int static int
xfs_xattr_put_listent_sizes(struct xfs_attr_list_context *context, int flags, xfs_xattr_put_listent_sizes(
char *name, int namelen, int valuelen, char *value) struct xfs_attr_list_context *context,
int flags,
unsigned char *name,
int namelen,
int valuelen,
unsigned char *value)
{ {
context->count += xfs_xattr_prefix_len(flags) + namelen + 1; context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
return 0; return 0;

View file

@ -1187,7 +1187,7 @@ xfs_qm_dqflush(
* block, nada. * block, nada.
*/ */
if (!XFS_DQ_IS_DIRTY(dqp) || if (!XFS_DQ_IS_DIRTY(dqp) ||
(!(flags & XFS_QMOPT_SYNC) && atomic_read(&dqp->q_pincount) > 0)) { (!(flags & SYNC_WAIT) && atomic_read(&dqp->q_pincount) > 0)) {
xfs_dqfunlock(dqp); xfs_dqfunlock(dqp);
return 0; return 0;
} }
@ -1248,23 +1248,20 @@ xfs_qm_dqflush(
*/ */
if (XFS_BUF_ISPINNED(bp)) { if (XFS_BUF_ISPINNED(bp)) {
trace_xfs_dqflush_force(dqp); trace_xfs_dqflush_force(dqp);
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); xfs_log_force(mp, 0);
} }
if (flags & XFS_QMOPT_DELWRI) { if (flags & SYNC_WAIT)
xfs_bdwrite(mp, bp);
} else if (flags & XFS_QMOPT_ASYNC) {
error = xfs_bawrite(mp, bp);
} else {
error = xfs_bwrite(mp, bp); error = xfs_bwrite(mp, bp);
} else
xfs_bdwrite(mp, bp);
trace_xfs_dqflush_done(dqp); trace_xfs_dqflush_done(dqp);
/* /*
* dqp is still locked, but caller is free to unlock it now. * dqp is still locked, but caller is free to unlock it now.
*/ */
return (error); return error;
} }
@ -1445,7 +1442,7 @@ xfs_qm_dqpurge(
* We don't care about getting disk errors here. We need * We don't care about getting disk errors here. We need
* to purge this dquot anyway, so we go ahead regardless. * to purge this dquot anyway, so we go ahead regardless.
*/ */
error = xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC); error = xfs_qm_dqflush(dqp, SYNC_WAIT);
if (error) if (error)
xfs_fs_cmn_err(CE_WARN, mp, xfs_fs_cmn_err(CE_WARN, mp,
"xfs_qm_dqpurge: dquot %p flush failed", dqp); "xfs_qm_dqpurge: dquot %p flush failed", dqp);
@ -1529,25 +1526,17 @@ xfs_qm_dqflock_pushbuf_wait(
* the flush lock when the I/O completes. * the flush lock when the I/O completes.
*/ */
bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno, bp = xfs_incore(dqp->q_mount->m_ddev_targp, dqp->q_blkno,
XFS_QI_DQCHUNKLEN(dqp->q_mount), XFS_QI_DQCHUNKLEN(dqp->q_mount), XBF_TRYLOCK);
XFS_INCORE_TRYLOCK); if (!bp)
if (bp != NULL) { goto out_lock;
if (XFS_BUF_ISDELAYWRITE(bp)) {
int error; if (XFS_BUF_ISDELAYWRITE(bp)) {
if (XFS_BUF_ISPINNED(bp)) { if (XFS_BUF_ISPINNED(bp))
xfs_log_force(dqp->q_mount, xfs_log_force(dqp->q_mount, 0);
(xfs_lsn_t)0, xfs_buf_delwri_promote(bp);
XFS_LOG_FORCE); wake_up_process(bp->b_target->bt_task);
}
error = xfs_bawrite(dqp->q_mount, bp);
if (error)
xfs_fs_cmn_err(CE_WARN, dqp->q_mount,
"xfs_qm_dqflock_pushbuf_wait: "
"pushbuf error %d on dqp %p, bp %p",
error, dqp, bp);
} else {
xfs_buf_relse(bp);
}
} }
xfs_buf_relse(bp);
out_lock:
xfs_dqflock(dqp); xfs_dqflock(dqp);
} }

View file

@ -74,11 +74,11 @@ xfs_qm_dquot_logitem_format(
logvec->i_addr = (xfs_caddr_t)&logitem->qli_format; logvec->i_addr = (xfs_caddr_t)&logitem->qli_format;
logvec->i_len = sizeof(xfs_dq_logformat_t); logvec->i_len = sizeof(xfs_dq_logformat_t);
XLOG_VEC_SET_TYPE(logvec, XLOG_REG_TYPE_QFORMAT); logvec->i_type = XLOG_REG_TYPE_QFORMAT;
logvec++; logvec++;
logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core; logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core;
logvec->i_len = sizeof(xfs_disk_dquot_t); logvec->i_len = sizeof(xfs_disk_dquot_t);
XLOG_VEC_SET_TYPE(logvec, XLOG_REG_TYPE_DQUOT); logvec->i_type = XLOG_REG_TYPE_DQUOT;
ASSERT(2 == logitem->qli_item.li_desc->lid_size); ASSERT(2 == logitem->qli_item.li_desc->lid_size);
logitem->qli_format.qlf_size = 2; logitem->qli_format.qlf_size = 2;
@ -153,7 +153,7 @@ xfs_qm_dquot_logitem_push(
* lock without sleeping, then there must not have been * lock without sleeping, then there must not have been
* anyone in the process of flushing the dquot. * anyone in the process of flushing the dquot.
*/ */
error = xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); error = xfs_qm_dqflush(dqp, 0);
if (error) if (error)
xfs_fs_cmn_err(CE_WARN, dqp->q_mount, xfs_fs_cmn_err(CE_WARN, dqp->q_mount,
"xfs_qm_dquot_logitem_push: push error %d on dqp %p", "xfs_qm_dquot_logitem_push: push error %d on dqp %p",
@ -190,7 +190,7 @@ xfs_qm_dqunpin_wait(
/* /*
* Give the log a push so we don't wait here too long. * Give the log a push so we don't wait here too long.
*/ */
xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE); xfs_log_force(dqp->q_mount, 0);
wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0));
} }
@ -212,18 +212,10 @@ xfs_qm_dquot_logitem_pushbuf(
xfs_dquot_t *dqp; xfs_dquot_t *dqp;
xfs_mount_t *mp; xfs_mount_t *mp;
xfs_buf_t *bp; xfs_buf_t *bp;
uint dopush;
dqp = qip->qli_dquot; dqp = qip->qli_dquot;
ASSERT(XFS_DQ_IS_LOCKED(dqp)); ASSERT(XFS_DQ_IS_LOCKED(dqp));
/*
* The qli_pushbuf_flag keeps others from
* trying to duplicate our effort.
*/
ASSERT(qip->qli_pushbuf_flag != 0);
ASSERT(qip->qli_push_owner == current_pid());
/* /*
* If flushlock isn't locked anymore, chances are that the * If flushlock isn't locked anymore, chances are that the
* inode flush completed and the inode was taken off the AIL. * inode flush completed and the inode was taken off the AIL.
@ -231,49 +223,20 @@ xfs_qm_dquot_logitem_pushbuf(
*/ */
if (completion_done(&dqp->q_flush) || if (completion_done(&dqp->q_flush) ||
((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
qip->qli_pushbuf_flag = 0;
xfs_dqunlock(dqp); xfs_dqunlock(dqp);
return; return;
} }
mp = dqp->q_mount; mp = dqp->q_mount;
bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno, bp = xfs_incore(mp->m_ddev_targp, qip->qli_format.qlf_blkno,
XFS_QI_DQCHUNKLEN(mp), XFS_QI_DQCHUNKLEN(mp), XBF_TRYLOCK);
XFS_INCORE_TRYLOCK);
if (bp != NULL) {
if (XFS_BUF_ISDELAYWRITE(bp)) {
dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
!completion_done(&dqp->q_flush));
qip->qli_pushbuf_flag = 0;
xfs_dqunlock(dqp);
if (XFS_BUF_ISPINNED(bp)) {
xfs_log_force(mp, (xfs_lsn_t)0,
XFS_LOG_FORCE);
}
if (dopush) {
int error;
#ifdef XFSRACEDEBUG
delay_for_intr();
delay(300);
#endif
error = xfs_bawrite(mp, bp);
if (error)
xfs_fs_cmn_err(CE_WARN, mp,
"xfs_qm_dquot_logitem_pushbuf: pushbuf error %d on qip %p, bp %p",
error, qip, bp);
} else {
xfs_buf_relse(bp);
}
} else {
qip->qli_pushbuf_flag = 0;
xfs_dqunlock(dqp);
xfs_buf_relse(bp);
}
return;
}
qip->qli_pushbuf_flag = 0;
xfs_dqunlock(dqp); xfs_dqunlock(dqp);
if (!bp)
return;
if (XFS_BUF_ISDELAYWRITE(bp))
xfs_buf_delwri_promote(bp);
xfs_buf_relse(bp);
return;
} }
/* /*
@ -291,50 +254,24 @@ xfs_qm_dquot_logitem_trylock(
xfs_dq_logitem_t *qip) xfs_dq_logitem_t *qip)
{ {
xfs_dquot_t *dqp; xfs_dquot_t *dqp;
uint retval;
dqp = qip->qli_dquot; dqp = qip->qli_dquot;
if (atomic_read(&dqp->q_pincount) > 0) if (atomic_read(&dqp->q_pincount) > 0)
return (XFS_ITEM_PINNED); return XFS_ITEM_PINNED;
if (! xfs_qm_dqlock_nowait(dqp)) if (! xfs_qm_dqlock_nowait(dqp))
return (XFS_ITEM_LOCKED); return XFS_ITEM_LOCKED;
retval = XFS_ITEM_SUCCESS;
if (!xfs_dqflock_nowait(dqp)) { if (!xfs_dqflock_nowait(dqp)) {
/* /*
* The dquot is already being flushed. It may have been * dquot has already been flushed to the backing buffer,
* flushed delayed write, however, and we don't want to * leave it locked, pushbuf routine will unlock it.
* get stuck waiting for that to complete. So, we want to check
* to see if we can lock the dquot's buffer without sleeping.
* If we can and it is marked for delayed write, then we
* hold it and send it out from the push routine. We don't
* want to do that now since we might sleep in the device
* strategy routine. We also don't want to grab the buffer lock
* here because we'd like not to call into the buffer cache
* while holding the AIL lock.
* Make sure to only return PUSHBUF if we set pushbuf_flag
* ourselves. If someone else is doing it then we don't
* want to go to the push routine and duplicate their efforts.
*/ */
if (qip->qli_pushbuf_flag == 0) { return XFS_ITEM_PUSHBUF;
qip->qli_pushbuf_flag = 1;
ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno);
#ifdef DEBUG
qip->qli_push_owner = current_pid();
#endif
/*
* The dquot is left locked.
*/
retval = XFS_ITEM_PUSHBUF;
} else {
retval = XFS_ITEM_FLUSHING;
xfs_dqunlock_nonotify(dqp);
}
} }
ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL); ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL);
return (retval); return XFS_ITEM_SUCCESS;
} }
@ -467,7 +404,7 @@ xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t *qf,
log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format); log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format);
log_vector->i_len = sizeof(xfs_qoff_logitem_t); log_vector->i_len = sizeof(xfs_qoff_logitem_t);
XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_QUOTAOFF); log_vector->i_type = XLOG_REG_TYPE_QUOTAOFF;
qf->qql_format.qf_size = 1; qf->qql_format.qf_size = 1;
} }

View file

@ -27,10 +27,6 @@ typedef struct xfs_dq_logitem {
xfs_log_item_t qli_item; /* common portion */ xfs_log_item_t qli_item; /* common portion */
struct xfs_dquot *qli_dquot; /* dquot ptr */ struct xfs_dquot *qli_dquot; /* dquot ptr */
xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ xfs_lsn_t qli_flush_lsn; /* lsn at last flush */
unsigned short qli_pushbuf_flag; /* 1 bit used in push_ail */
#ifdef DEBUG
uint64_t qli_push_owner;
#endif
xfs_dq_logformat_t qli_format; /* logged structure */ xfs_dq_logformat_t qli_format; /* logged structure */
} xfs_dq_logitem_t; } xfs_dq_logitem_t;

View file

@ -118,9 +118,14 @@ xfs_Gqm_init(void)
*/ */
udqhash = kmem_zalloc_greedy(&hsize, udqhash = kmem_zalloc_greedy(&hsize,
XFS_QM_HASHSIZE_LOW * sizeof(xfs_dqhash_t), XFS_QM_HASHSIZE_LOW * sizeof(xfs_dqhash_t),
XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t), XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t));
KM_SLEEP | KM_MAYFAIL | KM_LARGE); if (!udqhash)
gdqhash = kmem_zalloc(hsize, KM_SLEEP | KM_LARGE); goto out;
gdqhash = kmem_zalloc_large(hsize);
if (!gdqhash)
goto out_free_udqhash;
hsize /= sizeof(xfs_dqhash_t); hsize /= sizeof(xfs_dqhash_t);
ndquot = hsize << 8; ndquot = hsize << 8;
@ -170,6 +175,11 @@ xfs_Gqm_init(void)
mutex_init(&qcheck_lock); mutex_init(&qcheck_lock);
#endif #endif
return xqm; return xqm;
out_free_udqhash:
kmem_free_large(udqhash);
out:
return NULL;
} }
/* /*
@ -189,8 +199,8 @@ xfs_qm_destroy(
xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i])); xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
} }
kmem_free(xqm->qm_usr_dqhtable); kmem_free_large(xqm->qm_usr_dqhtable);
kmem_free(xqm->qm_grp_dqhtable); kmem_free_large(xqm->qm_grp_dqhtable);
xqm->qm_usr_dqhtable = NULL; xqm->qm_usr_dqhtable = NULL;
xqm->qm_grp_dqhtable = NULL; xqm->qm_grp_dqhtable = NULL;
xqm->qm_dqhashmask = 0; xqm->qm_dqhashmask = 0;
@ -219,8 +229,12 @@ xfs_qm_hold_quotafs_ref(
*/ */
mutex_lock(&xfs_Gqm_lock); mutex_lock(&xfs_Gqm_lock);
if (xfs_Gqm == NULL) if (!xfs_Gqm) {
xfs_Gqm = xfs_Gqm_init(); xfs_Gqm = xfs_Gqm_init();
if (!xfs_Gqm)
return ENOMEM;
}
/* /*
* We can keep a list of all filesystems with quotas mounted for * We can keep a list of all filesystems with quotas mounted for
* debugging and statistical purposes, but ... * debugging and statistical purposes, but ...
@ -436,7 +450,7 @@ xfs_qm_unmount_quotas(
STATIC int STATIC int
xfs_qm_dqflush_all( xfs_qm_dqflush_all(
xfs_mount_t *mp, xfs_mount_t *mp,
int flags) int sync_mode)
{ {
int recl; int recl;
xfs_dquot_t *dqp; xfs_dquot_t *dqp;
@ -472,7 +486,7 @@ again:
* across a disk write. * across a disk write.
*/ */
xfs_qm_mplist_unlock(mp); xfs_qm_mplist_unlock(mp);
error = xfs_qm_dqflush(dqp, flags); error = xfs_qm_dqflush(dqp, sync_mode);
xfs_dqunlock(dqp); xfs_dqunlock(dqp);
if (error) if (error)
return error; return error;
@ -912,13 +926,11 @@ xfs_qm_sync(
{ {
int recl, restarts; int recl, restarts;
xfs_dquot_t *dqp; xfs_dquot_t *dqp;
uint flush_flags;
int error; int error;
if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp)) if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
return 0; return 0;
flush_flags = (flags & SYNC_WAIT) ? XFS_QMOPT_SYNC : XFS_QMOPT_DELWRI;
restarts = 0; restarts = 0;
again: again:
@ -978,7 +990,7 @@ xfs_qm_sync(
* across a disk write * across a disk write
*/ */
xfs_qm_mplist_unlock(mp); xfs_qm_mplist_unlock(mp);
error = xfs_qm_dqflush(dqp, flush_flags); error = xfs_qm_dqflush(dqp, flags);
xfs_dqunlock(dqp); xfs_dqunlock(dqp);
if (error && XFS_FORCED_SHUTDOWN(mp)) if (error && XFS_FORCED_SHUTDOWN(mp))
return 0; /* Need to prevent umount failure */ return 0; /* Need to prevent umount failure */
@ -1782,7 +1794,7 @@ xfs_qm_quotacheck(
* successfully. * successfully.
*/ */
if (!error) if (!error)
error = xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI); error = xfs_qm_dqflush_all(mp, 0);
/* /*
* We can get this error if we couldn't do a dquot allocation inside * We can get this error if we couldn't do a dquot allocation inside
@ -2004,7 +2016,7 @@ xfs_qm_shake_freelist(
* We flush it delayed write, so don't bother * We flush it delayed write, so don't bother
* releasing the mplock. * releasing the mplock.
*/ */
error = xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); error = xfs_qm_dqflush(dqp, 0);
if (error) { if (error) {
xfs_fs_cmn_err(CE_WARN, dqp->q_mount, xfs_fs_cmn_err(CE_WARN, dqp->q_mount,
"xfs_qm_dqflush_all: dquot %p flush failed", dqp); "xfs_qm_dqflush_all: dquot %p flush failed", dqp);
@ -2187,7 +2199,7 @@ xfs_qm_dqreclaim_one(void)
* We flush it delayed write, so don't bother * We flush it delayed write, so don't bother
* releasing the freelist lock. * releasing the freelist lock.
*/ */
error = xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); error = xfs_qm_dqflush(dqp, 0);
if (error) { if (error) {
xfs_fs_cmn_err(CE_WARN, dqp->q_mount, xfs_fs_cmn_err(CE_WARN, dqp->q_mount,
"xfs_qm_dqreclaim: dquot %p flush failed", dqp); "xfs_qm_dqreclaim: dquot %p flush failed", dqp);

View file

@ -59,7 +59,7 @@ xfs_fill_statvfs_from_dquot(
be64_to_cpu(dp->d_blk_hardlimit); be64_to_cpu(dp->d_blk_hardlimit);
if (limit && statp->f_blocks > limit) { if (limit && statp->f_blocks > limit) {
statp->f_blocks = limit; statp->f_blocks = limit;
statp->f_bfree = statp->f_bfree = statp->f_bavail =
(statp->f_blocks > be64_to_cpu(dp->d_bcount)) ? (statp->f_blocks > be64_to_cpu(dp->d_bcount)) ?
(statp->f_blocks - be64_to_cpu(dp->d_bcount)) : 0; (statp->f_blocks - be64_to_cpu(dp->d_bcount)) : 0;
} }

View file

@ -1192,9 +1192,9 @@ xfs_qm_internalqcheck(
if (! XFS_IS_QUOTA_ON(mp)) if (! XFS_IS_QUOTA_ON(mp))
return XFS_ERROR(ESRCH); return XFS_ERROR(ESRCH);
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); xfs_log_force(mp, XFS_LOG_SYNC);
XFS_bflush(mp->m_ddev_targp); XFS_bflush(mp->m_ddev_targp);
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); xfs_log_force(mp, XFS_LOG_SYNC);
XFS_bflush(mp->m_ddev_targp); XFS_bflush(mp->m_ddev_targp);
mutex_lock(&qcheck_lock); mutex_lock(&qcheck_lock);

View file

@ -589,12 +589,18 @@ xfs_trans_unreserve_and_mod_dquots(
} }
} }
STATIC int STATIC void
xfs_quota_error(uint flags) xfs_quota_warn(
struct xfs_mount *mp,
struct xfs_dquot *dqp,
int type)
{ {
if (flags & XFS_QMOPT_ENOSPC) /* no warnings for project quotas - we just return ENOSPC later */
return ENOSPC; if (dqp->dq_flags & XFS_DQ_PROJ)
return EDQUOT; return;
quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
type);
} }
/* /*
@ -612,7 +618,6 @@ xfs_trans_dqresv(
long ninos, long ninos,
uint flags) uint flags)
{ {
int error;
xfs_qcnt_t hardlimit; xfs_qcnt_t hardlimit;
xfs_qcnt_t softlimit; xfs_qcnt_t softlimit;
time_t timer; time_t timer;
@ -649,7 +654,6 @@ xfs_trans_dqresv(
warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount); warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount);
resbcountp = &dqp->q_res_rtbcount; resbcountp = &dqp->q_res_rtbcount;
} }
error = 0;
if ((flags & XFS_QMOPT_FORCE_RES) == 0 && if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
dqp->q_core.d_id && dqp->q_core.d_id &&
@ -667,18 +671,20 @@ xfs_trans_dqresv(
* nblks. * nblks.
*/ */
if (hardlimit > 0ULL && if (hardlimit > 0ULL &&
(hardlimit <= nblks + *resbcountp)) { hardlimit <= nblks + *resbcountp) {
error = xfs_quota_error(flags); xfs_quota_warn(mp, dqp, QUOTA_NL_BHARDWARN);
goto error_return; goto error_return;
} }
if (softlimit > 0ULL && if (softlimit > 0ULL &&
(softlimit <= nblks + *resbcountp)) { softlimit <= nblks + *resbcountp) {
if ((timer != 0 && get_seconds() > timer) || if ((timer != 0 && get_seconds() > timer) ||
(warns != 0 && warns >= warnlimit)) { (warns != 0 && warns >= warnlimit)) {
error = xfs_quota_error(flags); xfs_quota_warn(mp, dqp,
QUOTA_NL_BSOFTLONGWARN);
goto error_return; goto error_return;
} }
xfs_quota_warn(mp, dqp, QUOTA_NL_BSOFTWARN);
} }
} }
if (ninos > 0) { if (ninos > 0) {
@ -692,15 +698,19 @@ xfs_trans_dqresv(
softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit); softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
if (!softlimit) if (!softlimit)
softlimit = q->qi_isoftlimit; softlimit = q->qi_isoftlimit;
if (hardlimit > 0ULL && count >= hardlimit) { if (hardlimit > 0ULL && count >= hardlimit) {
error = xfs_quota_error(flags); xfs_quota_warn(mp, dqp, QUOTA_NL_IHARDWARN);
goto error_return; goto error_return;
} else if (softlimit > 0ULL && count >= softlimit) { }
if ((timer != 0 && get_seconds() > timer) || if (softlimit > 0ULL && count >= softlimit) {
if ((timer != 0 && get_seconds() > timer) ||
(warns != 0 && warns >= warnlimit)) { (warns != 0 && warns >= warnlimit)) {
error = xfs_quota_error(flags); xfs_quota_warn(mp, dqp,
QUOTA_NL_ISOFTLONGWARN);
goto error_return; goto error_return;
} }
xfs_quota_warn(mp, dqp, QUOTA_NL_ISOFTWARN);
} }
} }
} }
@ -736,9 +746,14 @@ xfs_trans_dqresv(
ASSERT(dqp->q_res_rtbcount >= be64_to_cpu(dqp->q_core.d_rtbcount)); ASSERT(dqp->q_res_rtbcount >= be64_to_cpu(dqp->q_core.d_rtbcount));
ASSERT(dqp->q_res_icount >= be64_to_cpu(dqp->q_core.d_icount)); ASSERT(dqp->q_res_icount >= be64_to_cpu(dqp->q_core.d_icount));
xfs_dqunlock(dqp);
return 0;
error_return: error_return:
xfs_dqunlock(dqp); xfs_dqunlock(dqp);
return error; if (flags & XFS_QMOPT_ENOSPC)
return ENOSPC;
return EDQUOT;
} }

View file

@ -36,8 +36,8 @@ struct xfs_acl {
}; };
/* On-disk XFS extended attribute names */ /* On-disk XFS extended attribute names */
#define SGI_ACL_FILE "SGI_ACL_FILE" #define SGI_ACL_FILE (unsigned char *)"SGI_ACL_FILE"
#define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" #define SGI_ACL_DEFAULT (unsigned char *)"SGI_ACL_DEFAULT"
#define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) #define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1)
#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1)

View file

@ -187,17 +187,13 @@ typedef struct xfs_perag_busy {
/* /*
* Per-ag incore structure, copies of information in agf and agi, * Per-ag incore structure, copies of information in agf and agi,
* to improve the performance of allocation group selection. * to improve the performance of allocation group selection.
*
* pick sizes which fit in allocation buckets well
*/ */
#if (BITS_PER_LONG == 32)
#define XFS_PAGB_NUM_SLOTS 84
#elif (BITS_PER_LONG == 64)
#define XFS_PAGB_NUM_SLOTS 128 #define XFS_PAGB_NUM_SLOTS 128
#endif
typedef struct xfs_perag typedef struct xfs_perag {
{ struct xfs_mount *pag_mount; /* owner filesystem */
xfs_agnumber_t pag_agno; /* AG this structure belongs to */
atomic_t pag_ref; /* perag reference count */
char pagf_init; /* this agf's entry is initialized */ char pagf_init; /* this agf's entry is initialized */
char pagi_init; /* this agi's entry is initialized */ char pagi_init; /* this agi's entry is initialized */
char pagf_metadata; /* the agf is preferred to be metadata */ char pagf_metadata; /* the agf is preferred to be metadata */
@ -210,8 +206,6 @@ typedef struct xfs_perag
__uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */ __uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */
xfs_agino_t pagi_freecount; /* number of free inodes */ xfs_agino_t pagi_freecount; /* number of free inodes */
xfs_agino_t pagi_count; /* number of allocated inodes */ xfs_agino_t pagi_count; /* number of allocated inodes */
int pagb_count; /* pagb slots in use */
xfs_perag_busy_t *pagb_list; /* unstable blocks */
/* /*
* Inode allocation search lookup optimisation. * Inode allocation search lookup optimisation.
@ -230,6 +224,8 @@ typedef struct xfs_perag
rwlock_t pag_ici_lock; /* incore inode lock */ rwlock_t pag_ici_lock; /* incore inode lock */
struct radix_tree_root pag_ici_root; /* incore inode cache root */ struct radix_tree_root pag_ici_root; /* incore inode cache root */
#endif #endif
int pagb_count; /* pagb slots in use */
xfs_perag_busy_t pagb_list[XFS_PAGB_NUM_SLOTS]; /* unstable blocks */
} xfs_perag_t; } xfs_perag_t;
/* /*

View file

@ -1662,11 +1662,13 @@ xfs_free_ag_extent(
xfs_agf_t *agf; xfs_agf_t *agf;
xfs_perag_t *pag; /* per allocation group data */ xfs_perag_t *pag; /* per allocation group data */
pag = xfs_perag_get(mp, agno);
pag->pagf_freeblks += len;
xfs_perag_put(pag);
agf = XFS_BUF_TO_AGF(agbp); agf = XFS_BUF_TO_AGF(agbp);
pag = &mp->m_perag[agno];
be32_add_cpu(&agf->agf_freeblks, len); be32_add_cpu(&agf->agf_freeblks, len);
xfs_trans_agblocks_delta(tp, len); xfs_trans_agblocks_delta(tp, len);
pag->pagf_freeblks += len;
XFS_WANT_CORRUPTED_GOTO( XFS_WANT_CORRUPTED_GOTO(
be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_freeblks) <=
be32_to_cpu(agf->agf_length), be32_to_cpu(agf->agf_length),
@ -1969,10 +1971,12 @@ xfs_alloc_get_freelist(
xfs_trans_brelse(tp, agflbp); xfs_trans_brelse(tp, agflbp);
if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp)) if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))
agf->agf_flfirst = 0; agf->agf_flfirst = 0;
pag = &mp->m_perag[be32_to_cpu(agf->agf_seqno)];
pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
be32_add_cpu(&agf->agf_flcount, -1); be32_add_cpu(&agf->agf_flcount, -1);
xfs_trans_agflist_delta(tp, -1); xfs_trans_agflist_delta(tp, -1);
pag->pagf_flcount--; pag->pagf_flcount--;
xfs_perag_put(pag);
logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT; logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT;
if (btreeblk) { if (btreeblk) {
@ -2078,7 +2082,8 @@ xfs_alloc_put_freelist(
be32_add_cpu(&agf->agf_fllast, 1); be32_add_cpu(&agf->agf_fllast, 1);
if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp)) if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp))
agf->agf_fllast = 0; agf->agf_fllast = 0;
pag = &mp->m_perag[be32_to_cpu(agf->agf_seqno)];
pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
be32_add_cpu(&agf->agf_flcount, 1); be32_add_cpu(&agf->agf_flcount, 1);
xfs_trans_agflist_delta(tp, 1); xfs_trans_agflist_delta(tp, 1);
pag->pagf_flcount++; pag->pagf_flcount++;
@ -2089,6 +2094,7 @@ xfs_alloc_put_freelist(
pag->pagf_btreeblks--; pag->pagf_btreeblks--;
logflags |= XFS_AGF_BTREEBLKS; logflags |= XFS_AGF_BTREEBLKS;
} }
xfs_perag_put(pag);
xfs_alloc_log_agf(tp, agbp, logflags); xfs_alloc_log_agf(tp, agbp, logflags);
@ -2152,7 +2158,6 @@ xfs_read_agf(
xfs_trans_brelse(tp, *bpp); xfs_trans_brelse(tp, *bpp);
return XFS_ERROR(EFSCORRUPTED); return XFS_ERROR(EFSCORRUPTED);
} }
XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGF, XFS_AGF_REF); XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGF, XFS_AGF_REF);
return 0; return 0;
} }
@ -2175,7 +2180,7 @@ xfs_alloc_read_agf(
ASSERT(agno != NULLAGNUMBER); ASSERT(agno != NULLAGNUMBER);
error = xfs_read_agf(mp, tp, agno, error = xfs_read_agf(mp, tp, agno,
(flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0, (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XBF_TRYLOCK : 0,
bpp); bpp);
if (error) if (error)
return error; return error;
@ -2184,7 +2189,7 @@ xfs_alloc_read_agf(
ASSERT(!XFS_BUF_GETERROR(*bpp)); ASSERT(!XFS_BUF_GETERROR(*bpp));
agf = XFS_BUF_TO_AGF(*bpp); agf = XFS_BUF_TO_AGF(*bpp);
pag = &mp->m_perag[agno]; pag = xfs_perag_get(mp, agno);
if (!pag->pagf_init) { if (!pag->pagf_init) {
pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks); pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks);
pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks); pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks);
@ -2195,8 +2200,8 @@ xfs_alloc_read_agf(
pag->pagf_levels[XFS_BTNUM_CNTi] = pag->pagf_levels[XFS_BTNUM_CNTi] =
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]); be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]);
spin_lock_init(&pag->pagb_lock); spin_lock_init(&pag->pagb_lock);
pag->pagb_list = kmem_zalloc(XFS_PAGB_NUM_SLOTS * pag->pagb_count = 0;
sizeof(xfs_perag_busy_t), KM_SLEEP); memset(pag->pagb_list, 0, sizeof(pag->pagb_list));
pag->pagf_init = 1; pag->pagf_init = 1;
} }
#ifdef DEBUG #ifdef DEBUG
@ -2211,6 +2216,7 @@ xfs_alloc_read_agf(
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi])); be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]));
} }
#endif #endif
xfs_perag_put(pag);
return 0; return 0;
} }
@ -2270,8 +2276,7 @@ xfs_alloc_vextent(
* These three force us into a single a.g. * These three force us into a single a.g.
*/ */
args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
down_read(&mp->m_peraglock); args->pag = xfs_perag_get(mp, args->agno);
args->pag = &mp->m_perag[args->agno];
args->minleft = 0; args->minleft = 0;
error = xfs_alloc_fix_freelist(args, 0); error = xfs_alloc_fix_freelist(args, 0);
args->minleft = minleft; args->minleft = minleft;
@ -2280,14 +2285,12 @@ xfs_alloc_vextent(
goto error0; goto error0;
} }
if (!args->agbp) { if (!args->agbp) {
up_read(&mp->m_peraglock);
trace_xfs_alloc_vextent_noagbp(args); trace_xfs_alloc_vextent_noagbp(args);
break; break;
} }
args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
if ((error = xfs_alloc_ag_vextent(args))) if ((error = xfs_alloc_ag_vextent(args)))
goto error0; goto error0;
up_read(&mp->m_peraglock);
break; break;
case XFS_ALLOCTYPE_START_BNO: case XFS_ALLOCTYPE_START_BNO:
/* /*
@ -2339,9 +2342,8 @@ xfs_alloc_vextent(
* Loop over allocation groups twice; first time with * Loop over allocation groups twice; first time with
* trylock set, second time without. * trylock set, second time without.
*/ */
down_read(&mp->m_peraglock);
for (;;) { for (;;) {
args->pag = &mp->m_perag[args->agno]; args->pag = xfs_perag_get(mp, args->agno);
if (no_min) args->minleft = 0; if (no_min) args->minleft = 0;
error = xfs_alloc_fix_freelist(args, flags); error = xfs_alloc_fix_freelist(args, flags);
args->minleft = minleft; args->minleft = minleft;
@ -2400,8 +2402,8 @@ xfs_alloc_vextent(
} }
} }
} }
xfs_perag_put(args->pag);
} }
up_read(&mp->m_peraglock);
if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) { if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) {
if (args->agno == sagno) if (args->agno == sagno)
mp->m_agfrotor = (mp->m_agfrotor + 1) % mp->m_agfrotor = (mp->m_agfrotor + 1) %
@ -2427,9 +2429,10 @@ xfs_alloc_vextent(
args->len); args->len);
#endif #endif
} }
xfs_perag_put(args->pag);
return 0; return 0;
error0: error0:
up_read(&mp->m_peraglock); xfs_perag_put(args->pag);
return error; return error;
} }
@ -2454,8 +2457,7 @@ xfs_free_extent(
args.agno = XFS_FSB_TO_AGNO(args.mp, bno); args.agno = XFS_FSB_TO_AGNO(args.mp, bno);
ASSERT(args.agno < args.mp->m_sb.sb_agcount); ASSERT(args.agno < args.mp->m_sb.sb_agcount);
args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
down_read(&args.mp->m_peraglock); args.pag = xfs_perag_get(args.mp, args.agno);
args.pag = &args.mp->m_perag[args.agno];
if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING)))
goto error0; goto error0;
#ifdef DEBUG #ifdef DEBUG
@ -2465,7 +2467,7 @@ xfs_free_extent(
#endif #endif
error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
error0: error0:
up_read(&args.mp->m_peraglock); xfs_perag_put(args.pag);
return error; return error;
} }
@ -2486,15 +2488,15 @@ xfs_alloc_mark_busy(xfs_trans_t *tp,
xfs_agblock_t bno, xfs_agblock_t bno,
xfs_extlen_t len) xfs_extlen_t len)
{ {
xfs_mount_t *mp;
xfs_perag_busy_t *bsy; xfs_perag_busy_t *bsy;
struct xfs_perag *pag;
int n; int n;
mp = tp->t_mountp; pag = xfs_perag_get(tp->t_mountp, agno);
spin_lock(&mp->m_perag[agno].pagb_lock); spin_lock(&pag->pagb_lock);
/* search pagb_list for an open slot */ /* search pagb_list for an open slot */
for (bsy = mp->m_perag[agno].pagb_list, n = 0; for (bsy = pag->pagb_list, n = 0;
n < XFS_PAGB_NUM_SLOTS; n < XFS_PAGB_NUM_SLOTS;
bsy++, n++) { bsy++, n++) {
if (bsy->busy_tp == NULL) { if (bsy->busy_tp == NULL) {
@ -2502,11 +2504,11 @@ xfs_alloc_mark_busy(xfs_trans_t *tp,
} }
} }
trace_xfs_alloc_busy(mp, agno, bno, len, n); trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len, n);
if (n < XFS_PAGB_NUM_SLOTS) { if (n < XFS_PAGB_NUM_SLOTS) {
bsy = &mp->m_perag[agno].pagb_list[n]; bsy = &pag->pagb_list[n];
mp->m_perag[agno].pagb_count++; pag->pagb_count++;
bsy->busy_start = bno; bsy->busy_start = bno;
bsy->busy_length = len; bsy->busy_length = len;
bsy->busy_tp = tp; bsy->busy_tp = tp;
@ -2521,7 +2523,8 @@ xfs_alloc_mark_busy(xfs_trans_t *tp,
xfs_trans_set_sync(tp); xfs_trans_set_sync(tp);
} }
spin_unlock(&mp->m_perag[agno].pagb_lock); spin_unlock(&pag->pagb_lock);
xfs_perag_put(pag);
} }
void void
@ -2529,24 +2532,23 @@ xfs_alloc_clear_busy(xfs_trans_t *tp,
xfs_agnumber_t agno, xfs_agnumber_t agno,
int idx) int idx)
{ {
xfs_mount_t *mp; struct xfs_perag *pag;
xfs_perag_busy_t *list; xfs_perag_busy_t *list;
mp = tp->t_mountp;
spin_lock(&mp->m_perag[agno].pagb_lock);
list = mp->m_perag[agno].pagb_list;
ASSERT(idx < XFS_PAGB_NUM_SLOTS); ASSERT(idx < XFS_PAGB_NUM_SLOTS);
pag = xfs_perag_get(tp->t_mountp, agno);
spin_lock(&pag->pagb_lock);
list = pag->pagb_list;
trace_xfs_alloc_unbusy(mp, agno, idx, list[idx].busy_tp == tp); trace_xfs_alloc_unbusy(tp->t_mountp, agno, idx, list[idx].busy_tp == tp);
if (list[idx].busy_tp == tp) { if (list[idx].busy_tp == tp) {
list[idx].busy_tp = NULL; list[idx].busy_tp = NULL;
mp->m_perag[agno].pagb_count--; pag->pagb_count--;
} }
spin_unlock(&mp->m_perag[agno].pagb_lock); spin_unlock(&pag->pagb_lock);
xfs_perag_put(pag);
} }
@ -2560,17 +2562,15 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
xfs_agblock_t bno, xfs_agblock_t bno,
xfs_extlen_t len) xfs_extlen_t len)
{ {
xfs_mount_t *mp; struct xfs_perag *pag;
xfs_perag_busy_t *bsy; xfs_perag_busy_t *bsy;
xfs_agblock_t uend, bend; xfs_agblock_t uend, bend;
xfs_lsn_t lsn = 0; xfs_lsn_t lsn = 0;
int cnt; int cnt;
mp = tp->t_mountp; pag = xfs_perag_get(tp->t_mountp, agno);
spin_lock(&pag->pagb_lock);
spin_lock(&mp->m_perag[agno].pagb_lock); cnt = pag->pagb_count;
uend = bno + len - 1;
/* /*
* search pagb_list for this slot, skipping open slots. We have to * search pagb_list for this slot, skipping open slots. We have to
@ -2578,8 +2578,9 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
* we have to get the most recent LSN for the log force to push out * we have to get the most recent LSN for the log force to push out
* all the transactions that span the range. * all the transactions that span the range.
*/ */
for (cnt = 0; cnt < mp->m_perag[agno].pagb_count; cnt++) { uend = bno + len - 1;
bsy = &mp->m_perag[agno].pagb_list[cnt]; for (cnt = 0; cnt < pag->pagb_count; cnt++) {
bsy = &pag->pagb_list[cnt];
if (!bsy->busy_tp) if (!bsy->busy_tp)
continue; continue;
@ -2591,7 +2592,8 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
if (XFS_LSN_CMP(bsy->busy_tp->t_commit_lsn, lsn) > 0) if (XFS_LSN_CMP(bsy->busy_tp->t_commit_lsn, lsn) > 0)
lsn = bsy->busy_tp->t_commit_lsn; lsn = bsy->busy_tp->t_commit_lsn;
} }
spin_unlock(&mp->m_perag[agno].pagb_lock); spin_unlock(&pag->pagb_lock);
xfs_perag_put(pag);
trace_xfs_alloc_busysearch(tp->t_mountp, agno, bno, len, lsn); trace_xfs_alloc_busysearch(tp->t_mountp, agno, bno, len, lsn);
/* /*
@ -2599,5 +2601,5 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
* transaction that freed the block * transaction that freed the block
*/ */
if (lsn) if (lsn)
xfs_log_force(mp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC); xfs_log_force_lsn(tp->t_mountp, lsn, XFS_LOG_SYNC);
} }

View file

@ -61,12 +61,14 @@ xfs_allocbt_set_root(
struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
int btnum = cur->bc_btnum; int btnum = cur->bc_btnum;
struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno);
ASSERT(ptr->s != 0); ASSERT(ptr->s != 0);
agf->agf_roots[btnum] = ptr->s; agf->agf_roots[btnum] = ptr->s;
be32_add_cpu(&agf->agf_levels[btnum], inc); be32_add_cpu(&agf->agf_levels[btnum], inc);
cur->bc_mp->m_perag[seqno].pagf_levels[btnum] += inc; pag->pagf_levels[btnum] += inc;
xfs_perag_put(pag);
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
} }
@ -150,6 +152,7 @@ xfs_allocbt_update_lastrec(
{ {
struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);
xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
struct xfs_perag *pag;
__be32 len; __be32 len;
int numrecs; int numrecs;
@ -193,7 +196,9 @@ xfs_allocbt_update_lastrec(
} }
agf->agf_longest = len; agf->agf_longest = len;
cur->bc_mp->m_perag[seqno].pagf_longest = be32_to_cpu(len); pag = xfs_perag_get(cur->bc_mp, seqno);
pag->pagf_longest = be32_to_cpu(len);
xfs_perag_put(pag);
xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST); xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST);
} }

View file

@ -93,12 +93,12 @@ STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
STATIC int STATIC int
xfs_attr_name_to_xname( xfs_attr_name_to_xname(
struct xfs_name *xname, struct xfs_name *xname,
const char *aname) const unsigned char *aname)
{ {
if (!aname) if (!aname)
return EINVAL; return EINVAL;
xname->name = aname; xname->name = aname;
xname->len = strlen(aname); xname->len = strlen((char *)aname);
if (xname->len >= MAXNAMELEN) if (xname->len >= MAXNAMELEN)
return EFAULT; /* match IRIX behaviour */ return EFAULT; /* match IRIX behaviour */
@ -124,7 +124,7 @@ STATIC int
xfs_attr_get_int( xfs_attr_get_int(
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_name *name, struct xfs_name *name,
char *value, unsigned char *value,
int *valuelenp, int *valuelenp,
int flags) int flags)
{ {
@ -171,8 +171,8 @@ xfs_attr_get_int(
int int
xfs_attr_get( xfs_attr_get(
xfs_inode_t *ip, xfs_inode_t *ip,
const char *name, const unsigned char *name,
char *value, unsigned char *value,
int *valuelenp, int *valuelenp,
int flags) int flags)
{ {
@ -197,7 +197,7 @@ xfs_attr_get(
/* /*
* Calculate how many blocks we need for the new attribute, * Calculate how many blocks we need for the new attribute,
*/ */
int STATIC int
xfs_attr_calc_size( xfs_attr_calc_size(
struct xfs_inode *ip, struct xfs_inode *ip,
int namelen, int namelen,
@ -235,8 +235,12 @@ xfs_attr_calc_size(
} }
STATIC int STATIC int
xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, xfs_attr_set_int(
char *value, int valuelen, int flags) struct xfs_inode *dp,
struct xfs_name *name,
unsigned char *value,
int valuelen,
int flags)
{ {
xfs_da_args_t args; xfs_da_args_t args;
xfs_fsblock_t firstblock; xfs_fsblock_t firstblock;
@ -452,8 +456,8 @@ out:
int int
xfs_attr_set( xfs_attr_set(
xfs_inode_t *dp, xfs_inode_t *dp,
const char *name, const unsigned char *name,
char *value, unsigned char *value,
int valuelen, int valuelen,
int flags) int flags)
{ {
@ -600,7 +604,7 @@ out:
int int
xfs_attr_remove( xfs_attr_remove(
xfs_inode_t *dp, xfs_inode_t *dp,
const char *name, const unsigned char *name,
int flags) int flags)
{ {
int error; int error;
@ -669,9 +673,13 @@ xfs_attr_list_int(xfs_attr_list_context_t *context)
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
STATIC int STATIC int
xfs_attr_put_listent(xfs_attr_list_context_t *context, int flags, xfs_attr_put_listent(
char *name, int namelen, xfs_attr_list_context_t *context,
int valuelen, char *value) int flags,
unsigned char *name,
int namelen,
int valuelen,
unsigned char *value)
{ {
struct attrlist *alist = (struct attrlist *)context->alist; struct attrlist *alist = (struct attrlist *)context->alist;
attrlist_ent_t *aep; attrlist_ent_t *aep;
@ -1980,7 +1988,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
xfs_mount_t *mp; xfs_mount_t *mp;
xfs_daddr_t dblkno; xfs_daddr_t dblkno;
xfs_caddr_t dst; void *dst;
xfs_buf_t *bp; xfs_buf_t *bp;
int nmap, error, tmp, valuelen, blkcnt, i; int nmap, error, tmp, valuelen, blkcnt, i;
xfs_dablk_t lblkno; xfs_dablk_t lblkno;
@ -2007,15 +2015,14 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno,
blkcnt, blkcnt, XBF_LOCK | XBF_DONT_BLOCK,
XFS_BUF_LOCK | XBF_DONT_BLOCK,
&bp); &bp);
if (error) if (error)
return(error); return(error);
tmp = (valuelen < XFS_BUF_SIZE(bp)) tmp = (valuelen < XFS_BUF_SIZE(bp))
? valuelen : XFS_BUF_SIZE(bp); ? valuelen : XFS_BUF_SIZE(bp);
xfs_biomove(bp, 0, tmp, dst, XFS_B_READ); xfs_biomove(bp, 0, tmp, dst, XBF_READ);
xfs_buf_relse(bp); xfs_buf_relse(bp);
dst += tmp; dst += tmp;
valuelen -= tmp; valuelen -= tmp;
@ -2039,7 +2046,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
xfs_inode_t *dp; xfs_inode_t *dp;
xfs_bmbt_irec_t map; xfs_bmbt_irec_t map;
xfs_daddr_t dblkno; xfs_daddr_t dblkno;
xfs_caddr_t src; void *src;
xfs_buf_t *bp; xfs_buf_t *bp;
xfs_dablk_t lblkno; xfs_dablk_t lblkno;
int blkcnt, valuelen, nmap, error, tmp, committed; int blkcnt, valuelen, nmap, error, tmp, committed;
@ -2141,13 +2148,13 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt,
XFS_BUF_LOCK | XBF_DONT_BLOCK); XBF_LOCK | XBF_DONT_BLOCK);
ASSERT(bp); ASSERT(bp);
ASSERT(!XFS_BUF_GETERROR(bp)); ASSERT(!XFS_BUF_GETERROR(bp));
tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen : tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
XFS_BUF_SIZE(bp); XFS_BUF_SIZE(bp);
xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE); xfs_biomove(bp, 0, tmp, src, XBF_WRITE);
if (tmp < XFS_BUF_SIZE(bp)) if (tmp < XFS_BUF_SIZE(bp))
xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp); xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */ if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */
@ -2208,8 +2215,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
/* /*
* If the "remote" value is in the cache, remove it. * If the "remote" value is in the cache, remove it.
*/ */
bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt, XBF_TRYLOCK);
XFS_INCORE_TRYLOCK);
if (bp) { if (bp) {
XFS_BUF_STALE(bp); XFS_BUF_STALE(bp);
XFS_BUF_UNDELAYWRITE(bp); XFS_BUF_UNDELAYWRITE(bp);

View file

@ -113,7 +113,7 @@ typedef struct attrlist_cursor_kern {
typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int, typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int,
char *, int, int, char *); unsigned char *, int, int, unsigned char *);
typedef struct xfs_attr_list_context { typedef struct xfs_attr_list_context {
struct xfs_inode *dp; /* inode */ struct xfs_inode *dp; /* inode */
@ -139,7 +139,6 @@ typedef struct xfs_attr_list_context {
/* /*
* Overall external interface routines. * Overall external interface routines.
*/ */
int xfs_attr_calc_size(struct xfs_inode *, int, int, int *);
int xfs_attr_inactive(struct xfs_inode *dp); int xfs_attr_inactive(struct xfs_inode *dp);
int xfs_attr_rmtval_get(struct xfs_da_args *args); int xfs_attr_rmtval_get(struct xfs_da_args *args);
int xfs_attr_list_int(struct xfs_attr_list_context *); int xfs_attr_list_int(struct xfs_attr_list_context *);

View file

@ -521,11 +521,11 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
sfe = &sf->list[0]; sfe = &sf->list[0];
for (i = 0; i < sf->hdr.count; i++) { for (i = 0; i < sf->hdr.count; i++) {
nargs.name = (char *)sfe->nameval; nargs.name = sfe->nameval;
nargs.namelen = sfe->namelen; nargs.namelen = sfe->namelen;
nargs.value = (char *)&sfe->nameval[nargs.namelen]; nargs.value = &sfe->nameval[nargs.namelen];
nargs.valuelen = sfe->valuelen; nargs.valuelen = sfe->valuelen;
nargs.hashval = xfs_da_hashname((char *)sfe->nameval, nargs.hashval = xfs_da_hashname(sfe->nameval,
sfe->namelen); sfe->namelen);
nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags); nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */ error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */
@ -612,10 +612,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
error = context->put_listent(context, error = context->put_listent(context,
sfe->flags, sfe->flags,
(char *)sfe->nameval, sfe->nameval,
(int)sfe->namelen, (int)sfe->namelen,
(int)sfe->valuelen, (int)sfe->valuelen,
(char*)&sfe->nameval[sfe->namelen]); &sfe->nameval[sfe->namelen]);
/* /*
* Either search callback finished early or * Either search callback finished early or
@ -659,8 +659,8 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
} }
sbp->entno = i; sbp->entno = i;
sbp->hash = xfs_da_hashname((char *)sfe->nameval, sfe->namelen); sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
sbp->name = (char *)sfe->nameval; sbp->name = sfe->nameval;
sbp->namelen = sfe->namelen; sbp->namelen = sfe->namelen;
/* These are bytes, and both on-disk, don't endian-flip */ /* These are bytes, and both on-disk, don't endian-flip */
sbp->valuelen = sfe->valuelen; sbp->valuelen = sfe->valuelen;
@ -818,9 +818,9 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
continue; continue;
ASSERT(entry->flags & XFS_ATTR_LOCAL); ASSERT(entry->flags & XFS_ATTR_LOCAL);
name_loc = xfs_attr_leaf_name_local(leaf, i); name_loc = xfs_attr_leaf_name_local(leaf, i);
nargs.name = (char *)name_loc->nameval; nargs.name = name_loc->nameval;
nargs.namelen = name_loc->namelen; nargs.namelen = name_loc->namelen;
nargs.value = (char *)&name_loc->nameval[nargs.namelen]; nargs.value = &name_loc->nameval[nargs.namelen];
nargs.valuelen = be16_to_cpu(name_loc->valuelen); nargs.valuelen = be16_to_cpu(name_loc->valuelen);
nargs.hashval = be32_to_cpu(entry->hashval); nargs.hashval = be32_to_cpu(entry->hashval);
nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags); nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
@ -2370,10 +2370,10 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
retval = context->put_listent(context, retval = context->put_listent(context,
entry->flags, entry->flags,
(char *)name_loc->nameval, name_loc->nameval,
(int)name_loc->namelen, (int)name_loc->namelen,
be16_to_cpu(name_loc->valuelen), be16_to_cpu(name_loc->valuelen),
(char *)&name_loc->nameval[name_loc->namelen]); &name_loc->nameval[name_loc->namelen]);
if (retval) if (retval)
return retval; return retval;
} else { } else {
@ -2397,15 +2397,15 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
return retval; return retval;
retval = context->put_listent(context, retval = context->put_listent(context,
entry->flags, entry->flags,
(char *)name_rmt->name, name_rmt->name,
(int)name_rmt->namelen, (int)name_rmt->namelen,
valuelen, valuelen,
(char*)args.value); args.value);
kmem_free(args.value); kmem_free(args.value);
} else { } else {
retval = context->put_listent(context, retval = context->put_listent(context,
entry->flags, entry->flags,
(char *)name_rmt->name, name_rmt->name,
(int)name_rmt->namelen, (int)name_rmt->namelen,
valuelen, valuelen,
NULL); NULL);
@ -2950,7 +2950,7 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
map.br_blockcount); map.br_blockcount);
bp = xfs_trans_get_buf(*trans, bp = xfs_trans_get_buf(*trans,
dp->i_mount->m_ddev_targp, dp->i_mount->m_ddev_targp,
dblkno, dblkcnt, XFS_BUF_LOCK); dblkno, dblkcnt, XBF_LOCK);
xfs_trans_binval(*trans, bp); xfs_trans_binval(*trans, bp);
/* /*
* Roll to next transaction. * Roll to next transaction.

View file

@ -52,7 +52,7 @@ typedef struct xfs_attr_sf_sort {
__uint8_t valuelen; /* length of value */ __uint8_t valuelen; /* length of value */
__uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */
xfs_dahash_t hash; /* this entry's hash value */ xfs_dahash_t hash; /* this entry's hash value */
char *name; /* name value, pointer into buffer */ unsigned char *name; /* name value, pointer into buffer */
} xfs_attr_sf_sort_t; } xfs_attr_sf_sort_t;
#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \ #define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \

View file

@ -2629,13 +2629,12 @@ xfs_bmap_btalloc(
if (startag == NULLAGNUMBER) if (startag == NULLAGNUMBER)
startag = ag = 0; startag = ag = 0;
notinit = 0; notinit = 0;
down_read(&mp->m_peraglock); pag = xfs_perag_get(mp, ag);
while (blen < ap->alen) { while (blen < ap->alen) {
pag = &mp->m_perag[ag];
if (!pag->pagf_init && if (!pag->pagf_init &&
(error = xfs_alloc_pagf_init(mp, args.tp, (error = xfs_alloc_pagf_init(mp, args.tp,
ag, XFS_ALLOC_FLAG_TRYLOCK))) { ag, XFS_ALLOC_FLAG_TRYLOCK))) {
up_read(&mp->m_peraglock); xfs_perag_put(pag);
return error; return error;
} }
/* /*
@ -2667,13 +2666,13 @@ xfs_bmap_btalloc(
break; break;
error = xfs_filestream_new_ag(ap, &ag); error = xfs_filestream_new_ag(ap, &ag);
if (error) { xfs_perag_put(pag);
up_read(&mp->m_peraglock); if (error)
return error; return error;
}
/* loop again to set 'blen'*/ /* loop again to set 'blen'*/
startag = NULLAGNUMBER; startag = NULLAGNUMBER;
pag = xfs_perag_get(mp, ag);
continue; continue;
} }
} }
@ -2681,8 +2680,10 @@ xfs_bmap_btalloc(
ag = 0; ag = 0;
if (ag == startag) if (ag == startag)
break; break;
xfs_perag_put(pag);
pag = xfs_perag_get(mp, ag);
} }
up_read(&mp->m_peraglock); xfs_perag_put(pag);
/* /*
* Since the above loop did a BUF_TRYLOCK, it is * Since the above loop did a BUF_TRYLOCK, it is
* possible that there is space for this request. * possible that there is space for this request.
@ -4470,7 +4471,7 @@ xfs_bmapi(
xfs_fsblock_t abno; /* allocated block number */ xfs_fsblock_t abno; /* allocated block number */
xfs_extlen_t alen; /* allocated extent length */ xfs_extlen_t alen; /* allocated extent length */
xfs_fileoff_t aoff; /* allocated file offset */ xfs_fileoff_t aoff; /* allocated file offset */
xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */ xfs_bmalloca_t bma = { 0 }; /* args for xfs_bmap_alloc */
xfs_btree_cur_t *cur; /* bmap btree cursor */ xfs_btree_cur_t *cur; /* bmap btree cursor */
xfs_fileoff_t end; /* end of mapped file region */ xfs_fileoff_t end; /* end of mapped file region */
int eof; /* we've hit the end of extents */ int eof; /* we've hit the end of extents */

View file

@ -334,7 +334,7 @@ xfs_bmbt_disk_set_allf(
/* /*
* Set all the fields in a bmap extent record from the uncompressed form. * Set all the fields in a bmap extent record from the uncompressed form.
*/ */
void STATIC void
xfs_bmbt_disk_set_all( xfs_bmbt_disk_set_all(
xfs_bmbt_rec_t *r, xfs_bmbt_rec_t *r,
xfs_bmbt_irec_t *s) xfs_bmbt_irec_t *s)

View file

@ -223,7 +223,6 @@ extern void xfs_bmbt_set_startblock(xfs_bmbt_rec_host_t *r, xfs_fsblock_t v);
extern void xfs_bmbt_set_startoff(xfs_bmbt_rec_host_t *r, xfs_fileoff_t v); extern void xfs_bmbt_set_startoff(xfs_bmbt_rec_host_t *r, xfs_fileoff_t v);
extern void xfs_bmbt_set_state(xfs_bmbt_rec_host_t *r, xfs_exntst_t v); extern void xfs_bmbt_set_state(xfs_bmbt_rec_host_t *r, xfs_exntst_t v);
extern void xfs_bmbt_disk_set_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o, extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o,
xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v);

View file

@ -977,7 +977,7 @@ xfs_btree_get_buf_block(
xfs_daddr_t d; xfs_daddr_t d;
/* need to sort out how callers deal with failures first */ /* need to sort out how callers deal with failures first */
ASSERT(!(flags & XFS_BUF_TRYLOCK)); ASSERT(!(flags & XBF_TRYLOCK));
d = xfs_btree_ptr_to_daddr(cur, ptr); d = xfs_btree_ptr_to_daddr(cur, ptr);
*bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d, *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
@ -1008,7 +1008,7 @@ xfs_btree_read_buf_block(
int error; int error;
/* need to sort out how callers deal with failures first */ /* need to sort out how callers deal with failures first */
ASSERT(!(flags & XFS_BUF_TRYLOCK)); ASSERT(!(flags & XBF_TRYLOCK));
d = xfs_btree_ptr_to_daddr(cur, ptr); d = xfs_btree_ptr_to_daddr(cur, ptr);
error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d, error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d,

View file

@ -250,7 +250,7 @@ xfs_buf_item_format(
((bip->bli_format.blf_map_size - 1) * sizeof(uint))); ((bip->bli_format.blf_map_size - 1) * sizeof(uint)));
vecp->i_addr = (xfs_caddr_t)&bip->bli_format; vecp->i_addr = (xfs_caddr_t)&bip->bli_format;
vecp->i_len = base_size; vecp->i_len = base_size;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BFORMAT); vecp->i_type = XLOG_REG_TYPE_BFORMAT;
vecp++; vecp++;
nvecs = 1; nvecs = 1;
@ -297,14 +297,14 @@ xfs_buf_item_format(
buffer_offset = first_bit * XFS_BLI_CHUNK; buffer_offset = first_bit * XFS_BLI_CHUNK;
vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
vecp->i_len = nbits * XFS_BLI_CHUNK; vecp->i_len = nbits * XFS_BLI_CHUNK;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); vecp->i_type = XLOG_REG_TYPE_BCHUNK;
nvecs++; nvecs++;
break; break;
} else if (next_bit != last_bit + 1) { } else if (next_bit != last_bit + 1) {
buffer_offset = first_bit * XFS_BLI_CHUNK; buffer_offset = first_bit * XFS_BLI_CHUNK;
vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
vecp->i_len = nbits * XFS_BLI_CHUNK; vecp->i_len = nbits * XFS_BLI_CHUNK;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); vecp->i_type = XLOG_REG_TYPE_BCHUNK;
nvecs++; nvecs++;
vecp++; vecp++;
first_bit = next_bit; first_bit = next_bit;
@ -316,7 +316,7 @@ xfs_buf_item_format(
buffer_offset = first_bit * XFS_BLI_CHUNK; buffer_offset = first_bit * XFS_BLI_CHUNK;
vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
vecp->i_len = nbits * XFS_BLI_CHUNK; vecp->i_len = nbits * XFS_BLI_CHUNK;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); vecp->i_type = XLOG_REG_TYPE_BCHUNK;
/* You would think we need to bump the nvecs here too, but we do not /* You would think we need to bump the nvecs here too, but we do not
* this number is used by recovery, and it gets confused by the boundary * this number is used by recovery, and it gets confused by the boundary
* split here * split here
@ -467,8 +467,10 @@ xfs_buf_item_unpin_remove(
/* /*
* This is called to attempt to lock the buffer associated with this * 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 * 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, pull the * the lock right away, return 0. If we can get the lock, take a
* buffer from the free list, mark it busy, and return 1. * 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.
*/ */
STATIC uint STATIC uint
xfs_buf_item_trylock( xfs_buf_item_trylock(
@ -477,24 +479,18 @@ xfs_buf_item_trylock(
xfs_buf_t *bp; xfs_buf_t *bp;
bp = bip->bli_buf; bp = bip->bli_buf;
if (XFS_BUF_ISPINNED(bp))
if (XFS_BUF_ISPINNED(bp)) {
return XFS_ITEM_PINNED; return XFS_ITEM_PINNED;
} if (!XFS_BUF_CPSEMA(bp))
if (!XFS_BUF_CPSEMA(bp)) {
return XFS_ITEM_LOCKED; return XFS_ITEM_LOCKED;
}
/* /* take a reference to the buffer. */
* Remove the buffer from the free list. Only do this
* if it's on the free list. Private buffers like the
* superblock buffer are not.
*/
XFS_BUF_HOLD(bp); XFS_BUF_HOLD(bp);
ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
trace_xfs_buf_item_trylock(bip); trace_xfs_buf_item_trylock(bip);
if (XFS_BUF_ISDELAYWRITE(bp))
return XFS_ITEM_PUSHBUF;
return XFS_ITEM_SUCCESS; return XFS_ITEM_SUCCESS;
} }
@ -626,11 +622,9 @@ xfs_buf_item_committed(
} }
/* /*
* This is called to asynchronously write the buffer associated with this * The buffer is locked, but is not a delayed write buffer. This happens
* buf log item out to disk. The buffer will already have been locked by * if we race with IO completion and hence we don't want to try to write it
* a successful call to xfs_buf_item_trylock(). If the buffer still has * again. Just release the buffer.
* B_DELWRI set, then get it going out to disk with a call to bawrite().
* If not, then just release the buffer.
*/ */
STATIC void STATIC void
xfs_buf_item_push( xfs_buf_item_push(
@ -642,17 +636,29 @@ xfs_buf_item_push(
trace_xfs_buf_item_push(bip); trace_xfs_buf_item_push(bip);
bp = bip->bli_buf; bp = bip->bli_buf;
ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
xfs_buf_relse(bp);
}
if (XFS_BUF_ISDELAYWRITE(bp)) { /*
int error; * The buffer is locked and is a delayed write buffer. Promote the buffer
error = xfs_bawrite(bip->bli_item.li_mountp, bp); * in the delayed write queue as the caller knows that they must invoke
if (error) * the xfsbufd to get this buffer written. We have to unlock the buffer
xfs_fs_cmn_err(CE_WARN, bip->bli_item.li_mountp, * to allow the xfsbufd to write it, too.
"xfs_buf_item_push: pushbuf error %d on bip %p, bp %p", */
error, bip, bp); STATIC void
} else { xfs_buf_item_pushbuf(
xfs_buf_relse(bp); xfs_buf_log_item_t *bip)
} {
xfs_buf_t *bp;
ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
trace_xfs_buf_item_pushbuf(bip);
bp = bip->bli_buf;
ASSERT(XFS_BUF_ISDELAYWRITE(bp));
xfs_buf_delwri_promote(bp);
xfs_buf_relse(bp);
} }
/* ARGSUSED */ /* ARGSUSED */
@ -677,7 +683,7 @@ static struct xfs_item_ops xfs_buf_item_ops = {
.iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_buf_item_committed, xfs_buf_item_committed,
.iop_push = (void(*)(xfs_log_item_t*))xfs_buf_item_push, .iop_push = (void(*)(xfs_log_item_t*))xfs_buf_item_push,
.iop_pushbuf = NULL, .iop_pushbuf = (void(*)(xfs_log_item_t*))xfs_buf_item_pushbuf,
.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_buf_item_committing xfs_buf_item_committing
}; };

View file

@ -1534,8 +1534,8 @@ xfs_da_hashname(const __uint8_t *name, int namelen)
enum xfs_dacmp enum xfs_dacmp
xfs_da_compname( xfs_da_compname(
struct xfs_da_args *args, struct xfs_da_args *args,
const char *name, const unsigned char *name,
int len) int len)
{ {
return (args->namelen == len && memcmp(args->name, name, len) == 0) ? return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
XFS_CMP_EXACT : XFS_CMP_DIFFERENT; XFS_CMP_EXACT : XFS_CMP_DIFFERENT;

View file

@ -209,7 +209,8 @@ typedef struct xfs_da_state {
*/ */
struct xfs_nameops { struct xfs_nameops {
xfs_dahash_t (*hashname)(struct xfs_name *); xfs_dahash_t (*hashname)(struct xfs_name *);
enum xfs_dacmp (*compname)(struct xfs_da_args *, const char *, int); enum xfs_dacmp (*compname)(struct xfs_da_args *,
const unsigned char *, int);
}; };
@ -260,7 +261,7 @@ int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
uint xfs_da_hashname(const __uint8_t *name_string, int name_length); uint xfs_da_hashname(const __uint8_t *name_string, int name_length);
enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args, enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args,
const char *name, int len); const unsigned char *name, int len);
xfs_da_state_t *xfs_da_state_alloc(void); xfs_da_state_t *xfs_da_state_alloc(void);

View file

@ -45,15 +45,21 @@
#include "xfs_vnodeops.h" #include "xfs_vnodeops.h"
#include "xfs_trace.h" #include "xfs_trace.h"
static int xfs_swap_extents(
xfs_inode_t *ip, /* target inode */
xfs_inode_t *tip, /* tmp inode */
xfs_swapext_t *sxp);
/* /*
* Syssgi interface for swapext * ioctl interface for swapext
*/ */
int int
xfs_swapext( xfs_swapext(
xfs_swapext_t *sxp) xfs_swapext_t *sxp)
{ {
xfs_inode_t *ip, *tip; xfs_inode_t *ip, *tip;
struct file *file, *target_file; struct file *file, *tmp_file;
int error = 0; int error = 0;
/* Pull information for the target fd */ /* Pull information for the target fd */
@ -68,46 +74,46 @@ xfs_swapext(
goto out_put_file; goto out_put_file;
} }
target_file = fget((int)sxp->sx_fdtmp); tmp_file = fget((int)sxp->sx_fdtmp);
if (!target_file) { if (!tmp_file) {
error = XFS_ERROR(EINVAL); error = XFS_ERROR(EINVAL);
goto out_put_file; goto out_put_file;
} }
if (!(target_file->f_mode & FMODE_WRITE) || if (!(tmp_file->f_mode & FMODE_WRITE) ||
(target_file->f_flags & O_APPEND)) { (tmp_file->f_flags & O_APPEND)) {
error = XFS_ERROR(EBADF); error = XFS_ERROR(EBADF);
goto out_put_target_file; goto out_put_tmp_file;
} }
if (IS_SWAPFILE(file->f_path.dentry->d_inode) || if (IS_SWAPFILE(file->f_path.dentry->d_inode) ||
IS_SWAPFILE(target_file->f_path.dentry->d_inode)) { IS_SWAPFILE(tmp_file->f_path.dentry->d_inode)) {
error = XFS_ERROR(EINVAL); error = XFS_ERROR(EINVAL);
goto out_put_target_file; goto out_put_tmp_file;
} }
ip = XFS_I(file->f_path.dentry->d_inode); ip = XFS_I(file->f_path.dentry->d_inode);
tip = XFS_I(target_file->f_path.dentry->d_inode); tip = XFS_I(tmp_file->f_path.dentry->d_inode);
if (ip->i_mount != tip->i_mount) { if (ip->i_mount != tip->i_mount) {
error = XFS_ERROR(EINVAL); error = XFS_ERROR(EINVAL);
goto out_put_target_file; goto out_put_tmp_file;
} }
if (ip->i_ino == tip->i_ino) { if (ip->i_ino == tip->i_ino) {
error = XFS_ERROR(EINVAL); error = XFS_ERROR(EINVAL);
goto out_put_target_file; goto out_put_tmp_file;
} }
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
error = XFS_ERROR(EIO); error = XFS_ERROR(EIO);
goto out_put_target_file; goto out_put_tmp_file;
} }
error = xfs_swap_extents(ip, tip, sxp); error = xfs_swap_extents(ip, tip, sxp);
out_put_target_file: out_put_tmp_file:
fput(target_file); fput(tmp_file);
out_put_file: out_put_file:
fput(file); fput(file);
out: out:
@ -186,7 +192,7 @@ xfs_swap_extents_check_format(
return 0; return 0;
} }
int static int
xfs_swap_extents( xfs_swap_extents(
xfs_inode_t *ip, /* target inode */ xfs_inode_t *ip, /* target inode */
xfs_inode_t *tip, /* tmp inode */ xfs_inode_t *tip, /* tmp inode */
@ -254,6 +260,9 @@ xfs_swap_extents(
goto out_unlock; goto out_unlock;
} }
trace_xfs_swap_extent_before(ip, 0);
trace_xfs_swap_extent_before(tip, 1);
/* check inode formats now that data is flushed */ /* check inode formats now that data is flushed */
error = xfs_swap_extents_check_format(ip, tip); error = xfs_swap_extents_check_format(ip, tip);
if (error) { if (error) {
@ -421,6 +430,8 @@ xfs_swap_extents(
error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT); error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT);
trace_xfs_swap_extent_after(ip, 0);
trace_xfs_swap_extent_after(tip, 1);
out: out:
kmem_free(tempifp); kmem_free(tempifp);
return error; return error;

View file

@ -48,9 +48,6 @@ typedef struct xfs_swapext
*/ */
int xfs_swapext(struct xfs_swapext *sx); int xfs_swapext(struct xfs_swapext *sx);
int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
struct xfs_swapext *sxp);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __XFS_DFRAG_H__ */ #endif /* __XFS_DFRAG_H__ */

View file

@ -44,7 +44,7 @@
#include "xfs_vnodeops.h" #include "xfs_vnodeops.h"
#include "xfs_trace.h" #include "xfs_trace.h"
struct xfs_name xfs_name_dotdot = {"..", 2}; struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2};
/* /*
* ASCII case-insensitive (ie. A-Z) support for directories that was * ASCII case-insensitive (ie. A-Z) support for directories that was
@ -66,8 +66,8 @@ xfs_ascii_ci_hashname(
STATIC enum xfs_dacmp STATIC enum xfs_dacmp
xfs_ascii_ci_compname( xfs_ascii_ci_compname(
struct xfs_da_args *args, struct xfs_da_args *args,
const char *name, const unsigned char *name,
int len) int len)
{ {
enum xfs_dacmp result; enum xfs_dacmp result;
int i; int i;
@ -247,7 +247,7 @@ xfs_dir_createname(
int int
xfs_dir_cilookup_result( xfs_dir_cilookup_result(
struct xfs_da_args *args, struct xfs_da_args *args,
const char *name, const unsigned char *name,
int len) int len)
{ {
if (args->cmpresult == XFS_CMP_DIFFERENT) if (args->cmpresult == XFS_CMP_DIFFERENT)

View file

@ -100,7 +100,7 @@ extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp,
extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
struct xfs_dabuf *bp); struct xfs_dabuf *bp);
extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const char *name, extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
int len); const unsigned char *name, int len);
#endif /* __XFS_DIR2_H__ */ #endif /* __XFS_DIR2_H__ */

View file

@ -57,8 +57,8 @@ static xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot;
void void
xfs_dir_startup(void) xfs_dir_startup(void)
{ {
xfs_dir_hash_dot = xfs_da_hashname(".", 1); xfs_dir_hash_dot = xfs_da_hashname((unsigned char *)".", 1);
xfs_dir_hash_dotdot = xfs_da_hashname("..", 2); xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2);
} }
/* /*
@ -513,8 +513,9 @@ xfs_dir2_block_getdents(
/* /*
* If it didn't fit, set the final offset to here & return. * If it didn't fit, set the final offset to here & return.
*/ */
if (filldir(dirent, dep->name, dep->namelen, cook & 0x7fffffff, if (filldir(dirent, (char *)dep->name, dep->namelen,
be64_to_cpu(dep->inumber), DT_UNKNOWN)) { cook & 0x7fffffff, be64_to_cpu(dep->inumber),
DT_UNKNOWN)) {
*offset = cook & 0x7fffffff; *offset = cook & 0x7fffffff;
xfs_da_brelse(NULL, bp); xfs_da_brelse(NULL, bp);
return 0; return 0;

View file

@ -1081,7 +1081,7 @@ xfs_dir2_leaf_getdents(
dep = (xfs_dir2_data_entry_t *)ptr; dep = (xfs_dir2_data_entry_t *)ptr;
length = xfs_dir2_data_entsize(dep->namelen); length = xfs_dir2_data_entsize(dep->namelen);
if (filldir(dirent, dep->name, dep->namelen, if (filldir(dirent, (char *)dep->name, dep->namelen,
xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff, xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff,
be64_to_cpu(dep->inumber), DT_UNKNOWN)) be64_to_cpu(dep->inumber), DT_UNKNOWN))
break; break;

View file

@ -65,7 +65,7 @@ static int xfs_dir2_node_addname_int(xfs_da_args_t *args,
/* /*
* Log entries from a freespace block. * Log entries from a freespace block.
*/ */
void STATIC void
xfs_dir2_free_log_bests( xfs_dir2_free_log_bests(
xfs_trans_t *tp, /* transaction pointer */ xfs_trans_t *tp, /* transaction pointer */
xfs_dabuf_t *bp, /* freespace buffer */ xfs_dabuf_t *bp, /* freespace buffer */

View file

@ -75,8 +75,6 @@ xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db)
return ((db) % XFS_DIR2_MAX_FREE_BESTS(mp)); return ((db) % XFS_DIR2_MAX_FREE_BESTS(mp));
} }
extern void xfs_dir2_free_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp,
int first, int last);
extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args, extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args,
struct xfs_dabuf *lbp); struct xfs_dabuf *lbp);
extern xfs_dahash_t xfs_dir2_leafn_lasthash(struct xfs_dabuf *bp, int *count); extern xfs_dahash_t xfs_dir2_leafn_lasthash(struct xfs_dabuf *bp, int *count);

View file

@ -782,7 +782,7 @@ xfs_dir2_sf_getdents(
} }
ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep)); ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
if (filldir(dirent, sfep->name, sfep->namelen, if (filldir(dirent, (char *)sfep->name, sfep->namelen,
off & 0x7fffffff, ino, DT_UNKNOWN)) { off & 0x7fffffff, ino, DT_UNKNOWN)) {
*offset = off & 0x7fffffff; *offset = off & 0x7fffffff;
return 0; return 0;

View file

@ -82,7 +82,7 @@ xfs_efi_item_format(xfs_efi_log_item_t *efip,
log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format); log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format);
log_vector->i_len = size; log_vector->i_len = size;
XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_EFI_FORMAT); log_vector->i_type = XLOG_REG_TYPE_EFI_FORMAT;
ASSERT(size >= sizeof(xfs_efi_log_format_t)); ASSERT(size >= sizeof(xfs_efi_log_format_t));
} }
@ -406,7 +406,7 @@ xfs_efd_item_format(xfs_efd_log_item_t *efdp,
log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format); log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format);
log_vector->i_len = size; log_vector->i_len = size;
XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_EFD_FORMAT); log_vector->i_type = XLOG_REG_TYPE_EFD_FORMAT;
ASSERT(size >= sizeof(xfs_efd_log_format_t)); ASSERT(size >= sizeof(xfs_efd_log_format_t));
} }

View file

@ -140,6 +140,7 @@ _xfs_filestream_pick_ag(
int flags, int flags,
xfs_extlen_t minlen) xfs_extlen_t minlen)
{ {
int streams, max_streams;
int err, trylock, nscan; int err, trylock, nscan;
xfs_extlen_t longest, free, minfree, maxfree = 0; xfs_extlen_t longest, free, minfree, maxfree = 0;
xfs_agnumber_t ag, max_ag = NULLAGNUMBER; xfs_agnumber_t ag, max_ag = NULLAGNUMBER;
@ -155,15 +156,15 @@ _xfs_filestream_pick_ag(
trylock = XFS_ALLOC_FLAG_TRYLOCK; trylock = XFS_ALLOC_FLAG_TRYLOCK;
for (nscan = 0; 1; nscan++) { for (nscan = 0; 1; nscan++) {
pag = xfs_perag_get(mp, ag);
TRACE_AG_SCAN(mp, ag, xfs_filestream_peek_ag(mp, ag)); TRACE_AG_SCAN(mp, ag, atomic_read(&pag->pagf_fstrms));
pag = mp->m_perag + ag;
if (!pag->pagf_init) { if (!pag->pagf_init) {
err = xfs_alloc_pagf_init(mp, NULL, ag, trylock); err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
if (err && !trylock) if (err && !trylock) {
xfs_perag_put(pag);
return err; return err;
}
} }
/* Might fail sometimes during the 1st pass with trylock set. */ /* Might fail sometimes during the 1st pass with trylock set. */
@ -173,6 +174,7 @@ _xfs_filestream_pick_ag(
/* Keep track of the AG with the most free blocks. */ /* Keep track of the AG with the most free blocks. */
if (pag->pagf_freeblks > maxfree) { if (pag->pagf_freeblks > maxfree) {
maxfree = pag->pagf_freeblks; maxfree = pag->pagf_freeblks;
max_streams = atomic_read(&pag->pagf_fstrms);
max_ag = ag; max_ag = ag;
} }
@ -195,6 +197,8 @@ _xfs_filestream_pick_ag(
/* Break out, retaining the reference on the AG. */ /* Break out, retaining the reference on the AG. */
free = pag->pagf_freeblks; free = pag->pagf_freeblks;
streams = atomic_read(&pag->pagf_fstrms);
xfs_perag_put(pag);
*agp = ag; *agp = ag;
break; break;
} }
@ -202,6 +206,7 @@ _xfs_filestream_pick_ag(
/* Drop the reference on this AG, it's not usable. */ /* Drop the reference on this AG, it's not usable. */
xfs_filestream_put_ag(mp, ag); xfs_filestream_put_ag(mp, ag);
next_ag: next_ag:
xfs_perag_put(pag);
/* Move to the next AG, wrapping to AG 0 if necessary. */ /* Move to the next AG, wrapping to AG 0 if necessary. */
if (++ag >= mp->m_sb.sb_agcount) if (++ag >= mp->m_sb.sb_agcount)
ag = 0; ag = 0;
@ -229,6 +234,7 @@ next_ag:
if (max_ag != NULLAGNUMBER) { if (max_ag != NULLAGNUMBER) {
xfs_filestream_get_ag(mp, max_ag); xfs_filestream_get_ag(mp, max_ag);
TRACE_AG_PICK1(mp, max_ag, maxfree); TRACE_AG_PICK1(mp, max_ag, maxfree);
streams = max_streams;
free = maxfree; free = maxfree;
*agp = max_ag; *agp = max_ag;
break; break;
@ -240,16 +246,14 @@ next_ag:
return 0; return 0;
} }
TRACE_AG_PICK2(mp, startag, *agp, xfs_filestream_peek_ag(mp, *agp), TRACE_AG_PICK2(mp, startag, *agp, streams, free, nscan, flags);
free, nscan, flags);
return 0; return 0;
} }
/* /*
* Set the allocation group number for a file or a directory, updating inode * Set the allocation group number for a file or a directory, updating inode
* references and per-AG references as appropriate. Must be called with the * references and per-AG references as appropriate.
* m_peraglock held in read mode.
*/ */
static int static int
_xfs_filestream_update_ag( _xfs_filestream_update_ag(
@ -450,20 +454,6 @@ xfs_filestream_unmount(
xfs_mru_cache_destroy(mp->m_filestream); xfs_mru_cache_destroy(mp->m_filestream);
} }
/*
* If the mount point's m_perag array is going to be reallocated, all
* outstanding cache entries must be flushed to avoid accessing reference count
* addresses that have been freed. The call to xfs_filestream_flush() must be
* made inside the block that holds the m_peraglock in write mode to do the
* reallocation.
*/
void
xfs_filestream_flush(
xfs_mount_t *mp)
{
xfs_mru_cache_flush(mp->m_filestream);
}
/* /*
* Return the AG of the filestream the file or directory belongs to, or * Return the AG of the filestream the file or directory belongs to, or
* NULLAGNUMBER otherwise. * NULLAGNUMBER otherwise.
@ -526,7 +516,6 @@ xfs_filestream_associate(
mp = pip->i_mount; mp = pip->i_mount;
cache = mp->m_filestream; cache = mp->m_filestream;
down_read(&mp->m_peraglock);
/* /*
* We have a problem, Houston. * We have a problem, Houston.
@ -543,10 +532,8 @@ xfs_filestream_associate(
* *
* So, if we can't get the iolock without sleeping then just give up * So, if we can't get the iolock without sleeping then just give up
*/ */
if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) { if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL))
up_read(&mp->m_peraglock);
return 1; return 1;
}
/* If the parent directory is already in the cache, use its AG. */ /* If the parent directory is already in the cache, use its AG. */
item = xfs_mru_cache_lookup(cache, pip->i_ino); item = xfs_mru_cache_lookup(cache, pip->i_ino);
@ -601,7 +588,6 @@ exit_did_pick:
exit: exit:
xfs_iunlock(pip, XFS_IOLOCK_EXCL); xfs_iunlock(pip, XFS_IOLOCK_EXCL);
up_read(&mp->m_peraglock);
return -err; return -err;
} }

View file

@ -79,12 +79,21 @@ extern ktrace_t *xfs_filestreams_trace_buf;
* the cache that reference per-ag array elements that have since been * the cache that reference per-ag array elements that have since been
* reallocated. * reallocated.
*/ */
/*
* xfs_filestream_peek_ag is only used in tracing code
*/
static inline int static inline int
xfs_filestream_peek_ag( xfs_filestream_peek_ag(
xfs_mount_t *mp, xfs_mount_t *mp,
xfs_agnumber_t agno) xfs_agnumber_t agno)
{ {
return atomic_read(&mp->m_perag[agno].pagf_fstrms); struct xfs_perag *pag;
int ret;
pag = xfs_perag_get(mp, agno);
ret = atomic_read(&pag->pagf_fstrms);
xfs_perag_put(pag);
return ret;
} }
static inline int static inline int
@ -92,7 +101,13 @@ xfs_filestream_get_ag(
xfs_mount_t *mp, xfs_mount_t *mp,
xfs_agnumber_t agno) xfs_agnumber_t agno)
{ {
return atomic_inc_return(&mp->m_perag[agno].pagf_fstrms); struct xfs_perag *pag;
int ret;
pag = xfs_perag_get(mp, agno);
ret = atomic_inc_return(&pag->pagf_fstrms);
xfs_perag_put(pag);
return ret;
} }
static inline int static inline int
@ -100,7 +115,13 @@ xfs_filestream_put_ag(
xfs_mount_t *mp, xfs_mount_t *mp,
xfs_agnumber_t agno) xfs_agnumber_t agno)
{ {
return atomic_dec_return(&mp->m_perag[agno].pagf_fstrms); struct xfs_perag *pag;
int ret;
pag = xfs_perag_get(mp, agno);
ret = atomic_dec_return(&pag->pagf_fstrms);
xfs_perag_put(pag);
return ret;
} }
/* allocation selection flags */ /* allocation selection flags */
@ -114,7 +135,6 @@ int xfs_filestream_init(void);
void xfs_filestream_uninit(void); void xfs_filestream_uninit(void);
int xfs_filestream_mount(struct xfs_mount *mp); int xfs_filestream_mount(struct xfs_mount *mp);
void xfs_filestream_unmount(struct xfs_mount *mp); void xfs_filestream_unmount(struct xfs_mount *mp);
void xfs_filestream_flush(struct xfs_mount *mp);
xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip); xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip);
int xfs_filestream_associate(struct xfs_inode *dip, struct xfs_inode *ip); int xfs_filestream_associate(struct xfs_inode *dip, struct xfs_inode *ip);
void xfs_filestream_deassociate(struct xfs_inode *ip); void xfs_filestream_deassociate(struct xfs_inode *ip);

View file

@ -167,27 +167,14 @@ xfs_growfs_data_private(
} }
new = nb - mp->m_sb.sb_dblocks; new = nb - mp->m_sb.sb_dblocks;
oagcount = mp->m_sb.sb_agcount; oagcount = mp->m_sb.sb_agcount;
/* allocate the new per-ag structures */
if (nagcount > oagcount) { if (nagcount > oagcount) {
void *new_perag, *old_perag; error = xfs_initialize_perag(mp, nagcount, &nagimax);
if (error)
xfs_filestream_flush(mp); return error;
new_perag = kmem_zalloc(sizeof(xfs_perag_t) * nagcount,
KM_MAYFAIL);
if (!new_perag)
return XFS_ERROR(ENOMEM);
down_write(&mp->m_peraglock);
memcpy(new_perag, mp->m_perag, sizeof(xfs_perag_t) * oagcount);
old_perag = mp->m_perag;
mp->m_perag = new_perag;
mp->m_flags |= XFS_MOUNT_32BITINODES;
nagimax = xfs_initialize_perag(mp, nagcount);
up_write(&mp->m_peraglock);
kmem_free(old_perag);
} }
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
tp->t_flags |= XFS_TRANS_RESERVE; tp->t_flags |= XFS_TRANS_RESERVE;
if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp), if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
@ -196,6 +183,11 @@ xfs_growfs_data_private(
return error; return error;
} }
/*
* Write new AG headers to disk. Non-transactional, but written
* synchronously so they are completed prior to the growfs transaction
* being logged.
*/
nfree = 0; nfree = 0;
for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) {
/* /*
@ -359,6 +351,12 @@ xfs_growfs_data_private(
goto error0; goto error0;
} }
} }
/*
* Update changed superblock fields transactionally. These are not
* seen by the rest of the world until the transaction commit applies
* them atomically to the superblock.
*/
if (nagcount > oagcount) if (nagcount > oagcount)
xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
if (nb > mp->m_sb.sb_dblocks) if (nb > mp->m_sb.sb_dblocks)
@ -369,9 +367,9 @@ xfs_growfs_data_private(
if (dpct) if (dpct)
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
error = xfs_trans_commit(tp, 0); error = xfs_trans_commit(tp, 0);
if (error) { if (error)
return error; return error;
}
/* New allocation groups fully initialized, so update mount struct */ /* New allocation groups fully initialized, so update mount struct */
if (nagimax) if (nagimax)
mp->m_maxagi = nagimax; mp->m_maxagi = nagimax;
@ -381,6 +379,8 @@ xfs_growfs_data_private(
mp->m_maxicount = icount << mp->m_sb.sb_inopblog; mp->m_maxicount = icount << mp->m_sb.sb_inopblog;
} else } else
mp->m_maxicount = 0; mp->m_maxicount = 0;
/* update secondary superblocks. */
for (agno = 1; agno < nagcount; agno++) { for (agno = 1; agno < nagcount; agno++) {
error = xfs_read_buf(mp, mp->m_ddev_targp, error = xfs_read_buf(mp, mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),

View file

@ -205,7 +205,7 @@ xfs_ialloc_inode_init(
d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * blks_per_cluster)); d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * blks_per_cluster));
fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
mp->m_bsize * blks_per_cluster, mp->m_bsize * blks_per_cluster,
XFS_BUF_LOCK); XBF_LOCK);
ASSERT(fbuf); ASSERT(fbuf);
ASSERT(!XFS_BUF_GETERROR(fbuf)); ASSERT(!XFS_BUF_GETERROR(fbuf));
@ -253,6 +253,7 @@ xfs_ialloc_ag_alloc(
xfs_agino_t thisino; /* current inode number, for loop */ xfs_agino_t thisino; /* current inode number, for loop */
int isaligned = 0; /* inode allocation at stripe unit */ int isaligned = 0; /* inode allocation at stripe unit */
/* boundary */ /* boundary */
struct xfs_perag *pag;
args.tp = tp; args.tp = tp;
args.mp = tp->t_mountp; args.mp = tp->t_mountp;
@ -382,9 +383,9 @@ xfs_ialloc_ag_alloc(
newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0);
be32_add_cpu(&agi->agi_count, newlen); be32_add_cpu(&agi->agi_count, newlen);
be32_add_cpu(&agi->agi_freecount, newlen); be32_add_cpu(&agi->agi_freecount, newlen);
down_read(&args.mp->m_peraglock); pag = xfs_perag_get(args.mp, agno);
args.mp->m_perag[agno].pagi_freecount += newlen; pag->pagi_freecount += newlen;
up_read(&args.mp->m_peraglock); xfs_perag_put(pag);
agi->agi_newino = cpu_to_be32(newino); agi->agi_newino = cpu_to_be32(newino);
/* /*
@ -486,9 +487,8 @@ xfs_ialloc_ag_select(
*/ */
agno = pagno; agno = pagno;
flags = XFS_ALLOC_FLAG_TRYLOCK; flags = XFS_ALLOC_FLAG_TRYLOCK;
down_read(&mp->m_peraglock);
for (;;) { for (;;) {
pag = &mp->m_perag[agno]; pag = xfs_perag_get(mp, agno);
if (!pag->pagi_init) { if (!pag->pagi_init) {
if (xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { if (xfs_ialloc_read_agi(mp, tp, agno, &agbp)) {
agbp = NULL; agbp = NULL;
@ -527,7 +527,7 @@ xfs_ialloc_ag_select(
agbp = NULL; agbp = NULL;
goto nextag; goto nextag;
} }
up_read(&mp->m_peraglock); xfs_perag_put(pag);
return agbp; return agbp;
} }
} }
@ -535,22 +535,19 @@ unlock_nextag:
if (agbp) if (agbp)
xfs_trans_brelse(tp, agbp); xfs_trans_brelse(tp, agbp);
nextag: nextag:
xfs_perag_put(pag);
/* /*
* No point in iterating over the rest, if we're shutting * No point in iterating over the rest, if we're shutting
* down. * down.
*/ */
if (XFS_FORCED_SHUTDOWN(mp)) { if (XFS_FORCED_SHUTDOWN(mp))
up_read(&mp->m_peraglock);
return NULL; return NULL;
}
agno++; agno++;
if (agno >= agcount) if (agno >= agcount)
agno = 0; agno = 0;
if (agno == pagno) { if (agno == pagno) {
if (flags == 0) { if (flags == 0)
up_read(&mp->m_peraglock);
return NULL; return NULL;
}
flags = 0; flags = 0;
} }
} }
@ -672,6 +669,7 @@ xfs_dialloc(
xfs_agnumber_t tagno; /* testing allocation group number */ xfs_agnumber_t tagno; /* testing allocation group number */
xfs_btree_cur_t *tcur; /* temp cursor */ xfs_btree_cur_t *tcur; /* temp cursor */
xfs_inobt_rec_incore_t trec; /* temp inode allocation record */ xfs_inobt_rec_incore_t trec; /* temp inode allocation record */
struct xfs_perag *pag;
if (*IO_agbp == NULL) { if (*IO_agbp == NULL) {
@ -771,13 +769,13 @@ nextag:
*inop = NULLFSINO; *inop = NULLFSINO;
return noroom ? ENOSPC : 0; return noroom ? ENOSPC : 0;
} }
down_read(&mp->m_peraglock); pag = xfs_perag_get(mp, tagno);
if (mp->m_perag[tagno].pagi_inodeok == 0) { if (pag->pagi_inodeok == 0) {
up_read(&mp->m_peraglock); xfs_perag_put(pag);
goto nextag; goto nextag;
} }
error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp);
up_read(&mp->m_peraglock); xfs_perag_put(pag);
if (error) if (error)
goto nextag; goto nextag;
agi = XFS_BUF_TO_AGI(agbp); agi = XFS_BUF_TO_AGI(agbp);
@ -790,6 +788,7 @@ nextag:
*/ */
agno = tagno; agno = tagno;
*IO_agbp = NULL; *IO_agbp = NULL;
pag = xfs_perag_get(mp, agno);
restart_pagno: restart_pagno:
cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno)); cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno));
@ -808,7 +807,6 @@ nextag:
* If in the same AG as the parent, try to get near the parent. * If in the same AG as the parent, try to get near the parent.
*/ */
if (pagno == agno) { if (pagno == agno) {
xfs_perag_t *pag = &mp->m_perag[agno];
int doneleft; /* done, to the left */ int doneleft; /* done, to the left */
int doneright; /* done, to the right */ int doneright; /* done, to the right */
int searchdistance = 10; int searchdistance = 10;
@ -1006,9 +1004,7 @@ alloc_inode:
goto error0; goto error0;
be32_add_cpu(&agi->agi_freecount, -1); be32_add_cpu(&agi->agi_freecount, -1);
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
down_read(&mp->m_peraglock); pag->pagi_freecount--;
mp->m_perag[tagno].pagi_freecount--;
up_read(&mp->m_peraglock);
error = xfs_check_agi_freecount(cur, agi); error = xfs_check_agi_freecount(cur, agi);
if (error) if (error)
@ -1016,12 +1012,14 @@ alloc_inode:
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);
xfs_perag_put(pag);
*inop = ino; *inop = ino;
return 0; return 0;
error1: error1:
xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
error0: error0:
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
xfs_perag_put(pag);
return error; return error;
} }
@ -1052,6 +1050,7 @@ xfs_difree(
xfs_mount_t *mp; /* mount structure for filesystem */ xfs_mount_t *mp; /* mount structure for filesystem */
int off; /* offset of inode in inode chunk */ int off; /* offset of inode in inode chunk */
xfs_inobt_rec_incore_t rec; /* btree record */ xfs_inobt_rec_incore_t rec; /* btree record */
struct xfs_perag *pag;
mp = tp->t_mountp; mp = tp->t_mountp;
@ -1088,9 +1087,7 @@ xfs_difree(
/* /*
* Get the allocation group header. * Get the allocation group header.
*/ */
down_read(&mp->m_peraglock);
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
up_read(&mp->m_peraglock);
if (error) { if (error) {
cmn_err(CE_WARN, cmn_err(CE_WARN,
"xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.", "xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.",
@ -1157,9 +1154,9 @@ xfs_difree(
be32_add_cpu(&agi->agi_count, -ilen); be32_add_cpu(&agi->agi_count, -ilen);
be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); be32_add_cpu(&agi->agi_freecount, -(ilen - 1));
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT);
down_read(&mp->m_peraglock); pag = xfs_perag_get(mp, agno);
mp->m_perag[agno].pagi_freecount -= ilen - 1; pag->pagi_freecount -= ilen - 1;
up_read(&mp->m_peraglock); xfs_perag_put(pag);
xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen);
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1));
@ -1188,9 +1185,9 @@ xfs_difree(
*/ */
be32_add_cpu(&agi->agi_freecount, 1); be32_add_cpu(&agi->agi_freecount, 1);
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
down_read(&mp->m_peraglock); pag = xfs_perag_get(mp, agno);
mp->m_perag[agno].pagi_freecount++; pag->pagi_freecount++;
up_read(&mp->m_peraglock); xfs_perag_put(pag);
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
} }
@ -1312,9 +1309,7 @@ xfs_imap(
xfs_buf_t *agbp; /* agi buffer */ xfs_buf_t *agbp; /* agi buffer */
int i; /* temp state */ int i; /* temp state */
down_read(&mp->m_peraglock);
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
up_read(&mp->m_peraglock);
if (error) { if (error) {
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_ialloc_read_agi() returned " "xfs_ialloc_read_agi() returned "
@ -1379,7 +1374,6 @@ xfs_imap(
XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
return XFS_ERROR(EINVAL); return XFS_ERROR(EINVAL);
} }
return 0; return 0;
} }
@ -1523,8 +1517,7 @@ xfs_ialloc_read_agi(
return error; return error;
agi = XFS_BUF_TO_AGI(*bpp); agi = XFS_BUF_TO_AGI(*bpp);
pag = &mp->m_perag[agno]; pag = xfs_perag_get(mp, agno);
if (!pag->pagi_init) { if (!pag->pagi_init) {
pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); pag->pagi_freecount = be32_to_cpu(agi->agi_freecount);
pag->pagi_count = be32_to_cpu(agi->agi_count); pag->pagi_count = be32_to_cpu(agi->agi_count);
@ -1537,6 +1530,7 @@ xfs_ialloc_read_agi(
*/ */
ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) ||
XFS_FORCED_SHUTDOWN(mp)); XFS_FORCED_SHUTDOWN(mp));
xfs_perag_put(pag);
return 0; return 0;
} }

View file

@ -374,7 +374,7 @@ xfs_iget(
return EINVAL; return EINVAL;
/* get the perag structure and ensure that it's inode capable */ /* get the perag structure and ensure that it's inode capable */
pag = xfs_get_perag(mp, ino); pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
if (!pag->pagi_inodeok) if (!pag->pagi_inodeok)
return EINVAL; return EINVAL;
ASSERT(pag->pag_ici_init); ASSERT(pag->pag_ici_init);
@ -398,7 +398,7 @@ again:
if (error) if (error)
goto out_error_or_again; goto out_error_or_again;
} }
xfs_put_perag(mp, pag); xfs_perag_put(pag);
*ipp = ip; *ipp = ip;
@ -417,7 +417,7 @@ out_error_or_again:
delay(1); delay(1);
goto again; goto again;
} }
xfs_put_perag(mp, pag); xfs_perag_put(pag);
return error; return error;
} }
@ -488,12 +488,12 @@ xfs_ireclaim(
* added to the tree assert that it's been there before to catch * added to the tree assert that it's been there before to catch
* problems with the inode life time early on. * problems with the inode life time early on.
*/ */
pag = xfs_get_perag(mp, ip->i_ino); pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
write_lock(&pag->pag_ici_lock); write_lock(&pag->pag_ici_lock);
if (!radix_tree_delete(&pag->pag_ici_root, agino)) if (!radix_tree_delete(&pag->pag_ici_root, agino))
ASSERT(0); ASSERT(0);
write_unlock(&pag->pag_ici_lock); write_unlock(&pag->pag_ici_lock);
xfs_put_perag(mp, pag); xfs_perag_put(pag);
/* /*
* Here we do an (almost) spurious inode lock in order to coordinate * Here we do an (almost) spurious inode lock in order to coordinate

View file

@ -151,7 +151,7 @@ xfs_imap_to_bp(
"an error %d on %s. Returning error.", "an error %d on %s. Returning error.",
error, mp->m_fsname); error, mp->m_fsname);
} else { } else {
ASSERT(buf_flags & XFS_BUF_TRYLOCK); ASSERT(buf_flags & XBF_TRYLOCK);
} }
return error; return error;
} }
@ -239,7 +239,7 @@ xfs_inotobp(
if (error) if (error)
return error; return error;
error = xfs_imap_to_bp(mp, tp, &imap, &bp, XFS_BUF_LOCK, imap_flags); error = xfs_imap_to_bp(mp, tp, &imap, &bp, XBF_LOCK, imap_flags);
if (error) if (error)
return error; return error;
@ -285,7 +285,7 @@ xfs_itobp(
return error; return error;
if (!bp) { if (!bp) {
ASSERT(buf_flags & XFS_BUF_TRYLOCK); ASSERT(buf_flags & XBF_TRYLOCK);
ASSERT(tp == NULL); ASSERT(tp == NULL);
*bpp = NULL; *bpp = NULL;
return EAGAIN; return EAGAIN;
@ -807,7 +807,7 @@ xfs_iread(
* Get pointers to the on-disk inode and the buffer containing it. * Get pointers to the on-disk inode and the buffer containing it.
*/ */
error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp, error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp,
XFS_BUF_LOCK, iget_flags); XBF_LOCK, iget_flags);
if (error) if (error)
return error; return error;
dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset); dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
@ -1751,7 +1751,7 @@ xfs_iunlink(
* Here we put the head pointer into our next pointer, * Here we put the head pointer into our next pointer,
* and then we fall through to point the head at us. * and then we fall through to point the head at us.
*/ */
error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK); error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK);
if (error) if (error)
return error; return error;
@ -1833,7 +1833,7 @@ xfs_iunlink_remove(
* of dealing with the buffer when there is no need to * of dealing with the buffer when there is no need to
* change it. * change it.
*/ */
error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK); error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK);
if (error) { if (error) {
cmn_err(CE_WARN, cmn_err(CE_WARN,
"xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.",
@ -1895,7 +1895,7 @@ xfs_iunlink_remove(
* Now last_ibp points to the buffer previous to us on * Now last_ibp points to the buffer previous to us on
* the unlinked list. Pull us from the list. * the unlinked list. Pull us from the list.
*/ */
error = xfs_itobp(mp, tp, ip, &dip, &ibp, XFS_BUF_LOCK); error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK);
if (error) { if (error) {
cmn_err(CE_WARN, cmn_err(CE_WARN,
"xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.",
@ -1946,8 +1946,9 @@ xfs_ifree_cluster(
xfs_inode_t *ip, **ip_found; xfs_inode_t *ip, **ip_found;
xfs_inode_log_item_t *iip; xfs_inode_log_item_t *iip;
xfs_log_item_t *lip; xfs_log_item_t *lip;
xfs_perag_t *pag = xfs_get_perag(mp, inum); struct xfs_perag *pag;
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum));
if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) { if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) {
blks_per_cluster = 1; blks_per_cluster = 1;
ninodes = mp->m_sb.sb_inopblock; ninodes = mp->m_sb.sb_inopblock;
@ -2039,7 +2040,7 @@ xfs_ifree_cluster(
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno,
mp->m_bsize * blks_per_cluster, mp->m_bsize * blks_per_cluster,
XFS_BUF_LOCK); XBF_LOCK);
pre_flushed = 0; pre_flushed = 0;
lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
@ -2088,7 +2089,7 @@ xfs_ifree_cluster(
} }
kmem_free(ip_found); kmem_free(ip_found);
xfs_put_perag(mp, pag); xfs_perag_put(pag);
} }
/* /*
@ -2150,7 +2151,7 @@ xfs_ifree(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, XFS_BUF_LOCK); error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, XBF_LOCK);
if (error) if (error)
return error; return error;
@ -2483,13 +2484,16 @@ __xfs_iunpin_wait(
return; return;
/* Give the log a push to start the unpinning I/O */ /* Give the log a push to start the unpinning I/O */
xfs_log_force(ip->i_mount, (iip && iip->ili_last_lsn) ? if (iip && iip->ili_last_lsn)
iip->ili_last_lsn : 0, XFS_LOG_FORCE); xfs_log_force_lsn(ip->i_mount, iip->ili_last_lsn, 0);
else
xfs_log_force(ip->i_mount, 0);
if (wait) if (wait)
wait_event(ip->i_ipin_wait, (atomic_read(&ip->i_pincount) == 0)); wait_event(ip->i_ipin_wait, (atomic_read(&ip->i_pincount) == 0));
} }
static inline void void
xfs_iunpin_wait( xfs_iunpin_wait(
xfs_inode_t *ip) xfs_inode_t *ip)
{ {
@ -2675,7 +2679,7 @@ xfs_iflush_cluster(
xfs_buf_t *bp) xfs_buf_t *bp)
{ {
xfs_mount_t *mp = ip->i_mount; xfs_mount_t *mp = ip->i_mount;
xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); struct xfs_perag *pag;
unsigned long first_index, mask; unsigned long first_index, mask;
unsigned long inodes_per_cluster; unsigned long inodes_per_cluster;
int ilist_size; int ilist_size;
@ -2686,6 +2690,7 @@ xfs_iflush_cluster(
int bufwasdelwri; int bufwasdelwri;
int i; int i;
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
ASSERT(pag->pagi_inodeok); ASSERT(pag->pagi_inodeok);
ASSERT(pag->pag_ici_init); ASSERT(pag->pag_ici_init);
@ -2693,7 +2698,7 @@ xfs_iflush_cluster(
ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *); ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *);
ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS); ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS);
if (!ilist) if (!ilist)
return 0; goto out_put;
mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1); mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask; first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask;
@ -2762,6 +2767,8 @@ xfs_iflush_cluster(
out_free: out_free:
read_unlock(&pag->pag_ici_lock); read_unlock(&pag->pag_ici_lock);
kmem_free(ilist); kmem_free(ilist);
out_put:
xfs_perag_put(pag);
return 0; return 0;
@ -2805,6 +2812,7 @@ cluster_corrupt_out:
*/ */
xfs_iflush_abort(iq); xfs_iflush_abort(iq);
kmem_free(ilist); kmem_free(ilist);
xfs_perag_put(pag);
return XFS_ERROR(EFSCORRUPTED); return XFS_ERROR(EFSCORRUPTED);
} }
@ -2827,8 +2835,6 @@ xfs_iflush(
xfs_dinode_t *dip; xfs_dinode_t *dip;
xfs_mount_t *mp; xfs_mount_t *mp;
int error; int error;
int noblock = (flags == XFS_IFLUSH_ASYNC_NOBLOCK);
enum { INT_DELWRI = (1 << 0), INT_ASYNC = (1 << 1) };
XFS_STATS_INC(xs_iflush_count); XFS_STATS_INC(xs_iflush_count);
@ -2840,15 +2846,6 @@ xfs_iflush(
iip = ip->i_itemp; iip = ip->i_itemp;
mp = ip->i_mount; mp = ip->i_mount;
/*
* If the inode isn't dirty, then just release the inode flush lock and
* do nothing.
*/
if (xfs_inode_clean(ip)) {
xfs_ifunlock(ip);
return 0;
}
/* /*
* We can't flush the inode until it is unpinned, so wait for it if we * We can't flush the inode until it is unpinned, so wait for it if we
* are allowed to block. We know noone new can pin it, because we are * are allowed to block. We know noone new can pin it, because we are
@ -2860,7 +2857,7 @@ xfs_iflush(
* in the same cluster are dirty, they will probably write the inode * in the same cluster are dirty, they will probably write the inode
* out for us if they occur after the log force completes. * out for us if they occur after the log force completes.
*/ */
if (noblock && xfs_ipincount(ip)) { if (!(flags & SYNC_WAIT) && xfs_ipincount(ip)) {
xfs_iunpin_nowait(ip); xfs_iunpin_nowait(ip);
xfs_ifunlock(ip); xfs_ifunlock(ip);
return EAGAIN; return EAGAIN;
@ -2893,61 +2890,11 @@ xfs_iflush(
return XFS_ERROR(EIO); return XFS_ERROR(EIO);
} }
/*
* Decide how buffer will be flushed out. This is done before
* the call to xfs_iflush_int because this field is zeroed by it.
*/
if (iip != NULL && iip->ili_format.ilf_fields != 0) {
/*
* Flush out the inode buffer according to the directions
* of the caller. In the cases where the caller has given
* us a choice choose the non-delwri case. This is because
* the inode is in the AIL and we need to get it out soon.
*/
switch (flags) {
case XFS_IFLUSH_SYNC:
case XFS_IFLUSH_DELWRI_ELSE_SYNC:
flags = 0;
break;
case XFS_IFLUSH_ASYNC_NOBLOCK:
case XFS_IFLUSH_ASYNC:
case XFS_IFLUSH_DELWRI_ELSE_ASYNC:
flags = INT_ASYNC;
break;
case XFS_IFLUSH_DELWRI:
flags = INT_DELWRI;
break;
default:
ASSERT(0);
flags = 0;
break;
}
} else {
switch (flags) {
case XFS_IFLUSH_DELWRI_ELSE_SYNC:
case XFS_IFLUSH_DELWRI_ELSE_ASYNC:
case XFS_IFLUSH_DELWRI:
flags = INT_DELWRI;
break;
case XFS_IFLUSH_ASYNC_NOBLOCK:
case XFS_IFLUSH_ASYNC:
flags = INT_ASYNC;
break;
case XFS_IFLUSH_SYNC:
flags = 0;
break;
default:
ASSERT(0);
flags = 0;
break;
}
}
/* /*
* Get the buffer containing the on-disk inode. * Get the buffer containing the on-disk inode.
*/ */
error = xfs_itobp(mp, NULL, ip, &dip, &bp, error = xfs_itobp(mp, NULL, ip, &dip, &bp,
noblock ? XFS_BUF_TRYLOCK : XFS_BUF_LOCK); (flags & SYNC_WAIT) ? XBF_LOCK : XBF_TRYLOCK);
if (error || !bp) { if (error || !bp) {
xfs_ifunlock(ip); xfs_ifunlock(ip);
return error; return error;
@ -2965,7 +2912,7 @@ xfs_iflush(
* get stuck waiting in the write for too long. * get stuck waiting in the write for too long.
*/ */
if (XFS_BUF_ISPINNED(bp)) if (XFS_BUF_ISPINNED(bp))
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); xfs_log_force(mp, 0);
/* /*
* inode clustering: * inode clustering:
@ -2975,13 +2922,10 @@ xfs_iflush(
if (error) if (error)
goto cluster_corrupt_out; goto cluster_corrupt_out;
if (flags & INT_DELWRI) { if (flags & SYNC_WAIT)
xfs_bdwrite(mp, bp);
} else if (flags & INT_ASYNC) {
error = xfs_bawrite(mp, bp);
} else {
error = xfs_bwrite(mp, bp); error = xfs_bwrite(mp, bp);
} else
xfs_bdwrite(mp, bp);
return error; return error;
corrupt_out: corrupt_out:
@ -3016,16 +2960,6 @@ xfs_iflush_int(
iip = ip->i_itemp; iip = ip->i_itemp;
mp = ip->i_mount; mp = ip->i_mount;
/*
* If the inode isn't dirty, then just release the inode
* flush lock and do nothing.
*/
if (xfs_inode_clean(ip)) {
xfs_ifunlock(ip);
return 0;
}
/* set *dip = inode's place in the buffer */ /* set *dip = inode's place in the buffer */
dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset); dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);

View file

@ -419,16 +419,6 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
#define XFS_IOLOCK_DEP(flags) (((flags) & XFS_IOLOCK_DEP_MASK) >> XFS_IOLOCK_SHIFT) #define XFS_IOLOCK_DEP(flags) (((flags) & XFS_IOLOCK_DEP_MASK) >> XFS_IOLOCK_SHIFT)
#define XFS_ILOCK_DEP(flags) (((flags) & XFS_ILOCK_DEP_MASK) >> XFS_ILOCK_SHIFT) #define XFS_ILOCK_DEP(flags) (((flags) & XFS_ILOCK_DEP_MASK) >> XFS_ILOCK_SHIFT)
/*
* Flags for xfs_iflush()
*/
#define XFS_IFLUSH_DELWRI_ELSE_SYNC 1
#define XFS_IFLUSH_DELWRI_ELSE_ASYNC 2
#define XFS_IFLUSH_SYNC 3
#define XFS_IFLUSH_ASYNC 4
#define XFS_IFLUSH_DELWRI 5
#define XFS_IFLUSH_ASYNC_NOBLOCK 6
/* /*
* Flags for xfs_itruncate_start(). * Flags for xfs_itruncate_start().
*/ */
@ -483,6 +473,7 @@ int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
void xfs_iext_realloc(xfs_inode_t *, int, int); void xfs_iext_realloc(xfs_inode_t *, int, int);
void xfs_ipin(xfs_inode_t *); void xfs_ipin(xfs_inode_t *);
void xfs_iunpin(xfs_inode_t *); void xfs_iunpin(xfs_inode_t *);
void xfs_iunpin_wait(xfs_inode_t *);
int xfs_iflush(xfs_inode_t *, uint); int xfs_iflush(xfs_inode_t *, uint);
void xfs_ichgtime(xfs_inode_t *, int); void xfs_ichgtime(xfs_inode_t *, int);
void xfs_lock_inodes(xfs_inode_t **, int, uint); void xfs_lock_inodes(xfs_inode_t **, int, uint);

View file

@ -228,7 +228,7 @@ xfs_inode_item_format(
vecp->i_addr = (xfs_caddr_t)&iip->ili_format; vecp->i_addr = (xfs_caddr_t)&iip->ili_format;
vecp->i_len = sizeof(xfs_inode_log_format_t); vecp->i_len = sizeof(xfs_inode_log_format_t);
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IFORMAT); vecp->i_type = XLOG_REG_TYPE_IFORMAT;
vecp++; vecp++;
nvecs = 1; nvecs = 1;
@ -279,7 +279,7 @@ xfs_inode_item_format(
vecp->i_addr = (xfs_caddr_t)&ip->i_d; vecp->i_addr = (xfs_caddr_t)&ip->i_d;
vecp->i_len = sizeof(struct xfs_icdinode); vecp->i_len = sizeof(struct xfs_icdinode);
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ICORE); vecp->i_type = XLOG_REG_TYPE_ICORE;
vecp++; vecp++;
nvecs++; nvecs++;
iip->ili_format.ilf_fields |= XFS_ILOG_CORE; iip->ili_format.ilf_fields |= XFS_ILOG_CORE;
@ -336,7 +336,7 @@ xfs_inode_item_format(
vecp->i_addr = vecp->i_addr =
(char *)(ip->i_df.if_u1.if_extents); (char *)(ip->i_df.if_u1.if_extents);
vecp->i_len = ip->i_df.if_bytes; vecp->i_len = ip->i_df.if_bytes;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT); vecp->i_type = XLOG_REG_TYPE_IEXT;
} else } else
#endif #endif
{ {
@ -355,7 +355,7 @@ xfs_inode_item_format(
vecp->i_addr = (xfs_caddr_t)ext_buffer; vecp->i_addr = (xfs_caddr_t)ext_buffer;
vecp->i_len = xfs_iextents_copy(ip, ext_buffer, vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
XFS_DATA_FORK); XFS_DATA_FORK);
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IEXT); vecp->i_type = XLOG_REG_TYPE_IEXT;
} }
ASSERT(vecp->i_len <= ip->i_df.if_bytes); ASSERT(vecp->i_len <= ip->i_df.if_bytes);
iip->ili_format.ilf_dsize = vecp->i_len; iip->ili_format.ilf_dsize = vecp->i_len;
@ -373,7 +373,7 @@ xfs_inode_item_format(
ASSERT(ip->i_df.if_broot != NULL); ASSERT(ip->i_df.if_broot != NULL);
vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot; vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot;
vecp->i_len = ip->i_df.if_broot_bytes; vecp->i_len = ip->i_df.if_broot_bytes;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IBROOT); vecp->i_type = XLOG_REG_TYPE_IBROOT;
vecp++; vecp++;
nvecs++; nvecs++;
iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes; iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes;
@ -399,7 +399,7 @@ xfs_inode_item_format(
ASSERT((ip->i_df.if_real_bytes == 0) || ASSERT((ip->i_df.if_real_bytes == 0) ||
(ip->i_df.if_real_bytes == data_bytes)); (ip->i_df.if_real_bytes == data_bytes));
vecp->i_len = (int)data_bytes; vecp->i_len = (int)data_bytes;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ILOCAL); vecp->i_type = XLOG_REG_TYPE_ILOCAL;
vecp++; vecp++;
nvecs++; nvecs++;
iip->ili_format.ilf_dsize = (unsigned)data_bytes; iip->ili_format.ilf_dsize = (unsigned)data_bytes;
@ -477,7 +477,7 @@ xfs_inode_item_format(
vecp->i_len = xfs_iextents_copy(ip, ext_buffer, vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
XFS_ATTR_FORK); XFS_ATTR_FORK);
#endif #endif
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_EXT); vecp->i_type = XLOG_REG_TYPE_IATTR_EXT;
iip->ili_format.ilf_asize = vecp->i_len; iip->ili_format.ilf_asize = vecp->i_len;
vecp++; vecp++;
nvecs++; nvecs++;
@ -492,7 +492,7 @@ xfs_inode_item_format(
ASSERT(ip->i_afp->if_broot != NULL); ASSERT(ip->i_afp->if_broot != NULL);
vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot; vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot;
vecp->i_len = ip->i_afp->if_broot_bytes; vecp->i_len = ip->i_afp->if_broot_bytes;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_BROOT); vecp->i_type = XLOG_REG_TYPE_IATTR_BROOT;
vecp++; vecp++;
nvecs++; nvecs++;
iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes; iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes;
@ -516,7 +516,7 @@ xfs_inode_item_format(
ASSERT((ip->i_afp->if_real_bytes == 0) || ASSERT((ip->i_afp->if_real_bytes == 0) ||
(ip->i_afp->if_real_bytes == data_bytes)); (ip->i_afp->if_real_bytes == data_bytes));
vecp->i_len = (int)data_bytes; vecp->i_len = (int)data_bytes;
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_IATTR_LOCAL); vecp->i_type = XLOG_REG_TYPE_IATTR_LOCAL;
vecp++; vecp++;
nvecs++; nvecs++;
iip->ili_format.ilf_asize = (unsigned)data_bytes; iip->ili_format.ilf_asize = (unsigned)data_bytes;
@ -602,33 +602,20 @@ xfs_inode_item_trylock(
if (!xfs_iflock_nowait(ip)) { if (!xfs_iflock_nowait(ip)) {
/* /*
* If someone else isn't already trying to push the inode * inode has already been flushed to the backing buffer,
* buffer, we get to do it. * leave it locked in shared mode, pushbuf routine will
* unlock it.
*/ */
if (iip->ili_pushbuf_flag == 0) { return XFS_ITEM_PUSHBUF;
iip->ili_pushbuf_flag = 1;
#ifdef DEBUG
iip->ili_push_owner = current_pid();
#endif
/*
* Inode is left locked in shared mode.
* Pushbuf routine gets to unlock it.
*/
return XFS_ITEM_PUSHBUF;
} else {
/*
* We hold the AIL lock, so we must specify the
* NONOTIFY flag so that we won't double trip.
*/
xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY);
return XFS_ITEM_FLUSHING;
}
/* NOTREACHED */
} }
/* Stale items should force out the iclog */ /* Stale items should force out the iclog */
if (ip->i_flags & XFS_ISTALE) { if (ip->i_flags & XFS_ISTALE) {
xfs_ifunlock(ip); xfs_ifunlock(ip);
/*
* we hold the AIL lock - notify the unlock routine of this
* so it doesn't try to get the lock again.
*/
xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY); xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY);
return XFS_ITEM_PINNED; return XFS_ITEM_PINNED;
} }
@ -746,11 +733,8 @@ xfs_inode_item_committed(
* This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK * 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. * 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 * 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 initiate a bawrite on that * marked delayed write. If that's the case, we'll promote it and that will
* buffer to expedite the process. * allow the caller to write the buffer by triggering the xfsbufd to run.
*
* We aren't holding the AIL lock (or the flush lock) when this gets called,
* so it is inherently race-y.
*/ */
STATIC void STATIC void
xfs_inode_item_pushbuf( xfs_inode_item_pushbuf(
@ -759,82 +743,30 @@ xfs_inode_item_pushbuf(
xfs_inode_t *ip; xfs_inode_t *ip;
xfs_mount_t *mp; xfs_mount_t *mp;
xfs_buf_t *bp; xfs_buf_t *bp;
uint dopush;
ip = iip->ili_inode; ip = iip->ili_inode;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
/*
* The ili_pushbuf_flag keeps others from
* trying to duplicate our effort.
*/
ASSERT(iip->ili_pushbuf_flag != 0);
ASSERT(iip->ili_push_owner == current_pid());
/* /*
* If a flush is not in progress anymore, chances are that the * If a flush is not in progress anymore, chances are that the
* inode was taken off the AIL. So, just get out. * inode was taken off the AIL. So, just get out.
*/ */
if (completion_done(&ip->i_flush) || if (completion_done(&ip->i_flush) ||
((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) {
iip->ili_pushbuf_flag = 0;
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
return; return;
} }
mp = ip->i_mount; mp = ip->i_mount;
bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno, bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno,
iip->ili_format.ilf_len, XFS_INCORE_TRYLOCK); iip->ili_format.ilf_len, XBF_TRYLOCK);
if (bp != NULL) {
if (XFS_BUF_ISDELAYWRITE(bp)) {
/*
* We were racing with iflush because we don't hold
* the AIL lock or the flush lock. However, at this point,
* we have the buffer, and we know that it's dirty.
* So, it's possible that iflush raced with us, and
* this item is already taken off the AIL.
* If not, we can flush it async.
*/
dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) &&
!completion_done(&ip->i_flush));
iip->ili_pushbuf_flag = 0;
xfs_iunlock(ip, XFS_ILOCK_SHARED);
trace_xfs_inode_item_push(bp, _RET_IP_);
if (XFS_BUF_ISPINNED(bp)) {
xfs_log_force(mp, (xfs_lsn_t)0,
XFS_LOG_FORCE);
}
if (dopush) {
int error;
error = xfs_bawrite(mp, bp);
if (error)
xfs_fs_cmn_err(CE_WARN, mp,
"xfs_inode_item_pushbuf: pushbuf error %d on iip %p, bp %p",
error, iip, bp);
} else {
xfs_buf_relse(bp);
}
} else {
iip->ili_pushbuf_flag = 0;
xfs_iunlock(ip, XFS_ILOCK_SHARED);
xfs_buf_relse(bp);
}
return;
}
/*
* We have to be careful about resetting pushbuf flag too early (above).
* Even though in theory we can do it as soon as we have the buflock,
* we don't want others to be doing work needlessly. They'll come to
* this function thinking that pushing the buffer is their
* responsibility only to find that the buffer is still locked by
* another doing the same thing
*/
iip->ili_pushbuf_flag = 0;
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!bp)
return;
if (XFS_BUF_ISDELAYWRITE(bp))
xfs_buf_delwri_promote(bp);
xfs_buf_relse(bp);
return; return;
} }
@ -867,10 +799,14 @@ xfs_inode_item_push(
iip->ili_format.ilf_fields != 0); iip->ili_format.ilf_fields != 0);
/* /*
* Write out the inode. The completion routine ('iflush_done') will * Push the inode to it's backing buffer. This will not remove the
* pull it from the AIL, mark it clean, unlock the flush lock. * 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 th einode from the AIL, mark it clean and unlock the flush
* lock.
*/ */
(void) xfs_iflush(ip, XFS_IFLUSH_ASYNC); (void) xfs_iflush(ip, 0);
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
return; return;
@ -934,7 +870,6 @@ xfs_inode_item_init(
/* /*
We have zeroed memory. No need ... We have zeroed memory. No need ...
iip->ili_extents_buf = NULL; iip->ili_extents_buf = NULL;
iip->ili_pushbuf_flag = 0;
*/ */
iip->ili_format.ilf_type = XFS_LI_INODE; iip->ili_format.ilf_type = XFS_LI_INODE;

View file

@ -144,12 +144,6 @@ typedef struct xfs_inode_log_item {
data exts */ data exts */
struct xfs_bmbt_rec *ili_aextents_buf; /* array of logged struct xfs_bmbt_rec *ili_aextents_buf; /* array of logged
attr exts */ attr exts */
unsigned int ili_pushbuf_flag; /* one bit used in push_ail */
#ifdef DEBUG
uint64_t ili_push_owner; /* one who sets pushbuf_flag
above gets to push the buf */
#endif
#ifdef XFS_TRANS_DEBUG #ifdef XFS_TRANS_DEBUG
int ili_root_size; int ili_root_size;
char *ili_orig_root; char *ili_orig_root;

View file

@ -408,8 +408,10 @@ xfs_bulkstat(
(XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog); (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);
nimask = ~(nicluster - 1); nimask = ~(nicluster - 1);
nbcluster = nicluster >> mp->m_sb.sb_inopblog; nbcluster = nicluster >> mp->m_sb.sb_inopblog;
irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4, irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4);
KM_SLEEP | KM_MAYFAIL | KM_LARGE); if (!irbuf)
return ENOMEM;
nirbuf = irbsize / sizeof(*irbuf); nirbuf = irbsize / sizeof(*irbuf);
/* /*
@ -420,9 +422,7 @@ xfs_bulkstat(
while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) { while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
cond_resched(); cond_resched();
bp = NULL; bp = NULL;
down_read(&mp->m_peraglock);
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
up_read(&mp->m_peraglock);
if (error) { if (error) {
/* /*
* Skip this allocation group and go to the next one. * Skip this allocation group and go to the next one.
@ -729,7 +729,7 @@ xfs_bulkstat(
/* /*
* Done, we're either out of filesystem or space to put the data. * Done, we're either out of filesystem or space to put the data.
*/ */
kmem_free(irbuf); kmem_free_large(irbuf);
*ubcountp = ubelem; *ubcountp = ubelem;
/* /*
* Found some inodes, return them now and return the error next time. * Found some inodes, return them now and return the error next time.
@ -849,9 +849,7 @@ xfs_inumbers(
agbp = NULL; agbp = NULL;
while (left > 0 && agno < mp->m_sb.sb_agcount) { while (left > 0 && agno < mp->m_sb.sb_agcount) {
if (agbp == NULL) { if (agbp == NULL) {
down_read(&mp->m_peraglock);
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
up_read(&mp->m_peraglock);
if (error) { if (error) {
/* /*
* If we can't read the AGI of this ag, * If we can't read the AGI of this ag,

View file

@ -50,7 +50,6 @@ kmem_zone_t *xfs_log_ticket_zone;
(off) += (bytes);} (off) += (bytes);}
/* Local miscellaneous function prototypes */ /* Local miscellaneous function prototypes */
STATIC int xlog_bdstrat_cb(struct xfs_buf *);
STATIC int xlog_commit_record(xfs_mount_t *mp, xlog_ticket_t *ticket, STATIC int xlog_commit_record(xfs_mount_t *mp, xlog_ticket_t *ticket,
xlog_in_core_t **, xfs_lsn_t *); xlog_in_core_t **, xfs_lsn_t *);
STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp, STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp,
@ -80,11 +79,6 @@ STATIC int xlog_state_release_iclog(xlog_t *log,
STATIC void xlog_state_switch_iclogs(xlog_t *log, STATIC void xlog_state_switch_iclogs(xlog_t *log,
xlog_in_core_t *iclog, xlog_in_core_t *iclog,
int eventual_size); int eventual_size);
STATIC int xlog_state_sync(xlog_t *log,
xfs_lsn_t lsn,
uint flags,
int *log_flushed);
STATIC int xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed);
STATIC void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog); STATIC void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog);
/* local functions to manipulate grant head */ /* local functions to manipulate grant head */
@ -297,65 +291,6 @@ xfs_log_done(xfs_mount_t *mp,
return lsn; return lsn;
} /* xfs_log_done */ } /* xfs_log_done */
/*
* Force the in-core log to disk. If flags == XFS_LOG_SYNC,
* the force is done synchronously.
*
* Asynchronous forces are implemented by setting the WANT_SYNC
* bit in the appropriate in-core log and then returning.
*
* Synchronous forces are implemented with a signal variable. All callers
* to force a given lsn to disk will wait on a the sv attached to the
* specific in-core log. When given in-core log finally completes its
* write to disk, that thread will wake up all threads waiting on the
* sv.
*/
int
_xfs_log_force(
xfs_mount_t *mp,
xfs_lsn_t lsn,
uint flags,
int *log_flushed)
{
xlog_t *log = mp->m_log;
int dummy;
if (!log_flushed)
log_flushed = &dummy;
ASSERT(flags & XFS_LOG_FORCE);
XFS_STATS_INC(xs_log_force);
if (log->l_flags & XLOG_IO_ERROR)
return XFS_ERROR(EIO);
if (lsn == 0)
return xlog_state_sync_all(log, flags, log_flushed);
else
return xlog_state_sync(log, lsn, flags, log_flushed);
} /* _xfs_log_force */
/*
* Wrapper for _xfs_log_force(), to be used when caller doesn't care
* about errors or whether the log was flushed or not. This is the normal
* interface to use when trying to unpin items or move the log forward.
*/
void
xfs_log_force(
xfs_mount_t *mp,
xfs_lsn_t lsn,
uint flags)
{
int error;
error = _xfs_log_force(mp, lsn, flags, NULL);
if (error) {
xfs_fs_cmn_err(CE_WARN, mp, "xfs_log_force: "
"error %d returned.", error);
}
}
/* /*
* Attaches a new iclog I/O completion callback routine during * Attaches a new iclog I/O completion callback routine during
* transaction commit. If the log is in error state, a non-zero * transaction commit. If the log is in error state, a non-zero
@ -602,7 +537,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
if (mp->m_flags & XFS_MOUNT_RDONLY) if (mp->m_flags & XFS_MOUNT_RDONLY)
return 0; return 0;
error = _xfs_log_force(mp, 0, XFS_LOG_FORCE|XFS_LOG_SYNC, NULL); error = _xfs_log_force(mp, XFS_LOG_SYNC, NULL);
ASSERT(error || !(XLOG_FORCED_SHUTDOWN(log))); ASSERT(error || !(XLOG_FORCED_SHUTDOWN(log)));
#ifdef DEBUG #ifdef DEBUG
@ -618,7 +553,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
if (! (XLOG_FORCED_SHUTDOWN(log))) { if (! (XLOG_FORCED_SHUTDOWN(log))) {
reg[0].i_addr = (void*)&magic; reg[0].i_addr = (void*)&magic;
reg[0].i_len = sizeof(magic); reg[0].i_len = sizeof(magic);
XLOG_VEC_SET_TYPE(&reg[0], XLOG_REG_TYPE_UNMOUNT); reg[0].i_type = XLOG_REG_TYPE_UNMOUNT;
error = xfs_log_reserve(mp, 600, 1, &tic, error = xfs_log_reserve(mp, 600, 1, &tic,
XFS_LOG, 0, XLOG_UNMOUNT_REC_TYPE); XFS_LOG, 0, XLOG_UNMOUNT_REC_TYPE);
@ -987,35 +922,6 @@ xlog_iodone(xfs_buf_t *bp)
} /* xlog_iodone */ } /* xlog_iodone */
/*
* The bdstrat callback function for log bufs. This gives us a central
* place to trap bufs in case we get hit by a log I/O error and need to
* shutdown. Actually, in practice, even when we didn't get a log error,
* we transition the iclogs to IOERROR state *after* flushing all existing
* iclogs to disk. This is because we don't want anymore new transactions to be
* started or completed afterwards.
*/
STATIC int
xlog_bdstrat_cb(struct xfs_buf *bp)
{
xlog_in_core_t *iclog;
iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *);
if ((iclog->ic_state & XLOG_STATE_IOERROR) == 0) {
/* note for irix bstrat will need struct bdevsw passed
* Fix the following macro if the code ever is merged
*/
XFS_bdstrat(bp);
return 0;
}
XFS_BUF_ERROR(bp, EIO);
XFS_BUF_STALE(bp);
xfs_biodone(bp);
return XFS_ERROR(EIO);
}
/* /*
* Return size of each in-core log record buffer. * Return size of each in-core log record buffer.
* *
@ -1158,7 +1064,6 @@ xlog_alloc_log(xfs_mount_t *mp,
if (!bp) if (!bp)
goto out_free_log; goto out_free_log;
XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
ASSERT(XFS_BUF_ISBUSY(bp)); ASSERT(XFS_BUF_ISBUSY(bp));
ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
@ -1196,7 +1101,6 @@ xlog_alloc_log(xfs_mount_t *mp,
if (!XFS_BUF_CPSEMA(bp)) if (!XFS_BUF_CPSEMA(bp))
ASSERT(0); ASSERT(0);
XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
iclog->ic_bp = bp; iclog->ic_bp = bp;
iclog->ic_data = bp->b_addr; iclog->ic_data = bp->b_addr;
@ -1268,7 +1172,7 @@ xlog_commit_record(xfs_mount_t *mp,
reg[0].i_addr = NULL; reg[0].i_addr = NULL;
reg[0].i_len = 0; reg[0].i_len = 0;
XLOG_VEC_SET_TYPE(&reg[0], XLOG_REG_TYPE_COMMIT); reg[0].i_type = XLOG_REG_TYPE_COMMIT;
ASSERT_ALWAYS(iclog); ASSERT_ALWAYS(iclog);
if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp, if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp,
@ -1343,6 +1247,37 @@ xlog_grant_push_ail(xfs_mount_t *mp,
xfs_trans_ail_push(log->l_ailp, threshold_lsn); xfs_trans_ail_push(log->l_ailp, threshold_lsn);
} /* xlog_grant_push_ail */ } /* xlog_grant_push_ail */
/*
* The bdstrat callback function for log bufs. This gives us a central
* place to trap bufs in case we get hit by a log I/O error and need to
* shutdown. Actually, in practice, even when we didn't get a log error,
* we transition the iclogs to IOERROR state *after* flushing all existing
* iclogs to disk. This is because we don't want anymore new transactions to be
* started or completed afterwards.
*/
STATIC int
xlog_bdstrat(
struct xfs_buf *bp)
{
struct xlog_in_core *iclog;
iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *);
if (iclog->ic_state & XLOG_STATE_IOERROR) {
XFS_BUF_ERROR(bp, EIO);
XFS_BUF_STALE(bp);
xfs_biodone(bp);
/*
* It would seem logical to return EIO here, but we rely on
* the log state machine to propagate I/O errors instead of
* doing it here.
*/
return 0;
}
bp->b_flags |= _XBF_RUN_QUEUES;
xfs_buf_iorequest(bp);
return 0;
}
/* /*
* Flush out the in-core log (iclog) to the on-disk log in an asynchronous * Flush out the in-core log (iclog) to the on-disk log in an asynchronous
@ -1462,7 +1397,7 @@ xlog_sync(xlog_t *log,
*/ */
XFS_BUF_WRITE(bp); XFS_BUF_WRITE(bp);
if ((error = XFS_bwrite(bp))) { if ((error = xlog_bdstrat(bp))) {
xfs_ioerror_alert("xlog_sync", log->l_mp, bp, xfs_ioerror_alert("xlog_sync", log->l_mp, bp,
XFS_BUF_ADDR(bp)); XFS_BUF_ADDR(bp));
return error; return error;
@ -1502,7 +1437,7 @@ xlog_sync(xlog_t *log,
/* account for internal log which doesn't start at block #0 */ /* account for internal log which doesn't start at block #0 */
XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart); XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart);
XFS_BUF_WRITE(bp); XFS_BUF_WRITE(bp);
if ((error = XFS_bwrite(bp))) { if ((error = xlog_bdstrat(bp))) {
xfs_ioerror_alert("xlog_sync (split)", log->l_mp, xfs_ioerror_alert("xlog_sync (split)", log->l_mp,
bp, XFS_BUF_ADDR(bp)); bp, XFS_BUF_ADDR(bp));
return error; return error;
@ -2854,7 +2789,6 @@ xlog_state_switch_iclogs(xlog_t *log,
log->l_iclog = iclog->ic_next; log->l_iclog = iclog->ic_next;
} /* xlog_state_switch_iclogs */ } /* xlog_state_switch_iclogs */
/* /*
* Write out all data in the in-core log as of this exact moment in time. * Write out all data in the in-core log as of this exact moment in time.
* *
@ -2882,11 +2816,17 @@ xlog_state_switch_iclogs(xlog_t *log,
* b) when we return from flushing out this iclog, it is still * b) when we return from flushing out this iclog, it is still
* not in the active nor dirty state. * not in the active nor dirty state.
*/ */
STATIC int int
xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) _xfs_log_force(
struct xfs_mount *mp,
uint flags,
int *log_flushed)
{ {
xlog_in_core_t *iclog; struct log *log = mp->m_log;
xfs_lsn_t lsn; struct xlog_in_core *iclog;
xfs_lsn_t lsn;
XFS_STATS_INC(xs_log_force);
spin_lock(&log->l_icloglock); spin_lock(&log->l_icloglock);
@ -2932,7 +2872,9 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed)
if (xlog_state_release_iclog(log, iclog)) if (xlog_state_release_iclog(log, iclog))
return XFS_ERROR(EIO); return XFS_ERROR(EIO);
*log_flushed = 1;
if (log_flushed)
*log_flushed = 1;
spin_lock(&log->l_icloglock); spin_lock(&log->l_icloglock);
if (be64_to_cpu(iclog->ic_header.h_lsn) == lsn && if (be64_to_cpu(iclog->ic_header.h_lsn) == lsn &&
iclog->ic_state != XLOG_STATE_DIRTY) iclog->ic_state != XLOG_STATE_DIRTY)
@ -2976,19 +2918,37 @@ maybe_sleep:
*/ */
if (iclog->ic_state & XLOG_STATE_IOERROR) if (iclog->ic_state & XLOG_STATE_IOERROR)
return XFS_ERROR(EIO); return XFS_ERROR(EIO);
*log_flushed = 1; if (log_flushed)
*log_flushed = 1;
} else { } else {
no_sleep: no_sleep:
spin_unlock(&log->l_icloglock); spin_unlock(&log->l_icloglock);
} }
return 0; return 0;
} /* xlog_state_sync_all */ }
/* /*
* Used by code which implements synchronous log forces. * Wrapper for _xfs_log_force(), to be used when caller doesn't care
* about errors or whether the log was flushed or not. This is the normal
* interface to use when trying to unpin items or move the log forward.
*/
void
xfs_log_force(
xfs_mount_t *mp,
uint flags)
{
int error;
error = _xfs_log_force(mp, flags, NULL);
if (error) {
xfs_fs_cmn_err(CE_WARN, mp, "xfs_log_force: "
"error %d returned.", error);
}
}
/*
* Force the in-core log to disk for a specific LSN.
* *
* Find in-core log with lsn. * Find in-core log with lsn.
* If it is in the DIRTY state, just return. * If it is in the DIRTY state, just return.
@ -2996,109 +2956,142 @@ no_sleep:
* state and go to sleep or return. * state and go to sleep or return.
* If it is in any other state, go to sleep or return. * If it is in any other state, go to sleep or return.
* *
* If filesystem activity goes to zero, the iclog will get flushed only by * Synchronous forces are implemented with a signal variable. All callers
* bdflush(). * to force a given lsn to disk will wait on a the sv attached to the
* specific in-core log. When given in-core log finally completes its
* write to disk, that thread will wake up all threads waiting on the
* sv.
*/ */
STATIC int int
xlog_state_sync(xlog_t *log, _xfs_log_force_lsn(
xfs_lsn_t lsn, struct xfs_mount *mp,
uint flags, xfs_lsn_t lsn,
int *log_flushed) uint flags,
int *log_flushed)
{ {
xlog_in_core_t *iclog; struct log *log = mp->m_log;
int already_slept = 0; struct xlog_in_core *iclog;
int already_slept = 0;
ASSERT(lsn != 0);
XFS_STATS_INC(xs_log_force);
try_again: try_again:
spin_lock(&log->l_icloglock); spin_lock(&log->l_icloglock);
iclog = log->l_iclog; iclog = log->l_iclog;
if (iclog->ic_state & XLOG_STATE_IOERROR) {
if (iclog->ic_state & XLOG_STATE_IOERROR) {
spin_unlock(&log->l_icloglock);
return XFS_ERROR(EIO);
}
do {
if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) {
iclog = iclog->ic_next;
continue;
}
if (iclog->ic_state == XLOG_STATE_DIRTY) {
spin_unlock(&log->l_icloglock); spin_unlock(&log->l_icloglock);
return 0; return XFS_ERROR(EIO);
} }
if (iclog->ic_state == XLOG_STATE_ACTIVE) { do {
/* if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) {
* We sleep here if we haven't already slept (e.g. iclog = iclog->ic_next;
* this is the first time we've looked at the correct continue;
* iclog buf) and the buffer before us is going to }
* be sync'ed. The reason for this is that if we
* are doing sync transactions here, by waiting for if (iclog->ic_state == XLOG_STATE_DIRTY) {
* the previous I/O to complete, we can allow a few spin_unlock(&log->l_icloglock);
* more transactions into this iclog before we close return 0;
* it down. }
*
* Otherwise, we mark the buffer WANT_SYNC, and bump if (iclog->ic_state == XLOG_STATE_ACTIVE) {
* up the refcnt so we can release the log (which drops /*
* the ref count). The state switch keeps new transaction * We sleep here if we haven't already slept (e.g.
* commits from using this buffer. When the current commits * this is the first time we've looked at the correct
* finish writing into the buffer, the refcount will drop to * iclog buf) and the buffer before us is going to
* zero and the buffer will go out then. * be sync'ed. The reason for this is that if we
*/ * are doing sync transactions here, by waiting for
if (!already_slept && * the previous I/O to complete, we can allow a few
(iclog->ic_prev->ic_state & (XLOG_STATE_WANT_SYNC | * more transactions into this iclog before we close
XLOG_STATE_SYNCING))) { * it down.
ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR)); *
XFS_STATS_INC(xs_log_force_sleep); * Otherwise, we mark the buffer WANT_SYNC, and bump
sv_wait(&iclog->ic_prev->ic_write_wait, PSWP, * up the refcnt so we can release the log (which
&log->l_icloglock, s); * drops the ref count). The state switch keeps new
*log_flushed = 1; * transaction commits from using this buffer. When
already_slept = 1; * the current commits finish writing into the buffer,
goto try_again; * the refcount will drop to zero and the buffer will
} else { * go out then.
*/
if (!already_slept &&
(iclog->ic_prev->ic_state &
(XLOG_STATE_WANT_SYNC | XLOG_STATE_SYNCING))) {
ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR));
XFS_STATS_INC(xs_log_force_sleep);
sv_wait(&iclog->ic_prev->ic_write_wait,
PSWP, &log->l_icloglock, s);
if (log_flushed)
*log_flushed = 1;
already_slept = 1;
goto try_again;
}
atomic_inc(&iclog->ic_refcnt); atomic_inc(&iclog->ic_refcnt);
xlog_state_switch_iclogs(log, iclog, 0); xlog_state_switch_iclogs(log, iclog, 0);
spin_unlock(&log->l_icloglock); spin_unlock(&log->l_icloglock);
if (xlog_state_release_iclog(log, iclog)) if (xlog_state_release_iclog(log, iclog))
return XFS_ERROR(EIO); return XFS_ERROR(EIO);
*log_flushed = 1; if (log_flushed)
*log_flushed = 1;
spin_lock(&log->l_icloglock); spin_lock(&log->l_icloglock);
} }
}
if ((flags & XFS_LOG_SYNC) && /* sleep */ if ((flags & XFS_LOG_SYNC) && /* sleep */
!(iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) { !(iclog->ic_state &
(XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) {
/*
* Don't wait on completion if we know that we've
* gotten a log write error.
*/
if (iclog->ic_state & XLOG_STATE_IOERROR) {
spin_unlock(&log->l_icloglock);
return XFS_ERROR(EIO);
}
XFS_STATS_INC(xs_log_force_sleep);
sv_wait(&iclog->ic_force_wait, PSWP, &log->l_icloglock, s);
/*
* No need to grab the log lock here since we're
* only deciding whether or not to return EIO
* and the memory read should be atomic.
*/
if (iclog->ic_state & XLOG_STATE_IOERROR)
return XFS_ERROR(EIO);
/* if (log_flushed)
* Don't wait on completion if we know that we've *log_flushed = 1;
* gotten a log write error. } else { /* just return */
*/
if (iclog->ic_state & XLOG_STATE_IOERROR) {
spin_unlock(&log->l_icloglock); spin_unlock(&log->l_icloglock);
return XFS_ERROR(EIO);
} }
XFS_STATS_INC(xs_log_force_sleep);
sv_wait(&iclog->ic_force_wait, PSWP, &log->l_icloglock, s); return 0;
/* } while (iclog != log->l_iclog);
* No need to grab the log lock here since we're
* only deciding whether or not to return EIO spin_unlock(&log->l_icloglock);
* and the memory read should be atomic.
*/
if (iclog->ic_state & XLOG_STATE_IOERROR)
return XFS_ERROR(EIO);
*log_flushed = 1;
} else { /* just return */
spin_unlock(&log->l_icloglock);
}
return 0; return 0;
}
} while (iclog != log->l_iclog); /*
* Wrapper for _xfs_log_force_lsn(), to be used when caller doesn't care
spin_unlock(&log->l_icloglock); * about errors or whether the log was flushed or not. This is the normal
return 0; * interface to use when trying to unpin items or move the log forward.
} /* xlog_state_sync */ */
void
xfs_log_force_lsn(
xfs_mount_t *mp,
xfs_lsn_t lsn,
uint flags)
{
int error;
error = _xfs_log_force_lsn(mp, lsn, flags, NULL);
if (error) {
xfs_fs_cmn_err(CE_WARN, mp, "xfs_log_force: "
"error %d returned.", error);
}
}
/* /*
* Called when we want to mark the current iclog as being ready to sync to * Called when we want to mark the current iclog as being ready to sync to
@ -3463,7 +3456,6 @@ xfs_log_force_umount(
xlog_ticket_t *tic; xlog_ticket_t *tic;
xlog_t *log; xlog_t *log;
int retval; int retval;
int dummy;
log = mp->m_log; log = mp->m_log;
@ -3537,13 +3529,14 @@ xfs_log_force_umount(
} }
spin_unlock(&log->l_grant_lock); spin_unlock(&log->l_grant_lock);
if (! (log->l_iclog->ic_state & XLOG_STATE_IOERROR)) { if (!(log->l_iclog->ic_state & XLOG_STATE_IOERROR)) {
ASSERT(!logerror); ASSERT(!logerror);
/* /*
* Force the incore logs to disk before shutting the * Force the incore logs to disk before shutting the
* log down completely. * log down completely.
*/ */
xlog_state_sync_all(log, XFS_LOG_FORCE|XFS_LOG_SYNC, &dummy); _xfs_log_force(mp, XFS_LOG_SYNC, NULL);
spin_lock(&log->l_icloglock); spin_lock(&log->l_icloglock);
retval = xlog_state_ioerror(log); retval = xlog_state_ioerror(log);
spin_unlock(&log->l_icloglock); spin_unlock(&log->l_icloglock);

View file

@ -70,14 +70,8 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
* Flags to xfs_log_force() * Flags to xfs_log_force()
* *
* XFS_LOG_SYNC: Synchronous force in-core log to disk * XFS_LOG_SYNC: Synchronous force in-core log to disk
* XFS_LOG_FORCE: Start in-core log write now.
* XFS_LOG_URGE: Start write within some window of time.
*
* Note: Either XFS_LOG_FORCE or XFS_LOG_URGE must be set.
*/ */
#define XFS_LOG_SYNC 0x1 #define XFS_LOG_SYNC 0x1
#define XFS_LOG_FORCE 0x2
#define XFS_LOG_URGE 0x4
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
@ -110,10 +104,8 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
#define XLOG_REG_TYPE_TRANSHDR 19 #define XLOG_REG_TYPE_TRANSHDR 19
#define XLOG_REG_TYPE_MAX 19 #define XLOG_REG_TYPE_MAX 19
#define XLOG_VEC_SET_TYPE(vecp, t) ((vecp)->i_type = (t))
typedef struct xfs_log_iovec { typedef struct xfs_log_iovec {
xfs_caddr_t i_addr; /* beginning address of region */ xfs_caddr_t i_addr; /* beginning address of region */
int i_len; /* length in bytes of region */ int i_len; /* length in bytes of region */
uint i_type; /* type of region */ uint i_type; /* type of region */
} xfs_log_iovec_t; } xfs_log_iovec_t;
@ -140,12 +132,17 @@ xfs_lsn_t xfs_log_done(struct xfs_mount *mp,
void **iclog, void **iclog,
uint flags); uint flags);
int _xfs_log_force(struct xfs_mount *mp, int _xfs_log_force(struct xfs_mount *mp,
xfs_lsn_t lsn,
uint flags, uint flags,
int *log_forced); int *log_forced);
void xfs_log_force(struct xfs_mount *mp, void xfs_log_force(struct xfs_mount *mp,
xfs_lsn_t lsn,
uint flags); uint flags);
int _xfs_log_force_lsn(struct xfs_mount *mp,
xfs_lsn_t lsn,
uint flags,
int *log_forced);
void xfs_log_force_lsn(struct xfs_mount *mp,
xfs_lsn_t lsn,
uint flags);
int xfs_log_mount(struct xfs_mount *mp, int xfs_log_mount(struct xfs_mount *mp,
struct xfs_buftarg *log_target, struct xfs_buftarg *log_target,
xfs_daddr_t start_block, xfs_daddr_t start_block,

View file

@ -443,14 +443,9 @@ typedef struct log {
/* common routines */ /* common routines */
extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp); extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
extern int xlog_find_tail(xlog_t *log,
xfs_daddr_t *head_blk,
xfs_daddr_t *tail_blk);
extern int xlog_recover(xlog_t *log); extern int xlog_recover(xlog_t *log);
extern int xlog_recover_finish(xlog_t *log); extern int xlog_recover_finish(xlog_t *log);
extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int); extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
extern struct xfs_buf *xlog_get_bp(xlog_t *, int);
extern void xlog_put_bp(struct xfs_buf *);
extern kmem_zone_t *xfs_log_ticket_zone; extern kmem_zone_t *xfs_log_ticket_zone;

View file

@ -50,8 +50,6 @@
STATIC int xlog_find_zeroed(xlog_t *, xfs_daddr_t *); STATIC int xlog_find_zeroed(xlog_t *, xfs_daddr_t *);
STATIC int xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t); STATIC int xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t);
STATIC void xlog_recover_insert_item_backq(xlog_recover_item_t **q,
xlog_recover_item_t *item);
#if defined(DEBUG) #if defined(DEBUG)
STATIC void xlog_recover_check_summary(xlog_t *); STATIC void xlog_recover_check_summary(xlog_t *);
#else #else
@ -68,7 +66,7 @@ STATIC void xlog_recover_check_summary(xlog_t *);
((bbs + (log)->l_sectbb_mask + 1) & ~(log)->l_sectbb_mask) : (bbs) ) ((bbs + (log)->l_sectbb_mask + 1) & ~(log)->l_sectbb_mask) : (bbs) )
#define XLOG_SECTOR_ROUNDDOWN_BLKNO(log, bno) ((bno) & ~(log)->l_sectbb_mask) #define XLOG_SECTOR_ROUNDDOWN_BLKNO(log, bno) ((bno) & ~(log)->l_sectbb_mask)
xfs_buf_t * STATIC xfs_buf_t *
xlog_get_bp( xlog_get_bp(
xlog_t *log, xlog_t *log,
int nbblks) int nbblks)
@ -88,7 +86,7 @@ xlog_get_bp(
return xfs_buf_get_noaddr(BBTOB(nbblks), log->l_mp->m_logdev_targp); return xfs_buf_get_noaddr(BBTOB(nbblks), log->l_mp->m_logdev_targp);
} }
void STATIC void
xlog_put_bp( xlog_put_bp(
xfs_buf_t *bp) xfs_buf_t *bp)
{ {
@ -805,7 +803,7 @@ xlog_find_head(
* We could speed up search by using current head_blk buffer, but it is not * We could speed up search by using current head_blk buffer, but it is not
* available. * available.
*/ */
int STATIC int
xlog_find_tail( xlog_find_tail(
xlog_t *log, xlog_t *log,
xfs_daddr_t *head_blk, xfs_daddr_t *head_blk,
@ -1367,36 +1365,45 @@ xlog_clear_stale_blocks(
STATIC xlog_recover_t * STATIC xlog_recover_t *
xlog_recover_find_tid( xlog_recover_find_tid(
xlog_recover_t *q, struct hlist_head *head,
xlog_tid_t tid) xlog_tid_t tid)
{ {
xlog_recover_t *p = q; xlog_recover_t *trans;
struct hlist_node *n;
while (p != NULL) { hlist_for_each_entry(trans, n, head, r_list) {
if (p->r_log_tid == tid) if (trans->r_log_tid == tid)
break; return trans;
p = p->r_next;
} }
return p; return NULL;
} }
STATIC void STATIC void
xlog_recover_put_hashq( xlog_recover_new_tid(
xlog_recover_t **q, struct hlist_head *head,
xlog_recover_t *trans) xlog_tid_t tid,
xfs_lsn_t lsn)
{ {
trans->r_next = *q; xlog_recover_t *trans;
*q = trans;
trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP);
trans->r_log_tid = tid;
trans->r_lsn = lsn;
INIT_LIST_HEAD(&trans->r_itemq);
INIT_HLIST_NODE(&trans->r_list);
hlist_add_head(&trans->r_list, head);
} }
STATIC void STATIC void
xlog_recover_add_item( xlog_recover_add_item(
xlog_recover_item_t **itemq) struct list_head *head)
{ {
xlog_recover_item_t *item; xlog_recover_item_t *item;
item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP); item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP);
xlog_recover_insert_item_backq(itemq, item); INIT_LIST_HEAD(&item->ri_list);
list_add_tail(&item->ri_list, head);
} }
STATIC int STATIC int
@ -1409,8 +1416,7 @@ xlog_recover_add_to_cont_trans(
xfs_caddr_t ptr, old_ptr; xfs_caddr_t ptr, old_ptr;
int old_len; int old_len;
item = trans->r_itemq; if (list_empty(&trans->r_itemq)) {
if (item == NULL) {
/* finish copying rest of trans header */ /* finish copying rest of trans header */
xlog_recover_add_item(&trans->r_itemq); xlog_recover_add_item(&trans->r_itemq);
ptr = (xfs_caddr_t) &trans->r_theader + ptr = (xfs_caddr_t) &trans->r_theader +
@ -1418,7 +1424,8 @@ xlog_recover_add_to_cont_trans(
memcpy(ptr, dp, len); /* d, s, l */ memcpy(ptr, dp, len); /* d, s, l */
return 0; return 0;
} }
item = item->ri_prev; /* take the tail entry */
item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list);
old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; old_ptr = item->ri_buf[item->ri_cnt-1].i_addr;
old_len = item->ri_buf[item->ri_cnt-1].i_len; old_len = item->ri_buf[item->ri_cnt-1].i_len;
@ -1455,8 +1462,7 @@ xlog_recover_add_to_trans(
if (!len) if (!len)
return 0; return 0;
item = trans->r_itemq; if (list_empty(&trans->r_itemq)) {
if (item == NULL) {
/* we need to catch log corruptions here */ /* we need to catch log corruptions here */
if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) { if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) {
xlog_warn("XFS: xlog_recover_add_to_trans: " xlog_warn("XFS: xlog_recover_add_to_trans: "
@ -1474,12 +1480,15 @@ xlog_recover_add_to_trans(
memcpy(ptr, dp, len); memcpy(ptr, dp, len);
in_f = (xfs_inode_log_format_t *)ptr; in_f = (xfs_inode_log_format_t *)ptr;
if (item->ri_prev->ri_total != 0 && /* take the tail entry */
item->ri_prev->ri_total == item->ri_prev->ri_cnt) { item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list);
if (item->ri_total != 0 &&
item->ri_total == item->ri_cnt) {
/* tail item is in use, get a new one */
xlog_recover_add_item(&trans->r_itemq); xlog_recover_add_item(&trans->r_itemq);
item = list_entry(trans->r_itemq.prev,
xlog_recover_item_t, ri_list);
} }
item = trans->r_itemq;
item = item->ri_prev;
if (item->ri_total == 0) { /* first region to be added */ if (item->ri_total == 0) { /* first region to be added */
if (in_f->ilf_size == 0 || if (in_f->ilf_size == 0 ||
@ -1504,96 +1513,29 @@ xlog_recover_add_to_trans(
return 0; return 0;
} }
STATIC void /*
xlog_recover_new_tid( * Sort the log items in the transaction. Cancelled buffers need
xlog_recover_t **q, * to be put first so they are processed before any items that might
xlog_tid_t tid, * modify the buffers. If they are cancelled, then the modifications
xfs_lsn_t lsn) * don't need to be replayed.
{ */
xlog_recover_t *trans;
trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP);
trans->r_log_tid = tid;
trans->r_lsn = lsn;
xlog_recover_put_hashq(q, trans);
}
STATIC int
xlog_recover_unlink_tid(
xlog_recover_t **q,
xlog_recover_t *trans)
{
xlog_recover_t *tp;
int found = 0;
ASSERT(trans != NULL);
if (trans == *q) {
*q = (*q)->r_next;
} else {
tp = *q;
while (tp) {
if (tp->r_next == trans) {
found = 1;
break;
}
tp = tp->r_next;
}
if (!found) {
xlog_warn(
"XFS: xlog_recover_unlink_tid: trans not found");
ASSERT(0);
return XFS_ERROR(EIO);
}
tp->r_next = tp->r_next->r_next;
}
return 0;
}
STATIC void
xlog_recover_insert_item_backq(
xlog_recover_item_t **q,
xlog_recover_item_t *item)
{
if (*q == NULL) {
item->ri_prev = item->ri_next = item;
*q = item;
} else {
item->ri_next = *q;
item->ri_prev = (*q)->ri_prev;
(*q)->ri_prev = item;
item->ri_prev->ri_next = item;
}
}
STATIC void
xlog_recover_insert_item_frontq(
xlog_recover_item_t **q,
xlog_recover_item_t *item)
{
xlog_recover_insert_item_backq(q, item);
*q = item;
}
STATIC int STATIC int
xlog_recover_reorder_trans( xlog_recover_reorder_trans(
xlog_recover_t *trans) xlog_recover_t *trans)
{ {
xlog_recover_item_t *first_item, *itemq, *itemq_next; xlog_recover_item_t *item, *n;
xfs_buf_log_format_t *buf_f; LIST_HEAD(sort_list);
ushort flags = 0;
first_item = itemq = trans->r_itemq; list_splice_init(&trans->r_itemq, &sort_list);
trans->r_itemq = NULL; list_for_each_entry_safe(item, n, &sort_list, ri_list) {
do { xfs_buf_log_format_t *buf_f;
itemq_next = itemq->ri_next;
buf_f = (xfs_buf_log_format_t *)itemq->ri_buf[0].i_addr;
switch (ITEM_TYPE(itemq)) { buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr;
switch (ITEM_TYPE(item)) {
case XFS_LI_BUF: case XFS_LI_BUF:
flags = buf_f->blf_flags; if (!(buf_f->blf_flags & XFS_BLI_CANCEL)) {
if (!(flags & XFS_BLI_CANCEL)) { list_move(&item->ri_list, &trans->r_itemq);
xlog_recover_insert_item_frontq(&trans->r_itemq,
itemq);
break; break;
} }
case XFS_LI_INODE: case XFS_LI_INODE:
@ -1601,7 +1543,7 @@ xlog_recover_reorder_trans(
case XFS_LI_QUOTAOFF: case XFS_LI_QUOTAOFF:
case XFS_LI_EFD: case XFS_LI_EFD:
case XFS_LI_EFI: case XFS_LI_EFI:
xlog_recover_insert_item_backq(&trans->r_itemq, itemq); list_move_tail(&item->ri_list, &trans->r_itemq);
break; break;
default: default:
xlog_warn( xlog_warn(
@ -1609,8 +1551,8 @@ xlog_recover_reorder_trans(
ASSERT(0); ASSERT(0);
return XFS_ERROR(EIO); return XFS_ERROR(EIO);
} }
itemq = itemq_next; }
} while (first_item != itemq); ASSERT(list_empty(&sort_list));
return 0; return 0;
} }
@ -2242,9 +2184,9 @@ xlog_recover_do_buffer_trans(
} }
mp = log->l_mp; mp = log->l_mp;
buf_flags = XFS_BUF_LOCK; buf_flags = XBF_LOCK;
if (!(flags & XFS_BLI_INODE_BUF)) if (!(flags & XFS_BLI_INODE_BUF))
buf_flags |= XFS_BUF_MAPPED; buf_flags |= XBF_MAPPED;
bp = xfs_buf_read(mp->m_ddev_targp, blkno, len, buf_flags); bp = xfs_buf_read(mp->m_ddev_targp, blkno, len, buf_flags);
if (XFS_BUF_ISERROR(bp)) { if (XFS_BUF_ISERROR(bp)) {
@ -2346,7 +2288,7 @@ xlog_recover_do_inode_trans(
} }
bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len,
XFS_BUF_LOCK); XBF_LOCK);
if (XFS_BUF_ISERROR(bp)) { if (XFS_BUF_ISERROR(bp)) {
xfs_ioerror_alert("xlog_recover_do..(read#2)", mp, xfs_ioerror_alert("xlog_recover_do..(read#2)", mp,
bp, in_f->ilf_blkno); bp, in_f->ilf_blkno);
@ -2814,14 +2756,13 @@ xlog_recover_do_trans(
int pass) int pass)
{ {
int error = 0; int error = 0;
xlog_recover_item_t *item, *first_item; xlog_recover_item_t *item;
error = xlog_recover_reorder_trans(trans); error = xlog_recover_reorder_trans(trans);
if (error) if (error)
return error; return error;
first_item = item = trans->r_itemq; list_for_each_entry(item, &trans->r_itemq, ri_list) {
do {
switch (ITEM_TYPE(item)) { switch (ITEM_TYPE(item)) {
case XFS_LI_BUF: case XFS_LI_BUF:
error = xlog_recover_do_buffer_trans(log, item, pass); error = xlog_recover_do_buffer_trans(log, item, pass);
@ -2854,8 +2795,7 @@ xlog_recover_do_trans(
if (error) if (error)
return error; return error;
item = item->ri_next; }
} while (first_item != item);
return 0; return 0;
} }
@ -2869,21 +2809,18 @@ STATIC void
xlog_recover_free_trans( xlog_recover_free_trans(
xlog_recover_t *trans) xlog_recover_t *trans)
{ {
xlog_recover_item_t *first_item, *item, *free_item; xlog_recover_item_t *item, *n;
int i; int i;
item = first_item = trans->r_itemq; list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) {
do { /* Free the regions in the item. */
free_item = item; list_del(&item->ri_list);
item = item->ri_next; for (i = 0; i < item->ri_cnt; i++)
/* Free the regions in the item. */ kmem_free(item->ri_buf[i].i_addr);
for (i = 0; i < free_item->ri_cnt; i++) {
kmem_free(free_item->ri_buf[i].i_addr);
}
/* Free the item itself */ /* Free the item itself */
kmem_free(free_item->ri_buf); kmem_free(item->ri_buf);
kmem_free(free_item); kmem_free(item);
} while (first_item != item); }
/* Free the transaction recover structure */ /* Free the transaction recover structure */
kmem_free(trans); kmem_free(trans);
} }
@ -2891,14 +2828,12 @@ xlog_recover_free_trans(
STATIC int STATIC int
xlog_recover_commit_trans( xlog_recover_commit_trans(
xlog_t *log, xlog_t *log,
xlog_recover_t **q,
xlog_recover_t *trans, xlog_recover_t *trans,
int pass) int pass)
{ {
int error; int error;
if ((error = xlog_recover_unlink_tid(q, trans))) hlist_del(&trans->r_list);
return error;
if ((error = xlog_recover_do_trans(log, trans, pass))) if ((error = xlog_recover_do_trans(log, trans, pass)))
return error; return error;
xlog_recover_free_trans(trans); /* no error */ xlog_recover_free_trans(trans); /* no error */
@ -2926,7 +2861,7 @@ xlog_recover_unmount_trans(
STATIC int STATIC int
xlog_recover_process_data( xlog_recover_process_data(
xlog_t *log, xlog_t *log,
xlog_recover_t *rhash[], struct hlist_head rhash[],
xlog_rec_header_t *rhead, xlog_rec_header_t *rhead,
xfs_caddr_t dp, xfs_caddr_t dp,
int pass) int pass)
@ -2960,7 +2895,7 @@ xlog_recover_process_data(
} }
tid = be32_to_cpu(ohead->oh_tid); tid = be32_to_cpu(ohead->oh_tid);
hash = XLOG_RHASH(tid); hash = XLOG_RHASH(tid);
trans = xlog_recover_find_tid(rhash[hash], tid); trans = xlog_recover_find_tid(&rhash[hash], tid);
if (trans == NULL) { /* not found; add new tid */ if (trans == NULL) { /* not found; add new tid */
if (ohead->oh_flags & XLOG_START_TRANS) if (ohead->oh_flags & XLOG_START_TRANS)
xlog_recover_new_tid(&rhash[hash], tid, xlog_recover_new_tid(&rhash[hash], tid,
@ -2978,7 +2913,7 @@ xlog_recover_process_data(
switch (flags) { switch (flags) {
case XLOG_COMMIT_TRANS: case XLOG_COMMIT_TRANS:
error = xlog_recover_commit_trans(log, error = xlog_recover_commit_trans(log,
&rhash[hash], trans, pass); trans, pass);
break; break;
case XLOG_UNMOUNT_TRANS: case XLOG_UNMOUNT_TRANS:
error = xlog_recover_unmount_trans(trans); error = xlog_recover_unmount_trans(trans);
@ -3211,7 +3146,7 @@ xlog_recover_process_one_iunlink(
/* /*
* Get the on disk inode to find the next inode in the bucket. * Get the on disk inode to find the next inode in the bucket.
*/ */
error = xfs_itobp(mp, NULL, ip, &dip, &ibp, XFS_BUF_LOCK); error = xfs_itobp(mp, NULL, ip, &dip, &ibp, XBF_LOCK);
if (error) if (error)
goto fail_iput; goto fail_iput;
@ -3517,7 +3452,7 @@ xlog_do_recovery_pass(
int error = 0, h_size; int error = 0, h_size;
int bblks, split_bblks; int bblks, split_bblks;
int hblks, split_hblks, wrapped_hblks; int hblks, split_hblks, wrapped_hblks;
xlog_recover_t *rhash[XLOG_RHASH_SIZE]; struct hlist_head rhash[XLOG_RHASH_SIZE];
ASSERT(head_blk != tail_blk); ASSERT(head_blk != tail_blk);
@ -3978,8 +3913,7 @@ xlog_recover_finish(
* case the unlink transactions would have problems * case the unlink transactions would have problems
* pushing the EFIs out of the way. * pushing the EFIs out of the way.
*/ */
xfs_log_force(log->l_mp, (xfs_lsn_t)0, xfs_log_force(log->l_mp, XFS_LOG_SYNC);
(XFS_LOG_FORCE | XFS_LOG_SYNC));
xlog_recover_process_iunlinks(log); xlog_recover_process_iunlinks(log);

View file

@ -35,22 +35,21 @@
* item headers are in ri_buf[0]. Additional buffers follow. * item headers are in ri_buf[0]. Additional buffers follow.
*/ */
typedef struct xlog_recover_item { typedef struct xlog_recover_item {
struct xlog_recover_item *ri_next; struct list_head ri_list;
struct xlog_recover_item *ri_prev; int ri_type;
int ri_type; int ri_cnt; /* count of regions found */
int ri_cnt; /* count of regions found */ int ri_total; /* total regions */
int ri_total; /* total regions */ xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */
xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */
} xlog_recover_item_t; } xlog_recover_item_t;
struct xlog_tid; struct xlog_tid;
typedef struct xlog_recover { typedef struct xlog_recover {
struct xlog_recover *r_next; struct hlist_node r_list;
xlog_tid_t r_log_tid; /* log's transaction id */ xlog_tid_t r_log_tid; /* log's transaction id */
xfs_trans_header_t r_theader; /* trans header for partial */ xfs_trans_header_t r_theader; /* trans header for partial */
int r_state; /* not needed */ int r_state; /* not needed */
xfs_lsn_t r_lsn; /* xact lsn */ xfs_lsn_t r_lsn; /* xact lsn */
xlog_recover_item_t *r_itemq; /* q for items */ struct list_head r_itemq; /* q for items */
} xlog_recover_t; } xlog_recover_t;
#define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr) #define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr)

View file

@ -200,6 +200,38 @@ xfs_uuid_unmount(
} }
/*
* Reference counting access wrappers to the perag structures.
*/
struct xfs_perag *
xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno)
{
struct xfs_perag *pag;
int ref = 0;
spin_lock(&mp->m_perag_lock);
pag = radix_tree_lookup(&mp->m_perag_tree, agno);
if (pag) {
ASSERT(atomic_read(&pag->pag_ref) >= 0);
/* catch leaks in the positive direction during testing */
ASSERT(atomic_read(&pag->pag_ref) < 1000);
ref = atomic_inc_return(&pag->pag_ref);
}
spin_unlock(&mp->m_perag_lock);
trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
return pag;
}
void
xfs_perag_put(struct xfs_perag *pag)
{
int ref;
ASSERT(atomic_read(&pag->pag_ref) > 0);
ref = atomic_dec_return(&pag->pag_ref);
trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
}
/* /*
* Free up the resources associated with a mount structure. Assume that * Free up the resources associated with a mount structure. Assume that
* the structure was initially zeroed, so we can tell which fields got * the structure was initially zeroed, so we can tell which fields got
@ -209,13 +241,16 @@ STATIC void
xfs_free_perag( xfs_free_perag(
xfs_mount_t *mp) xfs_mount_t *mp)
{ {
if (mp->m_perag) { xfs_agnumber_t agno;
int agno; struct xfs_perag *pag;
for (agno = 0; agno < mp->m_maxagi; agno++) for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
if (mp->m_perag[agno].pagb_list) spin_lock(&mp->m_perag_lock);
kmem_free(mp->m_perag[agno].pagb_list); pag = radix_tree_delete(&mp->m_perag_tree, agno);
kmem_free(mp->m_perag); ASSERT(pag);
ASSERT(atomic_read(&pag->pag_ref) == 0);
spin_unlock(&mp->m_perag_lock);
kmem_free(pag);
} }
} }
@ -389,22 +424,57 @@ xfs_initialize_perag_icache(
} }
} }
xfs_agnumber_t int
xfs_initialize_perag( xfs_initialize_perag(
xfs_mount_t *mp, xfs_mount_t *mp,
xfs_agnumber_t agcount) xfs_agnumber_t agcount,
xfs_agnumber_t *maxagi)
{ {
xfs_agnumber_t index, max_metadata; xfs_agnumber_t index, max_metadata;
xfs_agnumber_t first_initialised = 0;
xfs_perag_t *pag; xfs_perag_t *pag;
xfs_agino_t agino; xfs_agino_t agino;
xfs_ino_t ino; xfs_ino_t ino;
xfs_sb_t *sbp = &mp->m_sb; xfs_sb_t *sbp = &mp->m_sb;
xfs_ino_t max_inum = XFS_MAXINUMBER_32; xfs_ino_t max_inum = XFS_MAXINUMBER_32;
int error = -ENOMEM;
/* Check to see if the filesystem can overflow 32 bit inodes */ /* Check to see if the filesystem can overflow 32 bit inodes */
agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);
/*
* Walk the current per-ag tree so we don't try to initialise AGs
* that already exist (growfs case). Allocate and insert all the
* AGs we don't find ready for initialisation.
*/
for (index = 0; index < agcount; index++) {
pag = xfs_perag_get(mp, index);
if (pag) {
xfs_perag_put(pag);
continue;
}
if (!first_initialised)
first_initialised = index;
pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
if (!pag)
goto out_unwind;
if (radix_tree_preload(GFP_NOFS))
goto out_unwind;
spin_lock(&mp->m_perag_lock);
if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
BUG();
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
error = -EEXIST;
goto out_unwind;
}
pag->pag_agno = index;
pag->pag_mount = mp;
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
}
/* Clear the mount flag if no inode can overflow 32 bits /* Clear the mount flag if no inode can overflow 32 bits
* on this filesystem, or if specifically requested.. * on this filesystem, or if specifically requested..
*/ */
@ -438,21 +508,33 @@ xfs_initialize_perag(
} }
/* This ag is preferred for inodes */ /* This ag is preferred for inodes */
pag = &mp->m_perag[index]; pag = xfs_perag_get(mp, index);
pag->pagi_inodeok = 1; pag->pagi_inodeok = 1;
if (index < max_metadata) if (index < max_metadata)
pag->pagf_metadata = 1; pag->pagf_metadata = 1;
xfs_initialize_perag_icache(pag); xfs_initialize_perag_icache(pag);
xfs_perag_put(pag);
} }
} else { } else {
/* Setup default behavior for smaller filesystems */ /* Setup default behavior for smaller filesystems */
for (index = 0; index < agcount; index++) { for (index = 0; index < agcount; index++) {
pag = &mp->m_perag[index]; pag = xfs_perag_get(mp, index);
pag->pagi_inodeok = 1; pag->pagi_inodeok = 1;
xfs_initialize_perag_icache(pag); xfs_initialize_perag_icache(pag);
xfs_perag_put(pag);
} }
} }
return index; if (maxagi)
*maxagi = index;
return 0;
out_unwind:
kmem_free(pag);
for (; index > first_initialised; index--) {
pag = radix_tree_delete(&mp->m_perag_tree, index);
kmem_free(pag);
}
return error;
} }
void void
@ -583,7 +665,7 @@ xfs_readsb(xfs_mount_t *mp, int flags)
* access to the superblock. * access to the superblock.
*/ */
sector_size = xfs_getsize_buftarg(mp->m_ddev_targp); sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
extra_flags = XFS_BUF_LOCK | XFS_BUF_MANAGE | XFS_BUF_MAPPED; extra_flags = XBF_LOCK | XBF_FS_MANAGED | XBF_MAPPED;
bp = xfs_buf_read(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size), bp = xfs_buf_read(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size),
extra_flags); extra_flags);
@ -731,12 +813,13 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
error = xfs_ialloc_pagi_init(mp, NULL, index); error = xfs_ialloc_pagi_init(mp, NULL, index);
if (error) if (error)
return error; return error;
pag = &mp->m_perag[index]; pag = xfs_perag_get(mp, index);
ifree += pag->pagi_freecount; ifree += pag->pagi_freecount;
ialloc += pag->pagi_count; ialloc += pag->pagi_count;
bfree += pag->pagf_freeblks; bfree += pag->pagf_freeblks;
bfreelst += pag->pagf_flcount; bfreelst += pag->pagf_flcount;
btree += pag->pagf_btreeblks; btree += pag->pagf_btreeblks;
xfs_perag_put(pag);
} }
/* /*
* Overwrite incore superblock counters with just-read data * Overwrite incore superblock counters with just-read data
@ -1008,6 +1091,22 @@ xfs_mount_reset_sbqflags(
return xfs_trans_commit(tp, 0); return xfs_trans_commit(tp, 0);
} }
__uint64_t
xfs_default_resblks(xfs_mount_t *mp)
{
__uint64_t resblks;
/*
* We default to 5% or 1024 fsbs of space reserved, whichever is smaller.
* This may drive us straight to ENOSPC on mount, but that implies
* we were already there on the last unmount. Warn if this occurs.
*/
resblks = mp->m_sb.sb_dblocks;
do_div(resblks, 20);
resblks = min_t(__uint64_t, resblks, 1024);
return resblks;
}
/* /*
* This function does the following on an initial mount of a file system: * This function does the following on an initial mount of a file system:
* - reads the superblock from disk and init the mount struct * - reads the superblock from disk and init the mount struct
@ -1152,13 +1251,13 @@ xfs_mountfs(
/* /*
* Allocate and initialize the per-ag data. * Allocate and initialize the per-ag data.
*/ */
init_rwsem(&mp->m_peraglock); spin_lock_init(&mp->m_perag_lock);
mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), INIT_RADIX_TREE(&mp->m_perag_tree, GFP_NOFS);
KM_MAYFAIL); error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
if (!mp->m_perag) if (error) {
cmn_err(CE_WARN, "XFS: Failed per-ag init: %d", error);
goto out_remove_uuid; goto out_remove_uuid;
}
mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount);
if (!sbp->sb_logblocks) { if (!sbp->sb_logblocks) {
cmn_err(CE_WARN, "XFS: no log defined"); cmn_err(CE_WARN, "XFS: no log defined");
@ -1318,18 +1417,14 @@ xfs_mountfs(
* when at ENOSPC. This is needed for operations like create with * when at ENOSPC. This is needed for operations like create with
* attr, unwritten extent conversion at ENOSPC, etc. Data allocations * attr, unwritten extent conversion at ENOSPC, etc. Data allocations
* are not allowed to use this reserved space. * are not allowed to use this reserved space.
*
* We default to 5% or 1024 fsbs of space reserved, whichever is smaller.
* This may drive us straight to ENOSPC on mount, but that implies
* we were already there on the last unmount. Warn if this occurs.
*/ */
resblks = mp->m_sb.sb_dblocks; if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
do_div(resblks, 20); resblks = xfs_default_resblks(mp);
resblks = min_t(__uint64_t, resblks, 1024); error = xfs_reserve_blocks(mp, &resblks, NULL);
error = xfs_reserve_blocks(mp, &resblks, NULL); if (error)
if (error) cmn_err(CE_WARN, "XFS: Unable to allocate reserve "
cmn_err(CE_WARN, "XFS: Unable to allocate reserve blocks. " "blocks. Continuing without a reserve pool.");
"Continuing without a reserve pool."); }
return 0; return 0;
@ -1372,8 +1467,19 @@ xfs_unmountfs(
* push out the iclog we will never get that unlocked. hence we * push out the iclog we will never get that unlocked. hence we
* need to force the log first. * need to force the log first.
*/ */
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); xfs_log_force(mp, XFS_LOG_SYNC);
xfs_reclaim_inodes(mp, XFS_IFLUSH_ASYNC);
/*
* 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.
*/
xfs_reclaim_inodes(mp, 0);
XFS_bflush(mp->m_ddev_targp);
xfs_reclaim_inodes(mp, SYNC_WAIT);
xfs_qm_unmount(mp); xfs_qm_unmount(mp);
@ -1382,7 +1488,7 @@ xfs_unmountfs(
* that nothing is pinned. This is important because bflush() * that nothing is pinned. This is important because bflush()
* will skip pinned buffers. * will skip pinned buffers.
*/ */
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); xfs_log_force(mp, XFS_LOG_SYNC);
xfs_binval(mp->m_ddev_targp); xfs_binval(mp->m_ddev_targp);
if (mp->m_rtdev_targp) { if (mp->m_rtdev_targp) {
@ -1548,15 +1654,14 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields); xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields);
/* find modified range */ /* find modified range */
f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);
ASSERT((1LL << f) & XFS_SB_MOD_BITS);
last = xfs_sb_info[f + 1].offset - 1;
f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
ASSERT((1LL << f) & XFS_SB_MOD_BITS); ASSERT((1LL << f) & XFS_SB_MOD_BITS);
first = xfs_sb_info[f].offset; first = xfs_sb_info[f].offset;
f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);
ASSERT((1LL << f) & XFS_SB_MOD_BITS);
last = xfs_sb_info[f + 1].offset - 1;
xfs_trans_log_buf(tp, bp, first, last); xfs_trans_log_buf(tp, bp, first, last);
} }
@ -1887,7 +1992,7 @@ xfs_getsb(
ASSERT(mp->m_sb_bp != NULL); ASSERT(mp->m_sb_bp != NULL);
bp = mp->m_sb_bp; bp = mp->m_sb_bp;
if (flags & XFS_BUF_TRYLOCK) { if (flags & XBF_TRYLOCK) {
if (!XFS_BUF_CPSEMA(bp)) { if (!XFS_BUF_CPSEMA(bp)) {
return NULL; return NULL;
} }

View file

@ -78,7 +78,8 @@ typedef int (*xfs_send_destroy_t)(struct xfs_inode *, dm_right_t);
typedef int (*xfs_send_namesp_t)(dm_eventtype_t, struct xfs_mount *, typedef int (*xfs_send_namesp_t)(dm_eventtype_t, struct xfs_mount *,
struct xfs_inode *, dm_right_t, struct xfs_inode *, dm_right_t,
struct xfs_inode *, dm_right_t, struct xfs_inode *, dm_right_t,
const char *, const char *, mode_t, int, int); const unsigned char *, const unsigned char *,
mode_t, int, int);
typedef int (*xfs_send_mount_t)(struct xfs_mount *, dm_right_t, typedef int (*xfs_send_mount_t)(struct xfs_mount *, dm_right_t,
char *, char *); char *, char *);
typedef void (*xfs_send_unmount_t)(struct xfs_mount *, struct xfs_inode *, typedef void (*xfs_send_unmount_t)(struct xfs_mount *, struct xfs_inode *,
@ -207,8 +208,8 @@ typedef struct xfs_mount {
uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */
uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */
uint m_in_maxlevels; /* max inobt btree levels. */ uint m_in_maxlevels; /* max inobt btree levels. */
struct xfs_perag *m_perag; /* per-ag accounting info */ struct radix_tree_root m_perag_tree; /* per-ag accounting info */
struct rw_semaphore m_peraglock; /* lock for m_perag (pointer) */ spinlock_t m_perag_lock; /* lock for m_perag_tree */
struct mutex m_growlock; /* growfs mutex */ struct mutex m_growlock; /* growfs mutex */
int m_fixedfsid[2]; /* unchanged for life of FS */ int m_fixedfsid[2]; /* unchanged for life of FS */
uint m_dmevmask; /* DMI events for this FS */ uint m_dmevmask; /* DMI events for this FS */
@ -224,6 +225,7 @@ typedef struct xfs_mount {
__uint64_t m_maxioffset; /* maximum inode offset */ __uint64_t m_maxioffset; /* maximum inode offset */
__uint64_t m_resblks; /* total reserved blocks */ __uint64_t m_resblks; /* total reserved blocks */
__uint64_t m_resblks_avail;/* available reserved blocks */ __uint64_t m_resblks_avail;/* available reserved blocks */
__uint64_t m_resblks_save; /* reserved blks @ remount,ro */
int m_dalign; /* stripe unit */ int m_dalign; /* stripe unit */
int m_swidth; /* stripe width */ int m_swidth; /* stripe width */
int m_sinoalign; /* stripe unit inode alignment */ int m_sinoalign; /* stripe unit inode alignment */
@ -384,19 +386,10 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
} }
/* /*
* perag get/put wrappers for eventual ref counting * perag get/put wrappers for ref counting
*/ */
static inline xfs_perag_t * struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
xfs_get_perag(struct xfs_mount *mp, xfs_ino_t ino) void xfs_perag_put(struct xfs_perag *pag);
{
return &mp->m_perag[XFS_INO_TO_AGNO(mp, ino)];
}
static inline void
xfs_put_perag(struct xfs_mount *mp, xfs_perag_t *pag)
{
/* nothing to see here, move along */
}
/* /*
* Per-cpu superblock locking functions * Per-cpu superblock locking functions
@ -428,6 +421,7 @@ typedef struct xfs_mod_sb {
} xfs_mod_sb_t; } xfs_mod_sb_t;
extern int xfs_log_sbcount(xfs_mount_t *, uint); extern int xfs_log_sbcount(xfs_mount_t *, uint);
extern __uint64_t xfs_default_resblks(xfs_mount_t *mp);
extern int xfs_mountfs(xfs_mount_t *mp); extern int xfs_mountfs(xfs_mount_t *mp);
extern void xfs_unmountfs(xfs_mount_t *); extern void xfs_unmountfs(xfs_mount_t *);
@ -450,7 +444,8 @@ extern struct xfs_dmops xfs_dmcore_xfs;
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
extern void xfs_mod_sb(struct xfs_trans *, __int64_t); extern void xfs_mod_sb(struct xfs_trans *, __int64_t);
extern xfs_agnumber_t xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t); extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t,
xfs_agnumber_t *);
extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *); extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t); extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);

View file

@ -398,7 +398,7 @@ exit:
* guaranteed that all the free functions for all the elements have finished * guaranteed that all the free functions for all the elements have finished
* executing and the reaper is not running. * executing and the reaper is not running.
*/ */
void static void
xfs_mru_cache_flush( xfs_mru_cache_flush(
xfs_mru_cache_t *mru) xfs_mru_cache_t *mru)
{ {

View file

@ -42,7 +42,6 @@ void xfs_mru_cache_uninit(void);
int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms, int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms,
unsigned int grp_count, unsigned int grp_count,
xfs_mru_cache_free_func_t free_func); xfs_mru_cache_free_func_t free_func);
void xfs_mru_cache_flush(xfs_mru_cache_t *mru);
void xfs_mru_cache_destroy(struct xfs_mru_cache *mru); void xfs_mru_cache_destroy(struct xfs_mru_cache *mru);
int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key, int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key,
void *value); void *value);

View file

@ -222,17 +222,10 @@ typedef struct xfs_qoff_logformat {
#define XFS_QMOPT_DELRTBCOUNT 0x0400000 #define XFS_QMOPT_DELRTBCOUNT 0x0400000
#define XFS_QMOPT_RES_INOS 0x0800000 #define XFS_QMOPT_RES_INOS 0x0800000
/*
* flags for dqflush and dqflush_all.
*/
#define XFS_QMOPT_SYNC 0x1000000
#define XFS_QMOPT_ASYNC 0x2000000
#define XFS_QMOPT_DELWRI 0x4000000
/* /*
* flags for dqalloc. * flags for dqalloc.
*/ */
#define XFS_QMOPT_INHERIT 0x8000000 #define XFS_QMOPT_INHERIT 0x1000000
/* /*
* flags to xfs_trans_mod_dquot. * flags to xfs_trans_mod_dquot.

View file

@ -46,48 +46,6 @@
#include "xfs_rw.h" #include "xfs_rw.h"
#include "xfs_trace.h" #include "xfs_trace.h"
/*
* This is a subroutine for xfs_write() and other writers (xfs_ioctl)
* which clears the setuid and setgid bits when a file is written.
*/
int
xfs_write_clear_setuid(
xfs_inode_t *ip)
{
xfs_mount_t *mp;
xfs_trans_t *tp;
int error;
mp = ip->i_mount;
tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID);
if ((error = xfs_trans_reserve(tp, 0,
XFS_WRITEID_LOG_RES(mp),
0, 0, 0))) {
xfs_trans_cancel(tp, 0);
return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_ihold(tp, ip);
ip->i_d.di_mode &= ~S_ISUID;
/*
* Note that we don't have to worry about mandatory
* file locking being disabled here because we only
* clear the S_ISGID bit if the Group execute bit is
* on, but if it was on then mandatory locking wouldn't
* have been enabled.
*/
if (ip->i_d.di_mode & S_IXGRP) {
ip->i_d.di_mode &= ~S_ISGID;
}
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_set_sync(tp);
error = xfs_trans_commit(tp, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return 0;
}
/* /*
* Force a shutdown of the filesystem instantly while keeping * Force a shutdown of the filesystem instantly while keeping
* the filesystem consistent. We don't do an unmount here; just shutdown * the filesystem consistent. We don't do an unmount here; just shutdown
@ -153,88 +111,6 @@ xfs_do_force_shutdown(
} }
} }
/*
* Called when we want to stop a buffer from getting written or read.
* We attach the EIO error, muck with its flags, and call biodone
* so that the proper iodone callbacks get called.
*/
int
xfs_bioerror(
xfs_buf_t *bp)
{
#ifdef XFSERRORDEBUG
ASSERT(XFS_BUF_ISREAD(bp) || bp->b_iodone);
#endif
/*
* No need to wait until the buffer is unpinned.
* We aren't flushing it.
*/
XFS_BUF_ERROR(bp, EIO);
/*
* We're calling biodone, so delete B_DONE flag. Either way
* we have to call the iodone callback, and calling biodone
* probably is the best way since it takes care of
* GRIO as well.
*/
XFS_BUF_UNREAD(bp);
XFS_BUF_UNDELAYWRITE(bp);
XFS_BUF_UNDONE(bp);
XFS_BUF_STALE(bp);
XFS_BUF_CLR_BDSTRAT_FUNC(bp);
xfs_biodone(bp);
return (EIO);
}
/*
* Same as xfs_bioerror, except that we are releasing the buffer
* here ourselves, and avoiding the biodone call.
* This is meant for userdata errors; metadata bufs come with
* iodone functions attached, so that we can track down errors.
*/
int
xfs_bioerror_relse(
xfs_buf_t *bp)
{
int64_t fl;
ASSERT(XFS_BUF_IODONE_FUNC(bp) != xfs_buf_iodone_callbacks);
ASSERT(XFS_BUF_IODONE_FUNC(bp) != xlog_iodone);
fl = XFS_BUF_BFLAGS(bp);
/*
* No need to wait until the buffer is unpinned.
* We aren't flushing it.
*
* chunkhold expects B_DONE to be set, whether
* we actually finish the I/O or not. We don't want to
* change that interface.
*/
XFS_BUF_UNREAD(bp);
XFS_BUF_UNDELAYWRITE(bp);
XFS_BUF_DONE(bp);
XFS_BUF_STALE(bp);
XFS_BUF_CLR_IODONE_FUNC(bp);
XFS_BUF_CLR_BDSTRAT_FUNC(bp);
if (!(fl & XFS_B_ASYNC)) {
/*
* Mark b_error and B_ERROR _both_.
* Lot's of chunkcache code assumes that.
* There's no reason to mark error for
* ASYNC buffers.
*/
XFS_BUF_ERROR(bp, EIO);
XFS_BUF_FINISH_IOWAIT(bp);
} else {
xfs_buf_relse(bp);
}
return (EIO);
}
/* /*
* Prints out an ALERT message about I/O error. * Prints out an ALERT message about I/O error.
*/ */
@ -305,37 +181,6 @@ xfs_read_buf(
return (error); return (error);
} }
/*
* Wrapper around bwrite() so that we can trap
* write errors, and act accordingly.
*/
int
xfs_bwrite(
struct xfs_mount *mp,
struct xfs_buf *bp)
{
int error;
/*
* XXXsup how does this work for quotas.
*/
XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb);
bp->b_mount = mp;
XFS_BUF_WRITE(bp);
if ((error = XFS_bwrite(bp))) {
ASSERT(mp);
/*
* Cannot put a buftrace here since if the buffer is not
* B_HOLD then we will brelse() the buffer before returning
* from bwrite and we could be tracing a buffer that has
* been reused.
*/
xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
}
return (error);
}
/* /*
* helper function to extract extent size hint from inode * helper function to extract extent size hint from inode
*/ */

View file

@ -39,10 +39,6 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
/* /*
* Prototypes for functions in xfs_rw.c. * Prototypes for functions in xfs_rw.c.
*/ */
extern int xfs_write_clear_setuid(struct xfs_inode *ip);
extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp);
extern int xfs_bioerror(struct xfs_buf *bp);
extern int xfs_bioerror_relse(struct xfs_buf *bp);
extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp, extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp,
xfs_daddr_t blkno, int len, uint flags, xfs_daddr_t blkno, int len, uint flags,
struct xfs_buf **bpp); struct xfs_buf **bpp);

View file

@ -981,9 +981,8 @@ shut_us_down:
*/ */
if (sync) { if (sync) {
if (!error) { if (!error) {
error = _xfs_log_force(mp, commit_lsn, error = _xfs_log_force_lsn(mp, commit_lsn,
XFS_LOG_FORCE | XFS_LOG_SYNC, XFS_LOG_SYNC, log_flushed);
log_flushed);
} }
XFS_STATS_INC(xs_trans_sync); XFS_STATS_INC(xs_trans_sync);
} else { } else {
@ -1121,7 +1120,7 @@ xfs_trans_fill_vecs(
tp->t_header.th_num_items = nitems; tp->t_header.th_num_items = nitems;
log_vector->i_addr = (xfs_caddr_t)&tp->t_header; log_vector->i_addr = (xfs_caddr_t)&tp->t_header;
log_vector->i_len = sizeof(xfs_trans_header_t); log_vector->i_len = sizeof(xfs_trans_header_t);
XLOG_VEC_SET_TYPE(log_vector, XLOG_REG_TYPE_TRANSHDR); log_vector->i_type = XLOG_REG_TYPE_TRANSHDR;
} }

View file

@ -861,8 +861,7 @@ typedef struct xfs_item_ops {
#define XFS_ITEM_SUCCESS 0 #define XFS_ITEM_SUCCESS 0
#define XFS_ITEM_PINNED 1 #define XFS_ITEM_PINNED 1
#define XFS_ITEM_LOCKED 2 #define XFS_ITEM_LOCKED 2
#define XFS_ITEM_FLUSHING 3 #define XFS_ITEM_PUSHBUF 3
#define XFS_ITEM_PUSHBUF 4
/* /*
* This structure is used to maintain a list of block ranges that have been * This structure is used to maintain a list of block ranges that have been

View file

@ -237,14 +237,15 @@ out:
} }
/* /*
* Function that does the work of pushing on the AIL * xfsaild_push does the work of pushing on the AIL. Returning a timeout of
* zero indicates that the caller should sleep until woken.
*/ */
long long
xfsaild_push( xfsaild_push(
struct xfs_ail *ailp, struct xfs_ail *ailp,
xfs_lsn_t *last_lsn) xfs_lsn_t *last_lsn)
{ {
long tout = 1000; /* milliseconds */ long tout = 0;
xfs_lsn_t last_pushed_lsn = *last_lsn; xfs_lsn_t last_pushed_lsn = *last_lsn;
xfs_lsn_t target = ailp->xa_target; xfs_lsn_t target = ailp->xa_target;
xfs_lsn_t lsn; xfs_lsn_t lsn;
@ -252,6 +253,7 @@ xfsaild_push(
int flush_log, count, stuck; int flush_log, count, stuck;
xfs_mount_t *mp = ailp->xa_mount; xfs_mount_t *mp = ailp->xa_mount;
struct xfs_ail_cursor *cur = &ailp->xa_cursors; struct xfs_ail_cursor *cur = &ailp->xa_cursors;
int push_xfsbufd = 0;
spin_lock(&ailp->xa_lock); spin_lock(&ailp->xa_lock);
xfs_trans_ail_cursor_init(ailp, cur); xfs_trans_ail_cursor_init(ailp, cur);
@ -262,7 +264,7 @@ xfsaild_push(
*/ */
xfs_trans_ail_cursor_done(ailp, cur); xfs_trans_ail_cursor_done(ailp, cur);
spin_unlock(&ailp->xa_lock); spin_unlock(&ailp->xa_lock);
last_pushed_lsn = 0; *last_lsn = 0;
return tout; return tout;
} }
@ -279,7 +281,6 @@ xfsaild_push(
* prevents use from spinning when we can't do anything or there is * prevents use from spinning when we can't do anything or there is
* lots of contention on the AIL lists. * lots of contention on the AIL lists.
*/ */
tout = 10;
lsn = lip->li_lsn; lsn = lip->li_lsn;
flush_log = stuck = count = 0; flush_log = stuck = count = 0;
while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) { while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) {
@ -308,6 +309,7 @@ xfsaild_push(
XFS_STATS_INC(xs_push_ail_pushbuf); XFS_STATS_INC(xs_push_ail_pushbuf);
IOP_PUSHBUF(lip); IOP_PUSHBUF(lip);
last_pushed_lsn = lsn; last_pushed_lsn = lsn;
push_xfsbufd = 1;
break; break;
case XFS_ITEM_PINNED: case XFS_ITEM_PINNED:
@ -322,12 +324,6 @@ xfsaild_push(
stuck++; stuck++;
break; break;
case XFS_ITEM_FLUSHING:
XFS_STATS_INC(xs_push_ail_flushing);
last_pushed_lsn = lsn;
stuck++;
break;
default: default:
ASSERT(0); ASSERT(0);
break; break;
@ -371,19 +367,24 @@ xfsaild_push(
* move forward in the AIL. * move forward in the AIL.
*/ */
XFS_STATS_INC(xs_push_ail_flush); XFS_STATS_INC(xs_push_ail_flush);
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); xfs_log_force(mp, 0);
}
if (push_xfsbufd) {
/* we've got delayed write buffers to flush */
wake_up_process(mp->m_ddev_targp->bt_task);
} }
if (!count) { if (!count) {
/* We're past our target or empty, so idle */ /* We're past our target or empty, so idle */
tout = 1000; last_pushed_lsn = 0;
} else if (XFS_LSN_CMP(lsn, target) >= 0) { } else if (XFS_LSN_CMP(lsn, target) >= 0) {
/* /*
* We reached the target so wait a bit longer for I/O to * We reached the target so wait a bit longer for I/O to
* complete and remove pushed items from the AIL before we * complete and remove pushed items from the AIL before we
* start the next scan from the start of the AIL. * start the next scan from the start of the AIL.
*/ */
tout += 20; tout = 50;
last_pushed_lsn = 0; last_pushed_lsn = 0;
} else if ((stuck * 100) / count > 90) { } else if ((stuck * 100) / count > 90) {
/* /*
@ -395,11 +396,14 @@ xfsaild_push(
* Backoff a bit more to allow some I/O to complete before * Backoff a bit more to allow some I/O to complete before
* continuing from where we were. * continuing from where we were.
*/ */
tout += 10; tout = 20;
} else {
/* more to do, but wait a short while before continuing */
tout = 10;
} }
*last_lsn = last_pushed_lsn; *last_lsn = last_pushed_lsn;
return tout; return tout;
} /* xfsaild_push */ }
/* /*

View file

@ -75,13 +75,14 @@ xfs_trans_get_buf(xfs_trans_t *tp,
xfs_buf_log_item_t *bip; xfs_buf_log_item_t *bip;
if (flags == 0) if (flags == 0)
flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; flags = XBF_LOCK | XBF_MAPPED;
/* /*
* Default to a normal get_buf() call if the tp is NULL. * Default to a normal get_buf() call if the tp is NULL.
*/ */
if (tp == NULL) if (tp == NULL)
return xfs_buf_get(target_dev, blkno, len, flags | BUF_BUSY); return xfs_buf_get(target_dev, blkno, len,
flags | XBF_DONT_BLOCK);
/* /*
* If we find the buffer in the cache with this transaction * If we find the buffer in the cache with this transaction
@ -117,14 +118,14 @@ xfs_trans_get_buf(xfs_trans_t *tp,
} }
/* /*
* We always specify the BUF_BUSY flag within a transaction so * We always specify the XBF_DONT_BLOCK flag within a transaction
* that get_buf does not try to push out a delayed write buffer * so that get_buf does not try to push out a delayed write buffer
* which might cause another transaction to take place (if the * which might cause another transaction to take place (if the
* buffer was delayed alloc). Such recursive transactions can * buffer was delayed alloc). Such recursive transactions can
* easily deadlock with our current transaction as well as cause * easily deadlock with our current transaction as well as cause
* us to run out of stack space. * us to run out of stack space.
*/ */
bp = xfs_buf_get(target_dev, blkno, len, flags | BUF_BUSY); bp = xfs_buf_get(target_dev, blkno, len, flags | XBF_DONT_BLOCK);
if (bp == NULL) { if (bp == NULL) {
return NULL; return NULL;
} }
@ -290,15 +291,15 @@ xfs_trans_read_buf(
int error; int error;
if (flags == 0) if (flags == 0)
flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; flags = XBF_LOCK | XBF_MAPPED;
/* /*
* Default to a normal get_buf() call if the tp is NULL. * Default to a normal get_buf() call if the tp is NULL.
*/ */
if (tp == NULL) { if (tp == NULL) {
bp = xfs_buf_read(target, blkno, len, flags | BUF_BUSY); bp = xfs_buf_read(target, blkno, len, flags | XBF_DONT_BLOCK);
if (!bp) if (!bp)
return (flags & XFS_BUF_TRYLOCK) ? return (flags & XBF_TRYLOCK) ?
EAGAIN : XFS_ERROR(ENOMEM); EAGAIN : XFS_ERROR(ENOMEM);
if (XFS_BUF_GETERROR(bp) != 0) { if (XFS_BUF_GETERROR(bp) != 0) {
@ -385,14 +386,14 @@ xfs_trans_read_buf(
} }
/* /*
* We always specify the BUF_BUSY flag within a transaction so * We always specify the XBF_DONT_BLOCK flag within a transaction
* that get_buf does not try to push out a delayed write buffer * so that get_buf does not try to push out a delayed write buffer
* which might cause another transaction to take place (if the * which might cause another transaction to take place (if the
* buffer was delayed alloc). Such recursive transactions can * buffer was delayed alloc). Such recursive transactions can
* easily deadlock with our current transaction as well as cause * easily deadlock with our current transaction as well as cause
* us to run out of stack space. * us to run out of stack space.
*/ */
bp = xfs_buf_read(target, blkno, len, flags | BUF_BUSY); bp = xfs_buf_read(target, blkno, len, flags | XBF_DONT_BLOCK);
if (bp == NULL) { if (bp == NULL) {
*bpp = NULL; *bpp = NULL;
return 0; return 0;
@ -472,8 +473,8 @@ shutdown_abort:
if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp)) if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp))
cmn_err(CE_NOTE, "about to pop assert, bp == 0x%p", bp); cmn_err(CE_NOTE, "about to pop assert, bp == 0x%p", bp);
#endif #endif
ASSERT((XFS_BUF_BFLAGS(bp) & (XFS_B_STALE|XFS_B_DELWRI)) != ASSERT((XFS_BUF_BFLAGS(bp) & (XBF_STALE|XBF_DELWRI)) !=
(XFS_B_STALE|XFS_B_DELWRI)); (XBF_STALE|XBF_DELWRI));
trace_xfs_trans_read_buf_shut(bp, _RET_IP_); trace_xfs_trans_read_buf_shut(bp, _RET_IP_);
xfs_buf_relse(bp); xfs_buf_relse(bp);

View file

@ -151,8 +151,8 @@ typedef enum {
} xfs_btnum_t; } xfs_btnum_t;
struct xfs_name { struct xfs_name {
const char *name; const unsigned char *name;
int len; int len;
}; };
#endif /* __XFS_TYPES_H__ */ #endif /* __XFS_TYPES_H__ */

View file

@ -256,7 +256,7 @@ xfs_setattr(
iattr->ia_size > ip->i_d.di_size) { iattr->ia_size > ip->i_d.di_size) {
code = xfs_flush_pages(ip, code = xfs_flush_pages(ip,
ip->i_d.di_size, iattr->ia_size, ip->i_d.di_size, iattr->ia_size,
XFS_B_ASYNC, FI_NONE); XBF_ASYNC, FI_NONE);
} }
/* wait for all I/O to complete */ /* wait for all I/O to complete */
@ -597,7 +597,7 @@ xfs_fsync(
{ {
xfs_trans_t *tp; xfs_trans_t *tp;
int error = 0; int error = 0;
int log_flushed = 0, changed = 1; int log_flushed = 0;
xfs_itrace_entry(ip); xfs_itrace_entry(ip);
@ -627,19 +627,16 @@ xfs_fsync(
* disk yet, the inode will be still be pinned. If it is, * disk yet, the inode will be still be pinned. If it is,
* force the log. * force the log.
*/ */
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (xfs_ipincount(ip)) { if (xfs_ipincount(ip)) {
error = _xfs_log_force(ip->i_mount, (xfs_lsn_t)0, if (ip->i_itemp->ili_last_lsn) {
XFS_LOG_FORCE | XFS_LOG_SYNC, error = _xfs_log_force_lsn(ip->i_mount,
&log_flushed); ip->i_itemp->ili_last_lsn,
} else { XFS_LOG_SYNC, &log_flushed);
/* } else {
* If the inode is not pinned and nothing has changed error = _xfs_log_force(ip->i_mount,
* we don't need to flush the cache. XFS_LOG_SYNC, &log_flushed);
*/ }
changed = 0;
} }
} else { } else {
/* /*
@ -674,7 +671,7 @@ xfs_fsync(
xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(ip, XFS_ILOCK_EXCL);
} }
if ((ip->i_mount->m_flags & XFS_MOUNT_BARRIER) && changed) { if (ip->i_mount->m_flags & XFS_MOUNT_BARRIER) {
/* /*
* If the log write didn't issue an ordered tag we need * If the log write didn't issue an ordered tag we need
* to flush the disk cache for the data device now. * to flush the disk cache for the data device now.
@ -1096,7 +1093,7 @@ xfs_release(
*/ */
truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0)
xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE);
} }
if (ip->i_d.di_nlink != 0) { if (ip->i_d.di_nlink != 0) {
@ -2199,7 +2196,8 @@ xfs_symlink(
if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) { if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) {
error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp, error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp,
DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
link_name->name, target_path, 0, 0, 0); link_name->name,
(unsigned char *)target_path, 0, 0, 0);
if (error) if (error)
return error; return error;
} }
@ -2395,7 +2393,8 @@ std_return:
dp, DM_RIGHT_NULL, dp, DM_RIGHT_NULL,
error ? NULL : ip, error ? NULL : ip,
DM_RIGHT_NULL, link_name->name, DM_RIGHT_NULL, link_name->name,
target_path, 0, error, 0); (unsigned char *)target_path,
0, error, 0);
} }
if (!error) if (!error)

View file

@ -43,11 +43,11 @@ int xfs_change_file_space(struct xfs_inode *ip, int cmd,
int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
struct xfs_inode *src_ip, struct xfs_inode *target_dp, struct xfs_inode *src_ip, struct xfs_inode *target_dp,
struct xfs_name *target_name, struct xfs_inode *target_ip); struct xfs_name *target_name, struct xfs_inode *target_ip);
int xfs_attr_get(struct xfs_inode *ip, const char *name, char *value, int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
int *valuelenp, int flags); unsigned char *value, int *valuelenp, int flags);
int xfs_attr_set(struct xfs_inode *dp, const char *name, char *value, int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
int valuelen, int flags); unsigned char *value, int valuelen, int flags);
int xfs_attr_remove(struct xfs_inode *dp, const char *name, int flags); int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
int flags, struct attrlist_cursor_kern *cursor); int flags, struct attrlist_cursor_kern *cursor);
ssize_t xfs_read(struct xfs_inode *ip, struct kiocb *iocb, ssize_t xfs_read(struct xfs_inode *ip, struct kiocb *iocb,