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

* 'for-linus' of git://oss.sgi.com/xfs/xfs: (36 commits)
  xfs: semaphore cleanup
  xfs: Extend project quotas to support 32bit project ids
  xfs: remove xfs_buf wrappers
  xfs: remove xfs_cred.h
  xfs: remove xfs_globals.h
  xfs: remove xfs_version.h
  xfs: remove xfs_refcache.h
  xfs: fix the xfs_trans_committed
  xfs: remove unused t_callback field in struct xfs_trans
  xfs: fix bogus m_maxagi check in xfs_iget
  xfs: do not use xfs_mod_incore_sb_batch for per-cpu counters
  xfs: do not use xfs_mod_incore_sb for per-cpu counters
  xfs: remove XFS_MOUNT_NO_PERCPU_SB
  xfs: pack xfs_buf structure more tightly
  xfs: convert buffer cache hash to rbtree
  xfs: serialise inode reclaim within an AG
  xfs: batch inode reclaim lookup
  xfs: implement batched inode lookups for AG walking
  xfs: split out inode walk inode grabbing
  xfs: split inode AG walking into separate code for reclaim
  ...
This commit is contained in:
Linus Torvalds 2010-10-22 17:32:27 -07:00
commit 5fe3a5ae5c
60 changed files with 1189 additions and 1379 deletions

View file

@ -188,8 +188,8 @@ _xfs_buf_initialize(
atomic_set(&bp->b_hold, 1);
init_completion(&bp->b_iowait);
INIT_LIST_HEAD(&bp->b_list);
INIT_LIST_HEAD(&bp->b_hash_list);
init_MUTEX_LOCKED(&bp->b_sema); /* held, no waiters */
RB_CLEAR_NODE(&bp->b_rbnode);
sema_init(&bp->b_sema, 0); /* held, no waiters */
XB_SET_OWNER(bp);
bp->b_target = target;
bp->b_file_offset = range_base;
@ -262,8 +262,6 @@ xfs_buf_free(
{
trace_xfs_buf_free(bp, _RET_IP_);
ASSERT(list_empty(&bp->b_hash_list));
if (bp->b_flags & (_XBF_PAGE_CACHE|_XBF_PAGES)) {
uint i;
@ -422,8 +420,10 @@ _xfs_buf_find(
{
xfs_off_t range_base;
size_t range_length;
xfs_bufhash_t *hash;
xfs_buf_t *bp, *n;
struct xfs_perag *pag;
struct rb_node **rbp;
struct rb_node *parent;
xfs_buf_t *bp;
range_base = (ioff << BBSHIFT);
range_length = (isize << BBSHIFT);
@ -432,14 +432,37 @@ _xfs_buf_find(
ASSERT(!(range_length < (1 << btp->bt_sshift)));
ASSERT(!(range_base & (xfs_off_t)btp->bt_smask));
hash = &btp->bt_hash[hash_long((unsigned long)ioff, btp->bt_hashshift)];
/* get tree root */
pag = xfs_perag_get(btp->bt_mount,
xfs_daddr_to_agno(btp->bt_mount, ioff));
spin_lock(&hash->bh_lock);
/* walk tree */
spin_lock(&pag->pag_buf_lock);
rbp = &pag->pag_buf_tree.rb_node;
parent = NULL;
bp = NULL;
while (*rbp) {
parent = *rbp;
bp = rb_entry(parent, struct xfs_buf, b_rbnode);
list_for_each_entry_safe(bp, n, &hash->bh_list, b_hash_list) {
ASSERT(btp == bp->b_target);
if (bp->b_file_offset == range_base &&
bp->b_buffer_length == range_length) {
if (range_base < bp->b_file_offset)
rbp = &(*rbp)->rb_left;
else if (range_base > bp->b_file_offset)
rbp = &(*rbp)->rb_right;
else {
/*
* found a block offset match. If the range doesn't
* match, the only way this is allowed is if the buffer
* in the cache is stale and the transaction that made
* it stale has not yet committed. i.e. we are
* reallocating a busy extent. Skip this buffer and
* continue searching to the right for an exact match.
*/
if (bp->b_buffer_length != range_length) {
ASSERT(bp->b_flags & XBF_STALE);
rbp = &(*rbp)->rb_right;
continue;
}
atomic_inc(&bp->b_hold);
goto found;
}
@ -449,17 +472,21 @@ _xfs_buf_find(
if (new_bp) {
_xfs_buf_initialize(new_bp, btp, range_base,
range_length, flags);
new_bp->b_hash = hash;
list_add(&new_bp->b_hash_list, &hash->bh_list);
rb_link_node(&new_bp->b_rbnode, parent, rbp);
rb_insert_color(&new_bp->b_rbnode, &pag->pag_buf_tree);
/* the buffer keeps the perag reference until it is freed */
new_bp->b_pag = pag;
spin_unlock(&pag->pag_buf_lock);
} else {
XFS_STATS_INC(xb_miss_locked);
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
}
spin_unlock(&hash->bh_lock);
return new_bp;
found:
spin_unlock(&hash->bh_lock);
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
/* Attempt to get the semaphore without sleeping,
* if this does not work then we need to drop the
@ -625,8 +652,7 @@ void
xfs_buf_readahead(
xfs_buftarg_t *target,
xfs_off_t ioff,
size_t isize,
xfs_buf_flags_t flags)
size_t isize)
{
struct backing_dev_info *bdi;
@ -634,8 +660,42 @@ xfs_buf_readahead(
if (bdi_read_congested(bdi))
return;
flags |= (XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD);
xfs_buf_read(target, ioff, isize, flags);
xfs_buf_read(target, ioff, isize,
XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD|XBF_DONT_BLOCK);
}
/*
* Read an uncached buffer from disk. Allocates and returns a locked
* buffer containing the disk contents or nothing.
*/
struct xfs_buf *
xfs_buf_read_uncached(
struct xfs_mount *mp,
struct xfs_buftarg *target,
xfs_daddr_t daddr,
size_t length,
int flags)
{
xfs_buf_t *bp;
int error;
bp = xfs_buf_get_uncached(target, length, flags);
if (!bp)
return NULL;
/* set up the buffer for a read IO */
xfs_buf_lock(bp);
XFS_BUF_SET_ADDR(bp, daddr);
XFS_BUF_READ(bp);
XFS_BUF_BUSY(bp);
xfsbdstrat(mp, bp);
error = xfs_buf_iowait(bp);
if (error || bp->b_error) {
xfs_buf_relse(bp);
return NULL;
}
return bp;
}
xfs_buf_t *
@ -707,9 +767,10 @@ xfs_buf_associate_memory(
}
xfs_buf_t *
xfs_buf_get_noaddr(
xfs_buf_get_uncached(
struct xfs_buftarg *target,
size_t len,
xfs_buftarg_t *target)
int flags)
{
unsigned long page_count = PAGE_ALIGN(len) >> PAGE_SHIFT;
int error, i;
@ -725,7 +786,7 @@ xfs_buf_get_noaddr(
goto fail_free_buf;
for (i = 0; i < page_count; i++) {
bp->b_pages[i] = alloc_page(GFP_KERNEL);
bp->b_pages[i] = alloc_page(xb_to_gfp(flags));
if (!bp->b_pages[i])
goto fail_free_mem;
}
@ -740,7 +801,7 @@ xfs_buf_get_noaddr(
xfs_buf_unlock(bp);
trace_xfs_buf_get_noaddr(bp, _RET_IP_);
trace_xfs_buf_get_uncached(bp, _RET_IP_);
return bp;
fail_free_mem:
@ -774,29 +835,30 @@ void
xfs_buf_rele(
xfs_buf_t *bp)
{
xfs_bufhash_t *hash = bp->b_hash;
struct xfs_perag *pag = bp->b_pag;
trace_xfs_buf_rele(bp, _RET_IP_);
if (unlikely(!hash)) {
if (!pag) {
ASSERT(!bp->b_relse);
ASSERT(RB_EMPTY_NODE(&bp->b_rbnode));
if (atomic_dec_and_test(&bp->b_hold))
xfs_buf_free(bp);
return;
}
ASSERT(!RB_EMPTY_NODE(&bp->b_rbnode));
ASSERT(atomic_read(&bp->b_hold) > 0);
if (atomic_dec_and_lock(&bp->b_hold, &hash->bh_lock)) {
if (atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock)) {
if (bp->b_relse) {
atomic_inc(&bp->b_hold);
spin_unlock(&hash->bh_lock);
(*(bp->b_relse)) (bp);
} else if (bp->b_flags & XBF_FS_MANAGED) {
spin_unlock(&hash->bh_lock);
spin_unlock(&pag->pag_buf_lock);
bp->b_relse(bp);
} else {
ASSERT(!(bp->b_flags & (XBF_DELWRI|_XBF_DELWRI_Q)));
list_del_init(&bp->b_hash_list);
spin_unlock(&hash->bh_lock);
rb_erase(&bp->b_rbnode, &pag->pag_buf_tree);
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
xfs_buf_free(bp);
}
}
@ -859,7 +921,7 @@ xfs_buf_lock(
trace_xfs_buf_lock(bp, _RET_IP_);
if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE))
xfs_log_force(bp->b_mount, 0);
xfs_log_force(bp->b_target->bt_mount, 0);
if (atomic_read(&bp->b_io_remaining))
blk_run_address_space(bp->b_target->bt_mapping);
down(&bp->b_sema);
@ -970,7 +1032,6 @@ xfs_bwrite(
{
int error;
bp->b_mount = mp;
bp->b_flags |= XBF_WRITE;
bp->b_flags &= ~(XBF_ASYNC | XBF_READ);
@ -991,8 +1052,6 @@ xfs_bdwrite(
{
trace_xfs_buf_bdwrite(bp, _RET_IP_);
bp->b_mount = mp;
bp->b_flags &= ~XBF_READ;
bp->b_flags |= (XBF_DELWRI | XBF_ASYNC);
@ -1001,7 +1060,7 @@ xfs_bdwrite(
/*
* 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
* We attach the EIO error, muck with its flags, and call xfs_buf_ioend
* so that the proper iodone callbacks get called.
*/
STATIC int
@ -1018,21 +1077,21 @@ xfs_bioerror(
XFS_BUF_ERROR(bp, EIO);
/*
* We're calling biodone, so delete XBF_DONE flag.
* We're calling xfs_buf_ioend, so delete XBF_DONE flag.
*/
XFS_BUF_UNREAD(bp);
XFS_BUF_UNDELAYWRITE(bp);
XFS_BUF_UNDONE(bp);
XFS_BUF_STALE(bp);
xfs_biodone(bp);
xfs_buf_ioend(bp, 0);
return EIO;
}
/*
* Same as xfs_bioerror, except that we are releasing the buffer
* here ourselves, and avoiding the biodone call.
* here ourselves, and avoiding the xfs_buf_ioend call.
* This is meant for userdata errors; metadata bufs come with
* iodone functions attached, so that we can track down errors.
*/
@ -1081,7 +1140,7 @@ int
xfs_bdstrat_cb(
struct xfs_buf *bp)
{
if (XFS_FORCED_SHUTDOWN(bp->b_mount)) {
if (XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) {
trace_xfs_bdstrat_shut(bp, _RET_IP_);
/*
* Metadata write that didn't get logged but
@ -1387,62 +1446,24 @@ xfs_buf_iomove(
*/
void
xfs_wait_buftarg(
xfs_buftarg_t *btp)
struct xfs_buftarg *btp)
{
xfs_buf_t *bp, *n;
xfs_bufhash_t *hash;
uint i;
struct xfs_perag *pag;
uint i;
for (i = 0; i < (1 << btp->bt_hashshift); i++) {
hash = &btp->bt_hash[i];
again:
spin_lock(&hash->bh_lock);
list_for_each_entry_safe(bp, n, &hash->bh_list, b_hash_list) {
ASSERT(btp == bp->b_target);
if (!(bp->b_flags & XBF_FS_MANAGED)) {
spin_unlock(&hash->bh_lock);
/*
* Catch superblock reference count leaks
* immediately
*/
BUG_ON(bp->b_bn == 0);
delay(100);
goto again;
}
for (i = 0; i < btp->bt_mount->m_sb.sb_agcount; i++) {
pag = xfs_perag_get(btp->bt_mount, i);
spin_lock(&pag->pag_buf_lock);
while (rb_first(&pag->pag_buf_tree)) {
spin_unlock(&pag->pag_buf_lock);
delay(100);
spin_lock(&pag->pag_buf_lock);
}
spin_unlock(&hash->bh_lock);
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
}
}
/*
* Allocate buffer hash table for a given target.
* For devices containing metadata (i.e. not the log/realtime devices)
* we need to allocate a much larger hash table.
*/
STATIC void
xfs_alloc_bufhash(
xfs_buftarg_t *btp,
int external)
{
unsigned int i;
btp->bt_hashshift = external ? 3 : 12; /* 8 or 4096 buckets */
btp->bt_hash = kmem_zalloc_large((1 << btp->bt_hashshift) *
sizeof(xfs_bufhash_t));
for (i = 0; i < (1 << btp->bt_hashshift); i++) {
spin_lock_init(&btp->bt_hash[i].bh_lock);
INIT_LIST_HEAD(&btp->bt_hash[i].bh_list);
}
}
STATIC void
xfs_free_bufhash(
xfs_buftarg_t *btp)
{
kmem_free_large(btp->bt_hash);
btp->bt_hash = NULL;
}
/*
* buftarg list for delwrite queue processing
*/
@ -1475,7 +1496,6 @@ xfs_free_buftarg(
xfs_flush_buftarg(btp, 1);
if (mp->m_flags & XFS_MOUNT_BARRIER)
xfs_blkdev_issue_flush(btp);
xfs_free_bufhash(btp);
iput(btp->bt_mapping->host);
/* Unregister the buftarg first so that we don't get a
@ -1597,6 +1617,7 @@ xfs_alloc_delwrite_queue(
xfs_buftarg_t *
xfs_alloc_buftarg(
struct xfs_mount *mp,
struct block_device *bdev,
int external,
const char *fsname)
@ -1605,6 +1626,7 @@ xfs_alloc_buftarg(
btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
btp->bt_mount = mp;
btp->bt_dev = bdev->bd_dev;
btp->bt_bdev = bdev;
if (xfs_setsize_buftarg_early(btp, bdev))
@ -1613,7 +1635,6 @@ xfs_alloc_buftarg(
goto error;
if (xfs_alloc_delwrite_queue(btp, fsname))
goto error;
xfs_alloc_bufhash(btp, external);
return btp;
error:
@ -1904,7 +1925,7 @@ xfs_flush_buftarg(
bp = list_first_entry(&wait_list, struct xfs_buf, b_list);
list_del_init(&bp->b_list);
xfs_iowait(bp);
xfs_buf_iowait(bp);
xfs_buf_relse(bp);
}
}

View file

@ -51,7 +51,6 @@ typedef enum {
#define XBF_DONE (1 << 5) /* all pages in the buffer uptodate */
#define XBF_DELWRI (1 << 6) /* buffer has dirty pages */
#define XBF_STALE (1 << 7) /* buffer has been staled, do not find it */
#define XBF_FS_MANAGED (1 << 8) /* filesystem controls freeing memory */
#define XBF_ORDERED (1 << 11)/* use ordered writes */
#define XBF_READ_AHEAD (1 << 12)/* asynchronous read-ahead */
#define XBF_LOG_BUFFER (1 << 13)/* this is a buffer used for the log */
@ -96,7 +95,6 @@ typedef unsigned int xfs_buf_flags_t;
{ XBF_DONE, "DONE" }, \
{ XBF_DELWRI, "DELWRI" }, \
{ XBF_STALE, "STALE" }, \
{ XBF_FS_MANAGED, "FS_MANAGED" }, \
{ XBF_ORDERED, "ORDERED" }, \
{ XBF_READ_AHEAD, "READ_AHEAD" }, \
{ XBF_LOCK, "LOCK" }, /* should never be set */\
@ -123,14 +121,11 @@ typedef struct xfs_buftarg {
dev_t bt_dev;
struct block_device *bt_bdev;
struct address_space *bt_mapping;
struct xfs_mount *bt_mount;
unsigned int bt_bsize;
unsigned int bt_sshift;
size_t bt_smask;
/* per device buffer hash table */
uint bt_hashshift;
xfs_bufhash_t *bt_hash;
/* per device delwri queue */
struct task_struct *bt_task;
struct list_head bt_list;
@ -158,34 +153,41 @@ typedef int (*xfs_buf_bdstrat_t)(struct xfs_buf *);
#define XB_PAGES 2
typedef struct xfs_buf {
struct semaphore b_sema; /* semaphore for lockables */
unsigned long b_queuetime; /* time buffer was queued */
atomic_t b_pin_count; /* pin count */
wait_queue_head_t b_waiters; /* unpin waiters */
struct list_head b_list;
xfs_buf_flags_t b_flags; /* status flags */
struct list_head b_hash_list; /* hash table list */
xfs_bufhash_t *b_hash; /* hash table list start */
xfs_buftarg_t *b_target; /* buffer target (device) */
atomic_t b_hold; /* reference count */
xfs_daddr_t b_bn; /* block number for I/O */
/*
* first cacheline holds all the fields needed for an uncontended cache
* hit to be fully processed. The semaphore straddles the cacheline
* boundary, but the counter and lock sits on the first cacheline,
* which is the only bit that is touched if we hit the semaphore
* fast-path on locking.
*/
struct rb_node b_rbnode; /* rbtree node */
xfs_off_t b_file_offset; /* offset in file */
size_t b_buffer_length;/* size of buffer in bytes */
atomic_t b_hold; /* reference count */
xfs_buf_flags_t b_flags; /* status flags */
struct semaphore b_sema; /* semaphore for lockables */
wait_queue_head_t b_waiters; /* unpin waiters */
struct list_head b_list;
struct xfs_perag *b_pag; /* contains rbtree root */
xfs_buftarg_t *b_target; /* buffer target (device) */
xfs_daddr_t b_bn; /* block number for I/O */
size_t b_count_desired;/* desired transfer size */
void *b_addr; /* virtual address of buffer */
struct work_struct b_iodone_work;
atomic_t b_io_remaining; /* #outstanding I/O requests */
xfs_buf_iodone_t b_iodone; /* I/O completion function */
xfs_buf_relse_t b_relse; /* releasing function */
struct completion b_iowait; /* queue for I/O waiters */
void *b_fspriv;
void *b_fspriv2;
struct xfs_mount *b_mount;
unsigned short b_error; /* error code on I/O */
unsigned int b_page_count; /* size of page array */
unsigned int b_offset; /* page offset in first page */
struct page **b_pages; /* array of page pointers */
struct page *b_page_array[XB_PAGES]; /* inline pages */
unsigned long b_queuetime; /* time buffer was queued */
atomic_t b_pin_count; /* pin count */
atomic_t b_io_remaining; /* #outstanding I/O requests */
unsigned int b_page_count; /* size of page array */
unsigned int b_offset; /* page offset in first page */
unsigned short b_error; /* error code on I/O */
#ifdef XFS_BUF_LOCK_TRACKING
int b_last_holder;
#endif
@ -204,11 +206,13 @@ extern xfs_buf_t *xfs_buf_read(xfs_buftarg_t *, xfs_off_t, size_t,
xfs_buf_flags_t);
extern xfs_buf_t *xfs_buf_get_empty(size_t, xfs_buftarg_t *);
extern xfs_buf_t *xfs_buf_get_noaddr(size_t, xfs_buftarg_t *);
extern xfs_buf_t *xfs_buf_get_uncached(struct xfs_buftarg *, size_t, int);
extern int xfs_buf_associate_memory(xfs_buf_t *, void *, size_t);
extern void xfs_buf_hold(xfs_buf_t *);
extern void xfs_buf_readahead(xfs_buftarg_t *, xfs_off_t, size_t,
xfs_buf_flags_t);
extern void xfs_buf_readahead(xfs_buftarg_t *, xfs_off_t, size_t);
struct xfs_buf *xfs_buf_read_uncached(struct xfs_mount *mp,
struct xfs_buftarg *target,
xfs_daddr_t daddr, size_t length, int flags);
/* Releasing Buffers */
extern void xfs_buf_free(xfs_buf_t *);
@ -233,6 +237,8 @@ extern int xfs_buf_iorequest(xfs_buf_t *);
extern int xfs_buf_iowait(xfs_buf_t *);
extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
xfs_buf_rw_t);
#define xfs_buf_zero(bp, off, len) \
xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO)
static inline int xfs_buf_geterror(xfs_buf_t *bp)
{
@ -267,8 +273,6 @@ extern void xfs_buf_terminate(void);
XFS_BUF_DONE(bp); \
} while (0)
#define XFS_BUF_UNMANAGE(bp) ((bp)->b_flags &= ~XBF_FS_MANAGED)
#define XFS_BUF_DELAYWRITE(bp) ((bp)->b_flags |= XBF_DELWRI)
#define XFS_BUF_UNDELAYWRITE(bp) xfs_buf_delwri_dequeue(bp)
#define XFS_BUF_ISDELAYWRITE(bp) ((bp)->b_flags & XBF_DELWRI)
@ -347,25 +351,11 @@ static inline void xfs_buf_relse(xfs_buf_t *bp)
xfs_buf_rele(bp);
}
#define xfs_biodone(bp) xfs_buf_ioend(bp, 0)
#define xfs_biomove(bp, off, len, data, rw) \
xfs_buf_iomove((bp), (off), (len), (data), \
((rw) == XBF_WRITE) ? XBRW_WRITE : XBRW_READ)
#define xfs_biozero(bp, off, len) \
xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO)
#define xfs_iowait(bp) xfs_buf_iowait(bp)
#define xfs_baread(target, rablkno, ralen) \
xfs_buf_readahead((target), (rablkno), (ralen), XBF_DONT_BLOCK)
/*
* Handling of buftargs.
*/
extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int, const char *);
extern xfs_buftarg_t *xfs_alloc_buftarg(struct xfs_mount *,
struct block_device *, int, const char *);
extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *);
extern void xfs_wait_buftarg(xfs_buftarg_t *);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __XFS_CRED_H__
#define __XFS_CRED_H__
#include <linux/capability.h>
/*
* Credentials
*/
typedef const struct cred cred_t;
#endif /* __XFS_CRED_H__ */

View file

@ -32,10 +32,9 @@ xfs_tosspages(
xfs_off_t last,
int fiopt)
{
struct address_space *mapping = VFS_I(ip)->i_mapping;
if (mapping->nrpages)
truncate_inode_pages(mapping, first);
/* can't toss partial tail pages, so mask them out */
last &= ~(PAGE_SIZE - 1);
truncate_inode_pages_range(VFS_I(ip)->i_mapping, first, last - 1);
}
int
@ -50,12 +49,11 @@ xfs_flushinval_pages(
trace_xfs_pagecache_inval(ip, first, last);
if (mapping->nrpages) {
xfs_iflags_clear(ip, XFS_ITRUNCATED);
ret = filemap_write_and_wait(mapping);
if (!ret)
truncate_inode_pages(mapping, first);
}
xfs_iflags_clear(ip, XFS_ITRUNCATED);
ret = filemap_write_and_wait_range(mapping, first,
last == -1 ? LLONG_MAX : last);
if (!ret)
truncate_inode_pages_range(mapping, first, last);
return -ret;
}
@ -71,10 +69,9 @@ xfs_flush_pages(
int ret = 0;
int ret2;
if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
xfs_iflags_clear(ip, XFS_ITRUNCATED);
ret = -filemap_fdatawrite(mapping);
}
xfs_iflags_clear(ip, XFS_ITRUNCATED);
ret = -filemap_fdatawrite_range(mapping, first,
last == -1 ? LLONG_MAX : last);
if (flags & XBF_ASYNC)
return ret;
ret2 = xfs_wait_on_pages(ip, first, last);
@ -91,7 +88,9 @@ xfs_wait_on_pages(
{
struct address_space *mapping = VFS_I(ip)->i_mapping;
if (mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK))
return -filemap_fdatawait(mapping);
if (mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) {
return -filemap_fdatawait_range(mapping, first,
last == -1 ? ip->i_size - 1 : last);
}
return 0;
}

View file

@ -16,7 +16,6 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xfs.h"
#include "xfs_cred.h"
#include "xfs_sysctl.h"
/*

View file

@ -1,23 +0,0 @@
/*
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __XFS_GLOBALS_H__
#define __XFS_GLOBALS_H__
extern uint64_t xfs_panic_mask; /* set to cause more panics */
#endif /* __XFS_GLOBALS_H__ */

View file

@ -790,7 +790,7 @@ xfs_ioc_fsgetxattr(
xfs_ilock(ip, XFS_ILOCK_SHARED);
fa.fsx_xflags = xfs_ip2xflags(ip);
fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog;
fa.fsx_projid = ip->i_d.di_projid;
fa.fsx_projid = xfs_get_projid(ip);
if (attr) {
if (ip->i_afp) {
@ -909,10 +909,10 @@ xfs_ioctl_setattr(
return XFS_ERROR(EIO);
/*
* Disallow 32bit project ids because on-disk structure
* is 16bit only.
* Disallow 32bit project ids when projid32bit feature is not enabled.
*/
if ((mask & FSX_PROJID) && (fa->fsx_projid > (__uint16_t)-1))
if ((mask & FSX_PROJID) && (fa->fsx_projid > (__uint16_t)-1) &&
!xfs_sb_version_hasprojid32bit(&ip->i_mount->m_sb))
return XFS_ERROR(EINVAL);
/*
@ -961,7 +961,7 @@ xfs_ioctl_setattr(
if (mask & FSX_PROJID) {
if (XFS_IS_QUOTA_RUNNING(mp) &&
XFS_IS_PQUOTA_ON(mp) &&
ip->i_d.di_projid != fa->fsx_projid) {
xfs_get_projid(ip) != fa->fsx_projid) {
ASSERT(tp);
code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
capable(CAP_FOWNER) ?
@ -1063,12 +1063,12 @@ xfs_ioctl_setattr(
* Change the ownerships and register quota modifications
* in the transaction.
*/
if (ip->i_d.di_projid != fa->fsx_projid) {
if (xfs_get_projid(ip) != fa->fsx_projid) {
if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) {
olddquot = xfs_qm_vop_chown(tp, ip,
&ip->i_gdquot, gdqp);
}
ip->i_d.di_projid = fa->fsx_projid;
xfs_set_projid(ip, fa->fsx_projid);
/*
* We may have to rev the inode as well as
@ -1088,8 +1088,8 @@ xfs_ioctl_setattr(
xfs_diflags_to_linux(ip);
}
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
XFS_STATS_INC(xs_ig_attrchg);
@ -1301,7 +1301,8 @@ xfs_file_ioctl(
case XFS_IOC_ALLOCSP64:
case XFS_IOC_FREESP64:
case XFS_IOC_RESVSP64:
case XFS_IOC_UNRESVSP64: {
case XFS_IOC_UNRESVSP64:
case XFS_IOC_ZERO_RANGE: {
xfs_flock64_t bf;
if (copy_from_user(&bf, arg, sizeof(bf)))

View file

@ -164,7 +164,8 @@ xfs_ioctl32_bstat_copyin(
get_user(bstat->bs_extsize, &bstat32->bs_extsize) ||
get_user(bstat->bs_extents, &bstat32->bs_extents) ||
get_user(bstat->bs_gen, &bstat32->bs_gen) ||
get_user(bstat->bs_projid, &bstat32->bs_projid) ||
get_user(bstat->bs_projid_lo, &bstat32->bs_projid_lo) ||
get_user(bstat->bs_projid_hi, &bstat32->bs_projid_hi) ||
get_user(bstat->bs_dmevmask, &bstat32->bs_dmevmask) ||
get_user(bstat->bs_dmstate, &bstat32->bs_dmstate) ||
get_user(bstat->bs_aextents, &bstat32->bs_aextents))
@ -218,6 +219,7 @@ xfs_bulkstat_one_fmt_compat(
put_user(buffer->bs_extents, &p32->bs_extents) ||
put_user(buffer->bs_gen, &p32->bs_gen) ||
put_user(buffer->bs_projid, &p32->bs_projid) ||
put_user(buffer->bs_projid_hi, &p32->bs_projid_hi) ||
put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) ||
put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
put_user(buffer->bs_aextents, &p32->bs_aextents))
@ -574,6 +576,7 @@ xfs_file_compat_ioctl(
case XFS_IOC_FSGEOMETRY_V1:
case XFS_IOC_FSGROWFSDATA:
case XFS_IOC_FSGROWFSRT:
case XFS_IOC_ZERO_RANGE:
return xfs_file_ioctl(filp, cmd, p);
#else
case XFS_IOC_ALLOCSP_32:

View file

@ -65,8 +65,10 @@ typedef struct compat_xfs_bstat {
__s32 bs_extsize; /* extent size */
__s32 bs_extents; /* number of extents */
__u32 bs_gen; /* generation count */
__u16 bs_projid; /* project id */
unsigned char bs_pad[14]; /* pad space, unused */
__u16 bs_projid_lo; /* lower part of project id */
#define bs_projid bs_projid_lo /* (previously just bs_projid) */
__u16 bs_projid_hi; /* high part of project id */
unsigned char bs_pad[12]; /* pad space, unused */
__u32 bs_dmevmask; /* DMIG event mask */
__u16 bs_dmstate; /* DMIG state info */
__u16 bs_aextents; /* attribute number of extents */

View file

@ -94,41 +94,6 @@ xfs_mark_inode_dirty(
mark_inode_dirty(inode);
}
/*
* Change the requested timestamp in the given inode.
* We don't lock across timestamp updates, and we don't log them but
* we do record the fact that there is dirty information in core.
*/
void
xfs_ichgtime(
xfs_inode_t *ip,
int flags)
{
struct inode *inode = VFS_I(ip);
timespec_t tv;
int sync_it = 0;
tv = current_fs_time(inode->i_sb);
if ((flags & XFS_ICHGTIME_MOD) &&
!timespec_equal(&inode->i_mtime, &tv)) {
inode->i_mtime = tv;
sync_it = 1;
}
if ((flags & XFS_ICHGTIME_CHG) &&
!timespec_equal(&inode->i_ctime, &tv)) {
inode->i_ctime = tv;
sync_it = 1;
}
/*
* Update complete - now make sure everyone knows that the inode
* is dirty.
*/
if (sync_it)
xfs_mark_inode_dirty_sync(ip);
}
/*
* Hook in SELinux. This is not quite correct yet, what we really need
* here (as we do for default ACLs) is a mechanism by which creation of
@ -224,7 +189,7 @@ xfs_vn_mknod(
}
xfs_dentry_to_name(&name, dentry);
error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip, NULL);
error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
if (unlikely(error))
goto out_free_acl;
@ -397,7 +362,7 @@ xfs_vn_symlink(
(irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO);
xfs_dentry_to_name(&name, dentry);
error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip, NULL);
error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip);
if (unlikely(error))
goto out;

View file

@ -71,6 +71,7 @@
#include <linux/random.h>
#include <linux/ctype.h>
#include <linux/writeback.h>
#include <linux/capability.h>
#include <asm/page.h>
#include <asm/div64.h>
@ -79,14 +80,12 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <xfs_cred.h>
#include <xfs_vnode.h>
#include <xfs_stats.h>
#include <xfs_sysctl.h>
#include <xfs_iops.h>
#include <xfs_aops.h>
#include <xfs_super.h>
#include <xfs_globals.h>
#include <xfs_buf.h>
/*
@ -144,7 +143,7 @@
#define SYNCHRONIZE() barrier()
#define __return_address __builtin_return_address(0)
#define dfltprid 0
#define XFS_PROJID_DEFAULT 0
#define MAXPATHLEN 1024
#define MIN(a,b) (min(a,b))

View file

@ -44,7 +44,6 @@
#include "xfs_buf_item.h"
#include "xfs_utils.h"
#include "xfs_vnodeops.h"
#include "xfs_version.h"
#include "xfs_log_priv.h"
#include "xfs_trans_priv.h"
#include "xfs_filestream.h"
@ -645,7 +644,7 @@ xfs_barrier_test(
XFS_BUF_ORDERED(sbp);
xfsbdstrat(mp, sbp);
error = xfs_iowait(sbp);
error = xfs_buf_iowait(sbp);
/*
* Clear all the flags we set and possible error state in the
@ -757,18 +756,20 @@ xfs_open_devices(
* Setup xfs_mount buffer target pointers
*/
error = ENOMEM;
mp->m_ddev_targp = xfs_alloc_buftarg(ddev, 0, mp->m_fsname);
mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev, 0, mp->m_fsname);
if (!mp->m_ddev_targp)
goto out_close_rtdev;
if (rtdev) {
mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev, 1, mp->m_fsname);
mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev, 1,
mp->m_fsname);
if (!mp->m_rtdev_targp)
goto out_free_ddev_targ;
}
if (logdev && logdev != ddev) {
mp->m_logdev_targp = xfs_alloc_buftarg(logdev, 1, mp->m_fsname);
mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev, 1,
mp->m_fsname);
if (!mp->m_logdev_targp)
goto out_free_rtdev_targ;
} else {
@ -971,12 +972,7 @@ xfs_fs_inode_init_once(
/*
* Dirty the XFS inode when mark_inode_dirty_sync() is called so that
* we catch unlogged VFS level updates to the inode. Care must be taken
* here - the transaction code calls mark_inode_dirty_sync() to mark the
* VFS inode dirty in a transaction and clears the i_update_core field;
* it must clear the field after calling mark_inode_dirty_sync() to
* correctly indicate that the dirty state has been propagated into the
* inode log item.
* we catch unlogged VFS level updates to the inode.
*
* We need the barrier() to maintain correct ordering between unlogged
* updates and the transaction commit code that clears the i_update_core
@ -1520,8 +1516,9 @@ xfs_fs_fill_super(
if (error)
goto out_free_fsname;
if (xfs_icsb_init_counters(mp))
mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
error = xfs_icsb_init_counters(mp);
if (error)
goto out_close_devices;
error = xfs_readsb(mp, flags);
if (error)
@ -1582,6 +1579,7 @@ xfs_fs_fill_super(
xfs_freesb(mp);
out_destroy_counters:
xfs_icsb_destroy_counters(mp);
out_close_devices:
xfs_close_devices(mp);
out_free_fsname:
xfs_free_fsname(mp);

View file

@ -62,6 +62,7 @@ extern void xfs_qm_exit(void);
# define XFS_DBG_STRING "no debug"
#endif
#define XFS_VERSION_STRING "SGI XFS"
#define XFS_BUILD_OPTIONS XFS_ACL_STRING \
XFS_SECURITY_STRING \
XFS_REALTIME_STRING \

View file

@ -39,42 +39,39 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
/*
* The inode lookup is done in batches to keep the amount of lock traffic and
* radix tree lookups to a minimum. The batch size is a trade off between
* lookup reduction and stack usage. This is in the reclaim path, so we can't
* be too greedy.
*/
#define XFS_LOOKUP_BATCH 32
STATIC xfs_inode_t *
xfs_inode_ag_lookup(
struct xfs_mount *mp,
struct xfs_perag *pag,
uint32_t *first_index,
int tag)
STATIC int
xfs_inode_ag_walk_grab(
struct xfs_inode *ip)
{
int nr_found;
struct xfs_inode *ip;
struct inode *inode = VFS_I(ip);
/*
* use a gang lookup to find the next inode in the tree
* as the tree is sparse and a gang lookup walks to find
* the number of objects requested.
*/
if (tag == XFS_ICI_NO_TAG) {
nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
(void **)&ip, *first_index, 1);
} else {
nr_found = radix_tree_gang_lookup_tag(&pag->pag_ici_root,
(void **)&ip, *first_index, 1, tag);
/* nothing to sync during shutdown */
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return EFSCORRUPTED;
/* avoid new or reclaimable inodes. Leave for reclaim code to flush */
if (xfs_iflags_test(ip, XFS_INEW | XFS_IRECLAIMABLE | XFS_IRECLAIM))
return ENOENT;
/* If we can't grab the inode, it must on it's way to reclaim. */
if (!igrab(inode))
return ENOENT;
if (is_bad_inode(inode)) {
IRELE(ip);
return ENOENT;
}
if (!nr_found)
return NULL;
/*
* Update the index for the next lookup. Catch overflows
* into the next AG range which can occur if we have inodes
* in the last block of the AG and we are currently
* pointing to the last inode.
*/
*first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
if (*first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
return NULL;
return ip;
/* inode is valid */
return 0;
}
STATIC int
@ -83,49 +80,75 @@ xfs_inode_ag_walk(
struct xfs_perag *pag,
int (*execute)(struct xfs_inode *ip,
struct xfs_perag *pag, int flags),
int flags,
int tag,
int exclusive,
int *nr_to_scan)
int flags)
{
uint32_t first_index;
int last_error = 0;
int skipped;
int done;
int nr_found;
restart:
done = 0;
skipped = 0;
first_index = 0;
nr_found = 0;
do {
struct xfs_inode *batch[XFS_LOOKUP_BATCH];
int error = 0;
xfs_inode_t *ip;
int i;
if (exclusive)
write_lock(&pag->pag_ici_lock);
else
read_lock(&pag->pag_ici_lock);
ip = xfs_inode_ag_lookup(mp, pag, &first_index, tag);
if (!ip) {
if (exclusive)
write_unlock(&pag->pag_ici_lock);
else
read_unlock(&pag->pag_ici_lock);
read_lock(&pag->pag_ici_lock);
nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
(void **)batch, first_index,
XFS_LOOKUP_BATCH);
if (!nr_found) {
read_unlock(&pag->pag_ici_lock);
break;
}
/* execute releases pag->pag_ici_lock */
error = execute(ip, pag, flags);
if (error == EAGAIN) {
skipped++;
continue;
/*
* Grab the inodes before we drop the lock. if we found
* nothing, nr == 0 and the loop will be skipped.
*/
for (i = 0; i < nr_found; i++) {
struct xfs_inode *ip = batch[i];
if (done || xfs_inode_ag_walk_grab(ip))
batch[i] = NULL;
/*
* Update the index for the next lookup. Catch overflows
* into the next AG range which can occur if we have inodes
* in the last block of the AG and we are currently
* pointing to the last inode.
*/
first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
done = 1;
}
/* unlock now we've grabbed the inodes. */
read_unlock(&pag->pag_ici_lock);
for (i = 0; i < nr_found; i++) {
if (!batch[i])
continue;
error = execute(batch[i], pag, flags);
IRELE(batch[i]);
if (error == EAGAIN) {
skipped++;
continue;
}
if (error && last_error != EFSCORRUPTED)
last_error = error;
}
if (error)
last_error = error;
/* bail out if the filesystem is corrupted. */
if (error == EFSCORRUPTED)
break;
} while ((*nr_to_scan)--);
} while (nr_found && !done);
if (skipped) {
delay(1);
@ -134,110 +157,32 @@ xfs_inode_ag_walk(
return last_error;
}
/*
* Select the next per-ag structure to iterate during the walk. The reclaim
* walk is optimised only to walk AGs with reclaimable inodes in them.
*/
static struct xfs_perag *
xfs_inode_ag_iter_next_pag(
struct xfs_mount *mp,
xfs_agnumber_t *first,
int tag)
{
struct xfs_perag *pag = NULL;
if (tag == XFS_ICI_RECLAIM_TAG) {
int found;
int ref;
spin_lock(&mp->m_perag_lock);
found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
(void **)&pag, *first, 1, tag);
if (found <= 0) {
spin_unlock(&mp->m_perag_lock);
return NULL;
}
*first = pag->pag_agno + 1;
/* open coded pag reference increment */
ref = atomic_inc_return(&pag->pag_ref);
spin_unlock(&mp->m_perag_lock);
trace_xfs_perag_get_reclaim(mp, pag->pag_agno, ref, _RET_IP_);
} else {
pag = xfs_perag_get(mp, *first);
(*first)++;
}
return pag;
}
int
xfs_inode_ag_iterator(
struct xfs_mount *mp,
int (*execute)(struct xfs_inode *ip,
struct xfs_perag *pag, int flags),
int flags,
int tag,
int exclusive,
int *nr_to_scan)
int flags)
{
struct xfs_perag *pag;
int error = 0;
int last_error = 0;
xfs_agnumber_t ag;
int nr;
nr = nr_to_scan ? *nr_to_scan : INT_MAX;
ag = 0;
while ((pag = xfs_inode_ag_iter_next_pag(mp, &ag, tag))) {
error = xfs_inode_ag_walk(mp, pag, execute, flags, tag,
exclusive, &nr);
while ((pag = xfs_perag_get(mp, ag))) {
ag = pag->pag_agno + 1;
error = xfs_inode_ag_walk(mp, pag, execute, flags);
xfs_perag_put(pag);
if (error) {
last_error = error;
if (error == EFSCORRUPTED)
break;
}
if (nr <= 0)
break;
}
if (nr_to_scan)
*nr_to_scan = nr;
return XFS_ERROR(last_error);
}
/* must be called with pag_ici_lock held and releases it */
int
xfs_sync_inode_valid(
struct xfs_inode *ip,
struct xfs_perag *pag)
{
struct inode *inode = VFS_I(ip);
int error = EFSCORRUPTED;
/* nothing to sync during shutdown */
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
goto out_unlock;
/* avoid new or reclaimable inodes. Leave for reclaim code to flush */
error = ENOENT;
if (xfs_iflags_test(ip, XFS_INEW | XFS_IRECLAIMABLE | XFS_IRECLAIM))
goto out_unlock;
/* If we can't grab the inode, it must on it's way to reclaim. */
if (!igrab(inode))
goto out_unlock;
if (is_bad_inode(inode)) {
IRELE(ip);
goto out_unlock;
}
/* inode is valid */
error = 0;
out_unlock:
read_unlock(&pag->pag_ici_lock);
return error;
}
STATIC int
xfs_sync_inode_data(
struct xfs_inode *ip,
@ -248,10 +193,6 @@ xfs_sync_inode_data(
struct address_space *mapping = inode->i_mapping;
int error = 0;
error = xfs_sync_inode_valid(ip, pag);
if (error)
return error;
if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
goto out_wait;
@ -268,7 +209,6 @@ xfs_sync_inode_data(
out_wait:
if (flags & SYNC_WAIT)
xfs_ioend_wait(ip);
IRELE(ip);
return error;
}
@ -280,10 +220,6 @@ xfs_sync_inode_attr(
{
int error = 0;
error = xfs_sync_inode_valid(ip, pag);
if (error)
return error;
xfs_ilock(ip, XFS_ILOCK_SHARED);
if (xfs_inode_clean(ip))
goto out_unlock;
@ -302,7 +238,6 @@ xfs_sync_inode_attr(
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_SHARED);
IRELE(ip);
return error;
}
@ -318,8 +253,7 @@ xfs_sync_data(
ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0);
error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags,
XFS_ICI_NO_TAG, 0, NULL);
error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags);
if (error)
return XFS_ERROR(error);
@ -337,8 +271,7 @@ xfs_sync_attr(
{
ASSERT((flags & ~SYNC_WAIT) == 0);
return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags,
XFS_ICI_NO_TAG, 0, NULL);
return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags);
}
STATIC int
@ -697,6 +630,43 @@ __xfs_inode_clear_reclaim_tag(
__xfs_inode_clear_reclaim(pag, ip);
}
/*
* Grab the inode for reclaim exclusively.
* Return 0 if we grabbed it, non-zero otherwise.
*/
STATIC int
xfs_reclaim_inode_grab(
struct xfs_inode *ip,
int flags)
{
/*
* do some unlocked checks first to avoid unnecceary lock traffic.
* The first is a flush lock check, the second is a already in reclaim
* check. Only do these checks if we are not going to block on locks.
*/
if ((flags & SYNC_TRYLOCK) &&
(!ip->i_flush.done || __xfs_iflags_test(ip, XFS_IRECLAIM))) {
return 1;
}
/*
* The radix tree lock here protects a thread in xfs_iget from racing
* with us starting reclaim on the inode. Once we have the
* XFS_IRECLAIM flag set it will not touch us.
*/
spin_lock(&ip->i_flags_lock);
ASSERT_ALWAYS(__xfs_iflags_test(ip, XFS_IRECLAIMABLE));
if (__xfs_iflags_test(ip, XFS_IRECLAIM)) {
/* ignore as it is already under reclaim */
spin_unlock(&ip->i_flags_lock);
return 1;
}
__xfs_iflags_set(ip, XFS_IRECLAIM);
spin_unlock(&ip->i_flags_lock);
return 0;
}
/*
* 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
@ -755,23 +725,6 @@ xfs_reclaim_inode(
{
int error = 0;
/*
* The radix tree lock here protects a thread in xfs_iget from racing
* with us starting reclaim on the inode. Once we have the
* XFS_IRECLAIM flag set it will not touch us.
*/
spin_lock(&ip->i_flags_lock);
ASSERT_ALWAYS(__xfs_iflags_test(ip, XFS_IRECLAIMABLE));
if (__xfs_iflags_test(ip, XFS_IRECLAIM)) {
/* ignore as it is already under reclaim */
spin_unlock(&ip->i_flags_lock);
write_unlock(&pag->pag_ici_lock);
return 0;
}
__xfs_iflags_set(ip, XFS_IRECLAIM);
spin_unlock(&ip->i_flags_lock);
write_unlock(&pag->pag_ici_lock);
xfs_ilock(ip, XFS_ILOCK_EXCL);
if (!xfs_iflock_nowait(ip)) {
if (!(sync_mode & SYNC_WAIT))
@ -868,13 +821,126 @@ xfs_reclaim_inode(
}
/*
* Walk the AGs and reclaim the inodes in them. Even if the filesystem is
* corrupted, we still want to try to reclaim all the inodes. If we don't,
* then a shut down during filesystem unmount reclaim walk leak all the
* unreclaimed inodes.
*/
int
xfs_reclaim_inodes_ag(
struct xfs_mount *mp,
int flags,
int *nr_to_scan)
{
struct xfs_perag *pag;
int error = 0;
int last_error = 0;
xfs_agnumber_t ag;
int trylock = flags & SYNC_TRYLOCK;
int skipped;
restart:
ag = 0;
skipped = 0;
while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
unsigned long first_index = 0;
int done = 0;
int nr_found = 0;
ag = pag->pag_agno + 1;
if (trylock) {
if (!mutex_trylock(&pag->pag_ici_reclaim_lock)) {
skipped++;
continue;
}
first_index = pag->pag_ici_reclaim_cursor;
} else
mutex_lock(&pag->pag_ici_reclaim_lock);
do {
struct xfs_inode *batch[XFS_LOOKUP_BATCH];
int i;
write_lock(&pag->pag_ici_lock);
nr_found = radix_tree_gang_lookup_tag(
&pag->pag_ici_root,
(void **)batch, first_index,
XFS_LOOKUP_BATCH,
XFS_ICI_RECLAIM_TAG);
if (!nr_found) {
write_unlock(&pag->pag_ici_lock);
break;
}
/*
* Grab the inodes before we drop the lock. if we found
* nothing, nr == 0 and the loop will be skipped.
*/
for (i = 0; i < nr_found; i++) {
struct xfs_inode *ip = batch[i];
if (done || xfs_reclaim_inode_grab(ip, flags))
batch[i] = NULL;
/*
* Update the index for the next lookup. Catch
* overflows into the next AG range which can
* occur if we have inodes in the last block of
* the AG and we are currently pointing to the
* last inode.
*/
first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
done = 1;
}
/* unlock now we've grabbed the inodes. */
write_unlock(&pag->pag_ici_lock);
for (i = 0; i < nr_found; i++) {
if (!batch[i])
continue;
error = xfs_reclaim_inode(batch[i], pag, flags);
if (error && last_error != EFSCORRUPTED)
last_error = error;
}
*nr_to_scan -= XFS_LOOKUP_BATCH;
} while (nr_found && !done && *nr_to_scan > 0);
if (trylock && !done)
pag->pag_ici_reclaim_cursor = first_index;
else
pag->pag_ici_reclaim_cursor = 0;
mutex_unlock(&pag->pag_ici_reclaim_lock);
xfs_perag_put(pag);
}
/*
* if we skipped any AG, and we still have scan count remaining, do
* another pass this time using blocking reclaim semantics (i.e
* waiting on the reclaim locks and ignoring the reclaim cursors). This
* ensure that when we get more reclaimers than AGs we block rather
* than spin trying to execute reclaim.
*/
if (trylock && skipped && *nr_to_scan > 0) {
trylock = 0;
goto restart;
}
return XFS_ERROR(last_error);
}
int
xfs_reclaim_inodes(
xfs_mount_t *mp,
int mode)
{
return xfs_inode_ag_iterator(mp, xfs_reclaim_inode, mode,
XFS_ICI_RECLAIM_TAG, 1, NULL);
int nr_to_scan = INT_MAX;
return xfs_reclaim_inodes_ag(mp, mode, &nr_to_scan);
}
/*
@ -896,17 +962,16 @@ xfs_reclaim_inode_shrink(
if (!(gfp_mask & __GFP_FS))
return -1;
xfs_inode_ag_iterator(mp, xfs_reclaim_inode, 0,
XFS_ICI_RECLAIM_TAG, 1, &nr_to_scan);
/* if we don't exhaust the scan, don't bother coming back */
xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK, &nr_to_scan);
/* terminate if we don't exhaust the scan */
if (nr_to_scan > 0)
return -1;
}
reclaimable = 0;
ag = 0;
while ((pag = xfs_inode_ag_iter_next_pag(mp, &ag,
XFS_ICI_RECLAIM_TAG))) {
while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
ag = pag->pag_agno + 1;
reclaimable += pag->pag_ici_reclaimable;
xfs_perag_put(pag);
}

View file

@ -47,10 +47,10 @@ void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip);
void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,
struct xfs_inode *ip);
int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag);
int xfs_sync_inode_grab(struct xfs_inode *ip);
int xfs_inode_ag_iterator(struct xfs_mount *mp,
int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
int flags, int tag, int write_lock, int *nr_to_scan);
int flags);
void xfs_inode_shrinker_register(struct xfs_mount *mp);
void xfs_inode_shrinker_unregister(struct xfs_mount *mp);

View file

@ -124,7 +124,7 @@ DEFINE_EVENT(xfs_perag_class, name, \
unsigned long caller_ip), \
TP_ARGS(mp, agno, refcount, caller_ip))
DEFINE_PERAG_REF_EVENT(xfs_perag_get);
DEFINE_PERAG_REF_EVENT(xfs_perag_get_reclaim);
DEFINE_PERAG_REF_EVENT(xfs_perag_get_tag);
DEFINE_PERAG_REF_EVENT(xfs_perag_put);
DEFINE_PERAG_REF_EVENT(xfs_perag_set_reclaim);
DEFINE_PERAG_REF_EVENT(xfs_perag_clear_reclaim);
@ -330,7 +330,7 @@ DEFINE_BUF_EVENT(xfs_buf_iowait_done);
DEFINE_BUF_EVENT(xfs_buf_delwri_queue);
DEFINE_BUF_EVENT(xfs_buf_delwri_dequeue);
DEFINE_BUF_EVENT(xfs_buf_delwri_split);
DEFINE_BUF_EVENT(xfs_buf_get_noaddr);
DEFINE_BUF_EVENT(xfs_buf_get_uncached);
DEFINE_BUF_EVENT(xfs_bdstrat_shut);
DEFINE_BUF_EVENT(xfs_buf_item_relse);
DEFINE_BUF_EVENT(xfs_buf_item_iodone);

View file

@ -1,29 +0,0 @@
/*
* Copyright (c) 2001-2002,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __XFS_VERSION_H__
#define __XFS_VERSION_H__
/*
* Dummy file that can contain a timestamp to put into the
* XFS init string, to help users keep track of what they're
* running
*/
#define XFS_VERSION_STRING "SGI XFS"
#endif /* __XFS_VERSION_H__ */

View file

@ -463,88 +463,69 @@ xfs_qm_dqtobp(
uint flags)
{
xfs_bmbt_irec_t map;
int nmaps, error;
int nmaps = 1, error;
xfs_buf_t *bp;
xfs_inode_t *quotip;
xfs_mount_t *mp;
xfs_inode_t *quotip = XFS_DQ_TO_QIP(dqp);
xfs_mount_t *mp = dqp->q_mount;
xfs_disk_dquot_t *ddq;
xfs_dqid_t id;
boolean_t newdquot;
xfs_dqid_t id = be32_to_cpu(dqp->q_core.d_id);
xfs_trans_t *tp = (tpp ? *tpp : NULL);
mp = dqp->q_mount;
id = be32_to_cpu(dqp->q_core.d_id);
nmaps = 1;
newdquot = B_FALSE;
dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk;
/*
* If we don't know where the dquot lives, find out.
*/
if (dqp->q_blkno == (xfs_daddr_t) 0) {
/* We use the id as an index */
dqp->q_fileoffset = (xfs_fileoff_t)id /
mp->m_quotainfo->qi_dqperchunk;
nmaps = 1;
quotip = XFS_DQ_TO_QIP(dqp);
xfs_ilock(quotip, XFS_ILOCK_SHARED);
xfs_ilock(quotip, XFS_ILOCK_SHARED);
if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
/*
* Return if this type of quotas is turned off while we didn't
* have an inode lock
* Return if this type of quotas is turned off while we
* didn't have the quota inode lock.
*/
if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
xfs_iunlock(quotip, XFS_ILOCK_SHARED);
return (ESRCH);
}
/*
* Find the block map; no allocations yet
*/
error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
XFS_DQUOT_CLUSTER_SIZE_FSB,
XFS_BMAPI_METADATA,
NULL, 0, &map, &nmaps, NULL);
xfs_iunlock(quotip, XFS_ILOCK_SHARED);
if (error)
return (error);
ASSERT(nmaps == 1);
ASSERT(map.br_blockcount == 1);
/*
* offset of dquot in the (fixed sized) dquot chunk.
*/
dqp->q_bufoffset = (id % mp->m_quotainfo->qi_dqperchunk) *
sizeof(xfs_dqblk_t);
if (map.br_startblock == HOLESTARTBLOCK) {
/*
* We don't allocate unless we're asked to
*/
if (!(flags & XFS_QMOPT_DQALLOC))
return (ENOENT);
ASSERT(tp);
if ((error = xfs_qm_dqalloc(tpp, mp, dqp, quotip,
dqp->q_fileoffset, &bp)))
return (error);
tp = *tpp;
newdquot = B_TRUE;
} else {
/*
* store the blkno etc so that we don't have to do the
* mapping all the time
*/
dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
}
return ESRCH;
}
ASSERT(dqp->q_blkno != DELAYSTARTBLOCK);
ASSERT(dqp->q_blkno != HOLESTARTBLOCK);
/*
* Read in the buffer, unless we've just done the allocation
* (in which case we already have the buf).
* Find the block map; no allocations yet
*/
if (!newdquot) {
error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA,
NULL, 0, &map, &nmaps, NULL);
xfs_iunlock(quotip, XFS_ILOCK_SHARED);
if (error)
return error;
ASSERT(nmaps == 1);
ASSERT(map.br_blockcount == 1);
/*
* Offset of dquot in the (fixed sized) dquot chunk.
*/
dqp->q_bufoffset = (id % mp->m_quotainfo->qi_dqperchunk) *
sizeof(xfs_dqblk_t);
ASSERT(map.br_startblock != DELAYSTARTBLOCK);
if (map.br_startblock == HOLESTARTBLOCK) {
/*
* We don't allocate unless we're asked to
*/
if (!(flags & XFS_QMOPT_DQALLOC))
return ENOENT;
ASSERT(tp);
error = xfs_qm_dqalloc(tpp, mp, dqp, quotip,
dqp->q_fileoffset, &bp);
if (error)
return error;
tp = *tpp;
} else {
trace_xfs_dqtobp_read(dqp);
/*
* store the blkno etc so that we don't have to do the
* mapping all the time
*/
dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock);
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen,
@ -552,13 +533,14 @@ xfs_qm_dqtobp(
if (error || !bp)
return XFS_ERROR(error);
}
ASSERT(XFS_BUF_ISBUSY(bp));
ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
/*
* calculate the location of the dquot inside the buffer.
*/
ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset);
ddq = (struct xfs_disk_dquot *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset);
/*
* A simple sanity check in case we got a corrupted dquot...
@ -1176,18 +1158,18 @@ xfs_qm_dqflush(
xfs_dquot_t *dqp,
uint flags)
{
xfs_mount_t *mp;
xfs_buf_t *bp;
xfs_disk_dquot_t *ddqp;
struct xfs_mount *mp = dqp->q_mount;
struct xfs_buf *bp;
struct xfs_disk_dquot *ddqp;
int error;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
ASSERT(!completion_done(&dqp->q_flush));
trace_xfs_dqflush(dqp);
/*
* If not dirty, or it's pinned and we are not supposed to
* block, nada.
* If not dirty, or it's pinned and we are not supposed to block, nada.
*/
if (!XFS_DQ_IS_DIRTY(dqp) ||
(!(flags & SYNC_WAIT) && atomic_read(&dqp->q_pincount) > 0)) {
@ -1201,40 +1183,46 @@ xfs_qm_dqflush(
* down forcibly. If that's the case we must not write this dquot
* to disk, because the log record didn't make it to disk!
*/
if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) {
dqp->dq_flags &= ~(XFS_DQ_DIRTY);
if (XFS_FORCED_SHUTDOWN(mp)) {
dqp->dq_flags &= ~XFS_DQ_DIRTY;
xfs_dqfunlock(dqp);
return XFS_ERROR(EIO);
}
/*
* Get the buffer containing the on-disk dquot
* We don't need a transaction envelope because we know that the
* the ondisk-dquot has already been allocated for.
*/
if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) {
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen, 0, &bp);
if (error) {
ASSERT(error != ENOENT);
/*
* Quotas could have gotten turned off (ESRCH)
*/
xfs_dqfunlock(dqp);
return (error);
return error;
}
if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id),
0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) {
xfs_force_shutdown(dqp->q_mount, SHUTDOWN_CORRUPT_INCORE);
/*
* Calculate the location of the dquot inside the buffer.
*/
ddqp = (struct xfs_disk_dquot *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset);
/*
* A simple sanity check in case we got a corrupted dquot..
*/
if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id), 0,
XFS_QMOPT_DOWARN, "dqflush (incore copy)")) {
xfs_buf_relse(bp);
xfs_dqfunlock(dqp);
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
return XFS_ERROR(EIO);
}
/* This is the only portion of data that needs to persist */
memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t));
memcpy(ddqp, &dqp->q_core, sizeof(xfs_disk_dquot_t));
/*
* Clear the dirty field and remember the flush lsn for later use.
*/
dqp->dq_flags &= ~(XFS_DQ_DIRTY);
mp = dqp->q_mount;
dqp->dq_flags &= ~XFS_DQ_DIRTY;
xfs_trans_ail_copy_lsn(mp->m_ail, &dqp->q_logitem.qli_flush_lsn,
&dqp->q_logitem.qli_item.li_lsn);

View file

@ -55,8 +55,6 @@ uint ndquot;
kmem_zone_t *qm_dqzone;
kmem_zone_t *qm_dqtrxzone;
static cred_t xfs_zerocr;
STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int);
STATIC void xfs_qm_list_destroy(xfs_dqlist_t *);
@ -837,7 +835,7 @@ xfs_qm_dqattach_locked(
xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
flags & XFS_QMOPT_DQALLOC,
ip->i_udquot, &ip->i_gdquot) :
xfs_qm_dqattach_one(ip, ip->i_d.di_projid, XFS_DQ_PROJ,
xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
flags & XFS_QMOPT_DQALLOC,
ip->i_udquot, &ip->i_gdquot);
/*
@ -1199,87 +1197,6 @@ xfs_qm_list_destroy(
mutex_destroy(&(list->qh_lock));
}
/*
* Stripped down version of dqattach. This doesn't attach, or even look at the
* dquots attached to the inode. The rationale is that there won't be any
* attached at the time this is called from quotacheck.
*/
STATIC int
xfs_qm_dqget_noattach(
xfs_inode_t *ip,
xfs_dquot_t **O_udqpp,
xfs_dquot_t **O_gdqpp)
{
int error;
xfs_mount_t *mp;
xfs_dquot_t *udqp, *gdqp;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
mp = ip->i_mount;
udqp = NULL;
gdqp = NULL;
if (XFS_IS_UQUOTA_ON(mp)) {
ASSERT(ip->i_udquot == NULL);
/*
* We want the dquot allocated if it doesn't exist.
*/
if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER,
XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN,
&udqp))) {
/*
* Shouldn't be able to turn off quotas here.
*/
ASSERT(error != ESRCH);
ASSERT(error != ENOENT);
return error;
}
ASSERT(udqp);
}
if (XFS_IS_OQUOTA_ON(mp)) {
ASSERT(ip->i_gdquot == NULL);
if (udqp)
xfs_dqunlock(udqp);
error = XFS_IS_GQUOTA_ON(mp) ?
xfs_qm_dqget(mp, ip,
ip->i_d.di_gid, XFS_DQ_GROUP,
XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
&gdqp) :
xfs_qm_dqget(mp, ip,
ip->i_d.di_projid, XFS_DQ_PROJ,
XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN,
&gdqp);
if (error) {
if (udqp)
xfs_qm_dqrele(udqp);
ASSERT(error != ESRCH);
ASSERT(error != ENOENT);
return error;
}
ASSERT(gdqp);
/* Reacquire the locks in the right order */
if (udqp) {
if (! xfs_qm_dqlock_nowait(udqp)) {
xfs_dqunlock(gdqp);
xfs_dqlock(udqp);
xfs_dqlock(gdqp);
}
}
}
*O_udqpp = udqp;
*O_gdqpp = gdqp;
#ifdef QUOTADEBUG
if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp));
if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp));
#endif
return 0;
}
/*
* Create an inode and return with a reference already taken, but unlocked
* This is how we create quota inodes
@ -1305,8 +1222,8 @@ xfs_qm_qino_alloc(
return error;
}
if ((error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0,
&xfs_zerocr, 0, 1, ip, &committed))) {
error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip, &committed);
if (error) {
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT);
return error;
@ -1516,7 +1433,7 @@ xfs_qm_dqiterate(
rablkcnt = map[i+1].br_blockcount;
rablkno = map[i+1].br_startblock;
while (rablkcnt--) {
xfs_baread(mp->m_ddev_targp,
xfs_buf_readahead(mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, rablkno),
mp->m_quotainfo->qi_dqchunklen);
rablkno++;
@ -1546,18 +1463,34 @@ xfs_qm_dqiterate(
/*
* Called by dqusage_adjust in doing a quotacheck.
* Given the inode, and a dquot (either USR or GRP, doesn't matter),
* this updates its incore copy as well as the buffer copy. This is
* so that once the quotacheck is done, we can just log all the buffers,
* as opposed to logging numerous updates to individual dquots.
*
* Given the inode, and a dquot id this updates both the incore dqout as well
* as the buffer copy. This is so that once the quotacheck is done, we can
* just log all the buffers, as opposed to logging numerous updates to
* individual dquots.
*/
STATIC void
STATIC int
xfs_qm_quotacheck_dqadjust(
xfs_dquot_t *dqp,
struct xfs_inode *ip,
xfs_dqid_t id,
uint type,
xfs_qcnt_t nblks,
xfs_qcnt_t rtblks)
{
ASSERT(XFS_DQ_IS_LOCKED(dqp));
struct xfs_mount *mp = ip->i_mount;
struct xfs_dquot *dqp;
int error;
error = xfs_qm_dqget(mp, ip, id, type,
XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, &dqp);
if (error) {
/*
* Shouldn't be able to turn off quotas here.
*/
ASSERT(error != ESRCH);
ASSERT(error != ENOENT);
return error;
}
trace_xfs_dqadjust(dqp);
@ -1582,11 +1515,13 @@ xfs_qm_quotacheck_dqadjust(
* There are no timers for the default values set in the root dquot.
*/
if (dqp->q_core.d_id) {
xfs_qm_adjust_dqlimits(dqp->q_mount, &dqp->q_core);
xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core);
xfs_qm_adjust_dqlimits(mp, &dqp->q_core);
xfs_qm_adjust_dqtimers(mp, &dqp->q_core);
}
dqp->dq_flags |= XFS_DQ_DIRTY;
xfs_qm_dqput(dqp);
return 0;
}
STATIC int
@ -1629,8 +1564,7 @@ xfs_qm_dqusage_adjust(
int *res) /* result code value */
{
xfs_inode_t *ip;
xfs_dquot_t *udqp, *gdqp;
xfs_qcnt_t nblks, rtblks;
xfs_qcnt_t nblks, rtblks = 0;
int error;
ASSERT(XFS_IS_QUOTA_RUNNING(mp));
@ -1650,51 +1584,24 @@ xfs_qm_dqusage_adjust(
* the case in all other instances. It's OK that we do this because
* quotacheck is done only at mount time.
*/
if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip))) {
error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip);
if (error) {
*res = BULKSTAT_RV_NOTHING;
return error;
}
/*
* Obtain the locked dquots. In case of an error (eg. allocation
* fails for ENOSPC), we return the negative of the error number
* to bulkstat, so that it can get propagated to quotacheck() and
* making us disable quotas for the file system.
*/
if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) {
xfs_iunlock(ip, XFS_ILOCK_EXCL);
IRELE(ip);
*res = BULKSTAT_RV_GIVEUP;
return error;
}
ASSERT(ip->i_delayed_blks == 0);
rtblks = 0;
if (! XFS_IS_REALTIME_INODE(ip)) {
nblks = (xfs_qcnt_t)ip->i_d.di_nblocks;
} else {
if (XFS_IS_REALTIME_INODE(ip)) {
/*
* Walk thru the extent list and count the realtime blocks.
*/
if ((error = xfs_qm_get_rtblks(ip, &rtblks))) {
xfs_iunlock(ip, XFS_ILOCK_EXCL);
IRELE(ip);
if (udqp)
xfs_qm_dqput(udqp);
if (gdqp)
xfs_qm_dqput(gdqp);
*res = BULKSTAT_RV_GIVEUP;
return error;
}
nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
error = xfs_qm_get_rtblks(ip, &rtblks);
if (error)
goto error0;
}
ASSERT(ip->i_delayed_blks == 0);
/*
* We can't release the inode while holding its dquot locks.
* The inode can go into inactive and might try to acquire the dquotlocks.
* So, just unlock here and do a vn_rele at the end.
*/
xfs_iunlock(ip, XFS_ILOCK_EXCL);
nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
/*
* Add the (disk blocks and inode) resources occupied by this
@ -1709,26 +1616,36 @@ xfs_qm_dqusage_adjust(
* and quotaoffs don't race. (Quotachecks happen at mount time only).
*/
if (XFS_IS_UQUOTA_ON(mp)) {
ASSERT(udqp);
xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks);
xfs_qm_dqput(udqp);
error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_uid,
XFS_DQ_USER, nblks, rtblks);
if (error)
goto error0;
}
if (XFS_IS_OQUOTA_ON(mp)) {
ASSERT(gdqp);
xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks);
xfs_qm_dqput(gdqp);
}
/*
* Now release the inode. This will send it to 'inactive', and
* possibly even free blocks.
*/
IRELE(ip);
/*
* Goto next inode.
*/
if (XFS_IS_GQUOTA_ON(mp)) {
error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_gid,
XFS_DQ_GROUP, nblks, rtblks);
if (error)
goto error0;
}
if (XFS_IS_PQUOTA_ON(mp)) {
error = xfs_qm_quotacheck_dqadjust(ip, xfs_get_projid(ip),
XFS_DQ_PROJ, nblks, rtblks);
if (error)
goto error0;
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
IRELE(ip);
*res = BULKSTAT_RV_DIDONE;
return 0;
error0:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
IRELE(ip);
*res = BULKSTAT_RV_GIVEUP;
return error;
}
/*
@ -2224,7 +2141,7 @@ xfs_qm_write_sb_changes(
/*
* Given an inode, a uid and gid (from cred_t) make sure that we have
* Given an inode, a uid, gid and prid make sure that we have
* allocated relevant dquot(s) on disk, and that we won't exceed inode
* quotas by creating this file.
* This also attaches dquot(s) to the given inode after locking it,
@ -2332,7 +2249,7 @@ xfs_qm_vop_dqalloc(
xfs_dqunlock(gq);
}
} else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
if (ip->i_d.di_projid != prid) {
if (xfs_get_projid(ip) != prid) {
xfs_iunlock(ip, lockflags);
if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
XFS_DQ_PROJ,
@ -2454,7 +2371,7 @@ xfs_qm_vop_chown_reserve(
}
if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
if (XFS_IS_PQUOTA_ON(ip->i_mount) &&
ip->i_d.di_projid != be32_to_cpu(gdqp->q_core.d_id))
xfs_get_projid(ip) != be32_to_cpu(gdqp->q_core.d_id))
prjflags = XFS_QMOPT_ENOSPC;
if (prjflags ||
@ -2558,7 +2475,7 @@ xfs_qm_vop_create_dqattach(
ip->i_gdquot = gdqp;
ASSERT(XFS_IS_OQUOTA_ON(mp));
ASSERT((XFS_IS_GQUOTA_ON(mp) ?
ip->i_d.di_gid : ip->i_d.di_projid) ==
ip->i_d.di_gid : xfs_get_projid(ip)) ==
be32_to_cpu(gdqp->q_core.d_id));
xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
}

View file

@ -81,7 +81,7 @@ xfs_qm_statvfs(
xfs_mount_t *mp = ip->i_mount;
xfs_dquot_t *dqp;
if (!xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp)) {
if (!xfs_qm_dqget(mp, NULL, xfs_get_projid(ip), XFS_DQ_PROJ, 0, &dqp)) {
xfs_fill_statvfs_from_dquot(statp, &dqp->q_core);
xfs_qm_dqput(dqp);
}

View file

@ -276,7 +276,7 @@ xfs_qm_scall_trunc_qfile(
goto out_unlock;
}
xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
out_unlock:
@ -875,21 +875,14 @@ xfs_dqrele_inode(
struct xfs_perag *pag,
int flags)
{
int error;
/* skip quota inodes */
if (ip == ip->i_mount->m_quotainfo->qi_uquotaip ||
ip == ip->i_mount->m_quotainfo->qi_gquotaip) {
ASSERT(ip->i_udquot == NULL);
ASSERT(ip->i_gdquot == NULL);
read_unlock(&pag->pag_ici_lock);
return 0;
}
error = xfs_sync_inode_valid(ip, pag);
if (error)
return error;
xfs_ilock(ip, XFS_ILOCK_EXCL);
if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
xfs_qm_dqrele(ip->i_udquot);
@ -900,8 +893,6 @@ xfs_dqrele_inode(
ip->i_gdquot = NULL;
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
IRELE(ip);
return 0;
}
@ -918,8 +909,7 @@ xfs_qm_dqrele_all_inodes(
uint flags)
{
ASSERT(mp->m_quotainfo);
xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags,
XFS_ICI_NO_TAG, 0, NULL);
xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags);
}
/*------------------------------------------------------------------------*/
@ -1175,7 +1165,7 @@ xfs_qm_internalqcheck_adjust(
}
xfs_qm_internalqcheck_get_dquots(mp,
(xfs_dqid_t) ip->i_d.di_uid,
(xfs_dqid_t) ip->i_d.di_projid,
(xfs_dqid_t) xfs_get_projid(ip),
(xfs_dqid_t) ip->i_d.di_gid,
&ud, &gd);
if (XFS_IS_UQUOTA_ON(mp)) {

View file

@ -230,6 +230,15 @@ typedef struct xfs_perag {
rwlock_t pag_ici_lock; /* incore inode lock */
struct radix_tree_root pag_ici_root; /* incore inode cache root */
int pag_ici_reclaimable; /* reclaimable inodes */
struct mutex pag_ici_reclaim_lock; /* serialisation point */
unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */
/* buffer cache index */
spinlock_t pag_buf_lock; /* lock for pag_buf_tree */
struct rb_root pag_buf_tree; /* ordered tree of active buffers */
/* for rcu-safe freeing */
struct rcu_head rcu_head;
#endif
int pagb_count; /* pagb slots in use */
} xfs_perag_t;

View file

@ -675,7 +675,7 @@ xfs_alloc_ag_vextent_near(
xfs_agblock_t gtbnoa; /* aligned ... */
xfs_extlen_t gtdiff; /* difference to right side entry */
xfs_extlen_t gtlen; /* length of right side entry */
xfs_extlen_t gtlena; /* aligned ... */
xfs_extlen_t gtlena = 0; /* aligned ... */
xfs_agblock_t gtnew; /* useful start bno of right side */
int error; /* error code */
int i; /* result code, temporary */
@ -684,7 +684,7 @@ xfs_alloc_ag_vextent_near(
xfs_agblock_t ltbnoa; /* aligned ... */
xfs_extlen_t ltdiff; /* difference to left side entry */
xfs_extlen_t ltlen; /* length of left side entry */
xfs_extlen_t ltlena; /* aligned ... */
xfs_extlen_t ltlena = 0; /* aligned ... */
xfs_agblock_t ltnew; /* useful start bno of left side */
xfs_extlen_t rlen; /* length of returned extent */
#if defined(DEBUG) && defined(__KERNEL__)

View file

@ -280,38 +280,6 @@ xfs_allocbt_key_diff(
return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock;
}
STATIC int
xfs_allocbt_kill_root(
struct xfs_btree_cur *cur,
struct xfs_buf *bp,
int level,
union xfs_btree_ptr *newroot)
{
int error;
XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
XFS_BTREE_STATS_INC(cur, killroot);
/*
* Update the root pointer, decreasing the level by 1 and then
* free the old root.
*/
xfs_allocbt_set_root(cur, newroot, -1);
error = xfs_allocbt_free_block(cur, bp);
if (error) {
XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
XFS_BTREE_STATS_INC(cur, free);
xfs_btree_setbuf(cur, level, NULL);
cur->bc_nlevels--;
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
}
#ifdef DEBUG
STATIC int
xfs_allocbt_keys_inorder(
@ -423,7 +391,6 @@ static const struct xfs_btree_ops xfs_allocbt_ops = {
.dup_cursor = xfs_allocbt_dup_cursor,
.set_root = xfs_allocbt_set_root,
.kill_root = xfs_allocbt_kill_root,
.alloc_block = xfs_allocbt_alloc_block,
.free_block = xfs_allocbt_free_block,
.update_lastrec = xfs_allocbt_update_lastrec,

View file

@ -355,16 +355,15 @@ xfs_attr_set_int(
if (mp->m_flags & XFS_MOUNT_WSYNC) {
xfs_trans_set_sync(args.trans);
}
if (!error && (flags & ATTR_KERNOTIME) == 0) {
xfs_trans_ichgtime(args.trans, dp,
XFS_ICHGTIME_CHG);
}
err2 = xfs_trans_commit(args.trans,
XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
/*
* Hit the inode change time.
*/
if (!error && (flags & ATTR_KERNOTIME) == 0) {
xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
}
return(error == 0 ? err2 : error);
}
@ -420,6 +419,9 @@ xfs_attr_set_int(
xfs_trans_set_sync(args.trans);
}
if ((flags & ATTR_KERNOTIME) == 0)
xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
/*
* Commit the last in the sequence of transactions.
*/
@ -427,13 +429,6 @@ xfs_attr_set_int(
error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
/*
* Hit the inode change time.
*/
if (!error && (flags & ATTR_KERNOTIME) == 0) {
xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
}
return(error);
out:
@ -567,6 +562,9 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
xfs_trans_set_sync(args.trans);
}
if ((flags & ATTR_KERNOTIME) == 0)
xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
/*
* Commit the last in the sequence of transactions.
*/
@ -574,13 +572,6 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
/*
* Hit the inode change time.
*/
if (!error && (flags & ATTR_KERNOTIME) == 0) {
xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
}
return(error);
out:
@ -1995,7 +1986,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
tmp = (valuelen < XFS_BUF_SIZE(bp))
? valuelen : XFS_BUF_SIZE(bp);
xfs_biomove(bp, 0, tmp, dst, XBF_READ);
xfs_buf_iomove(bp, 0, tmp, dst, XBRW_READ);
xfs_buf_relse(bp);
dst += tmp;
valuelen -= tmp;
@ -2125,9 +2116,9 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
XFS_BUF_SIZE(bp);
xfs_biomove(bp, 0, tmp, src, XBF_WRITE);
xfs_buf_iomove(bp, 0, tmp, src, XBRW_WRITE);
if (tmp < XFS_BUF_SIZE(bp))
xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
xfs_buf_zero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */
return (error);
}

View file

@ -614,7 +614,7 @@ xfs_bmap_add_extent(
nblks += cur->bc_private.b.allocated;
ASSERT(nblks <= da_old);
if (nblks < da_old)
xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS,
xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
(int64_t)(da_old - nblks), rsvd);
}
/*
@ -1079,7 +1079,8 @@ xfs_bmap_add_extent_delay_real(
diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) -
(cur ? cur->bc_private.b.allocated : 0));
if (diff > 0 &&
xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, -((int64_t)diff), rsvd)) {
xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
-((int64_t)diff), rsvd)) {
/*
* Ick gross gag me with a spoon.
*/
@ -1089,16 +1090,18 @@ xfs_bmap_add_extent_delay_real(
temp--;
diff--;
if (!diff ||
!xfs_mod_incore_sb(ip->i_mount,
XFS_SBS_FDBLOCKS, -((int64_t)diff), rsvd))
!xfs_icsb_modify_counters(ip->i_mount,
XFS_SBS_FDBLOCKS,
-((int64_t)diff), rsvd))
break;
}
if (temp2) {
temp2--;
diff--;
if (!diff ||
!xfs_mod_incore_sb(ip->i_mount,
XFS_SBS_FDBLOCKS, -((int64_t)diff), rsvd))
!xfs_icsb_modify_counters(ip->i_mount,
XFS_SBS_FDBLOCKS,
-((int64_t)diff), rsvd))
break;
}
}
@ -1766,7 +1769,7 @@ xfs_bmap_add_extent_hole_delay(
}
if (oldlen != newlen) {
ASSERT(oldlen > newlen);
xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS,
xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
(int64_t)(oldlen - newlen), rsvd);
/*
* Nothing to do for disk quota accounting here.
@ -3111,9 +3114,10 @@ xfs_bmap_del_extent(
* Nothing to do for disk quota accounting here.
*/
ASSERT(da_old >= da_new);
if (da_old > da_new)
xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int64_t)(da_old - da_new),
rsvd);
if (da_old > da_new) {
xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
(int64_t)(da_old - da_new), rsvd);
}
done:
*logflagsp = flags;
return error;
@ -4526,13 +4530,13 @@ xfs_bmapi(
-((int64_t)extsz), (flags &
XFS_BMAPI_RSVBLOCKS));
} else {
error = xfs_mod_incore_sb(mp,
error = xfs_icsb_modify_counters(mp,
XFS_SBS_FDBLOCKS,
-((int64_t)alen), (flags &
XFS_BMAPI_RSVBLOCKS));
}
if (!error) {
error = xfs_mod_incore_sb(mp,
error = xfs_icsb_modify_counters(mp,
XFS_SBS_FDBLOCKS,
-((int64_t)indlen), (flags &
XFS_BMAPI_RSVBLOCKS));
@ -4542,7 +4546,7 @@ xfs_bmapi(
(int64_t)extsz, (flags &
XFS_BMAPI_RSVBLOCKS));
else if (error)
xfs_mod_incore_sb(mp,
xfs_icsb_modify_counters(mp,
XFS_SBS_FDBLOCKS,
(int64_t)alen, (flags &
XFS_BMAPI_RSVBLOCKS));
@ -4744,8 +4748,12 @@ xfs_bmapi(
* Check if writing previously allocated but
* unwritten extents.
*/
if (wr && mval->br_state == XFS_EXT_UNWRITTEN &&
((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) {
if (wr &&
((mval->br_state == XFS_EXT_UNWRITTEN &&
((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) ||
(mval->br_state == XFS_EXT_NORM &&
((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT)) ==
(XFS_BMAPI_PREALLOC|XFS_BMAPI_CONVERT))))) {
/*
* Modify (by adding) the state flag, if writing.
*/
@ -4757,7 +4765,9 @@ xfs_bmapi(
*firstblock;
cur->bc_private.b.flist = flist;
}
mval->br_state = XFS_EXT_NORM;
mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
? XFS_EXT_NORM
: XFS_EXT_UNWRITTEN;
error = xfs_bmap_add_extent(ip, lastx, &cur, mval,
firstblock, flist, &tmp_logflags,
whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
@ -5200,7 +5210,7 @@ xfs_bunmapi(
ip, -((long)del.br_blockcount), 0,
XFS_QMOPT_RES_RTBLKS);
} else {
xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS,
xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
(int64_t)del.br_blockcount, rsvd);
(void)xfs_trans_reserve_quota_nblks(NULL,
ip, -((long)del.br_blockcount), 0,

View file

@ -74,9 +74,12 @@ typedef struct xfs_bmap_free
#define XFS_BMAPI_IGSTATE 0x080 /* Ignore state - */
/* combine contig. space */
#define XFS_BMAPI_CONTIG 0x100 /* must allocate only one extent */
#define XFS_BMAPI_CONVERT 0x200 /* unwritten extent conversion - */
/* need write cache flushing and no */
/* additional allocation alignments */
/*
* unwritten extent conversion - this needs write cache flushing and no additional
* allocation alignments. When specified with XFS_BMAPI_PREALLOC it converts
* from written to unwritten, otherwise convert from unwritten to written.
*/
#define XFS_BMAPI_CONVERT 0x200
#define XFS_BMAPI_FLAGS \
{ XFS_BMAPI_WRITE, "WRITE" }, \

View file

@ -217,7 +217,7 @@ xfs_btree_del_cursor(
*/
for (i = 0; i < cur->bc_nlevels; i++) {
if (cur->bc_bufs[i])
xfs_btree_setbuf(cur, i, NULL);
xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[i]);
else if (!error)
break;
}
@ -656,7 +656,7 @@ xfs_btree_reada_bufl(
ASSERT(fsbno != NULLFSBLOCK);
d = XFS_FSB_TO_DADDR(mp, fsbno);
xfs_baread(mp->m_ddev_targp, d, mp->m_bsize * count);
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count);
}
/*
@ -676,7 +676,7 @@ xfs_btree_reada_bufs(
ASSERT(agno != NULLAGNUMBER);
ASSERT(agbno != NULLAGBLOCK);
d = XFS_AGB_TO_DADDR(mp, agno, agbno);
xfs_baread(mp->m_ddev_targp, d, mp->m_bsize * count);
xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count);
}
STATIC int
@ -763,22 +763,19 @@ xfs_btree_readahead(
* Set the buffer for level "lev" in the cursor to bp, releasing
* any previous buffer.
*/
void
STATIC void
xfs_btree_setbuf(
xfs_btree_cur_t *cur, /* btree cursor */
int lev, /* level in btree */
xfs_buf_t *bp) /* new buffer to set */
{
struct xfs_btree_block *b; /* btree block */
xfs_buf_t *obp; /* old buffer pointer */
obp = cur->bc_bufs[lev];
if (obp)
xfs_trans_brelse(cur->bc_tp, obp);
if (cur->bc_bufs[lev])
xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[lev]);
cur->bc_bufs[lev] = bp;
cur->bc_ra[lev] = 0;
if (!bp)
return;
b = XFS_BUF_TO_BLOCK(bp);
if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
if (be64_to_cpu(b->bb_u.l.bb_leftsib) == NULLDFSBNO)
@ -3011,6 +3008,43 @@ xfs_btree_kill_iroot(
return 0;
}
/*
* Kill the current root node, and replace it with it's only child node.
*/
STATIC int
xfs_btree_kill_root(
struct xfs_btree_cur *cur,
struct xfs_buf *bp,
int level,
union xfs_btree_ptr *newroot)
{
int error;
XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
XFS_BTREE_STATS_INC(cur, killroot);
/*
* Update the root pointer, decreasing the level by 1 and then
* free the old root.
*/
cur->bc_ops->set_root(cur, newroot, -1);
error = cur->bc_ops->free_block(cur, bp);
if (error) {
XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
XFS_BTREE_STATS_INC(cur, free);
cur->bc_bufs[level] = NULL;
cur->bc_ra[level] = 0;
cur->bc_nlevels--;
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
}
STATIC int
xfs_btree_dec_cursor(
struct xfs_btree_cur *cur,
@ -3195,7 +3229,7 @@ xfs_btree_delrec(
* Make it the new root of the btree.
*/
pp = xfs_btree_ptr_addr(cur, 1, block);
error = cur->bc_ops->kill_root(cur, bp, level, pp);
error = xfs_btree_kill_root(cur, bp, level, pp);
if (error)
goto error0;
} else if (level > 0) {

View file

@ -152,9 +152,7 @@ struct xfs_btree_ops {
/* update btree root pointer */
void (*set_root)(struct xfs_btree_cur *cur,
union xfs_btree_ptr *nptr, int level_change);
int (*kill_root)(struct xfs_btree_cur *cur, struct xfs_buf *bp,
int level, union xfs_btree_ptr *newroot);
union xfs_btree_ptr *nptr, int level_change);
/* block allocation / freeing */
int (*alloc_block)(struct xfs_btree_cur *cur,
@ -399,16 +397,6 @@ xfs_btree_reada_bufs(
xfs_agblock_t agbno, /* allocation group block number */
xfs_extlen_t count); /* count of filesystem blocks */
/*
* Set the buffer for level "lev" in the cursor to bp, releasing
* any previous buffer.
*/
void
xfs_btree_setbuf(
xfs_btree_cur_t *cur, /* btree cursor */
int lev, /* level in btree */
struct xfs_buf *bp); /* new buffer to set */
/*
* Common btree core entry points.

View file

@ -692,8 +692,7 @@ xfs_buf_item_init(
* the first. If we do already have one, there is
* nothing to do here so return.
*/
if (bp->b_mount != mp)
bp->b_mount = mp;
ASSERT(bp->b_target->bt_mount == mp);
if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) {
lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
if (lip->li_type == XFS_LI_BUF) {
@ -974,7 +973,7 @@ xfs_buf_iodone_callbacks(
xfs_buf_do_callbacks(bp, lip);
XFS_BUF_SET_FSPRIVATE(bp, NULL);
XFS_BUF_CLR_IODONE_FUNC(bp);
xfs_biodone(bp);
xfs_buf_ioend(bp, 0);
return;
}
@ -1033,7 +1032,7 @@ xfs_buf_iodone_callbacks(
xfs_buf_do_callbacks(bp, lip);
XFS_BUF_SET_FSPRIVATE(bp, NULL);
XFS_BUF_CLR_IODONE_FUNC(bp);
xfs_biodone(bp);
xfs_buf_ioend(bp, 0);
}
/*

View file

@ -2042,7 +2042,7 @@ xfs_da_do_buf(
mappedbno, nmapped, 0, &bp);
break;
case 3:
xfs_baread(mp->m_ddev_targp, mappedbno, nmapped);
xfs_buf_readahead(mp->m_ddev_targp, mappedbno, nmapped);
error = 0;
bp = NULL;
break;

View file

@ -49,8 +49,9 @@ typedef struct xfs_dinode {
__be32 di_uid; /* owner's user id */
__be32 di_gid; /* owner's group id */
__be32 di_nlink; /* number of links to file */
__be16 di_projid; /* owner's project id */
__u8 di_pad[8]; /* unused, zeroed space */
__be16 di_projid_lo; /* lower part of owner's project id */
__be16 di_projid_hi; /* higher part owner's project id */
__u8 di_pad[6]; /* unused, zeroed space */
__be16 di_flushiter; /* incremented on flush */
xfs_timestamp_t di_atime; /* time last accessed */
xfs_timestamp_t di_mtime; /* time last modified */

View file

@ -961,7 +961,7 @@ xfs_dir2_leaf_getdents(
if (i > ra_current &&
map[ra_index].br_blockcount >=
mp->m_dirblkfsbs) {
xfs_baread(mp->m_ddev_targp,
xfs_buf_readahead(mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp,
map[ra_index].br_startblock +
ra_offset),

View file

@ -293,9 +293,11 @@ typedef struct xfs_bstat {
__s32 bs_extsize; /* extent size */
__s32 bs_extents; /* number of extents */
__u32 bs_gen; /* generation count */
__u16 bs_projid; /* project id */
__u16 bs_projid_lo; /* lower part of project id */
#define bs_projid bs_projid_lo /* (previously just bs_projid) */
__u16 bs_forkoff; /* inode fork offset in bytes */
unsigned char bs_pad[12]; /* pad space, unused */
__u16 bs_projid_hi; /* higher part of project id */
unsigned char bs_pad[10]; /* pad space, unused */
__u32 bs_dmevmask; /* DMIG event mask */
__u16 bs_dmstate; /* DMIG state info */
__u16 bs_aextents; /* attribute number of extents */
@ -448,6 +450,7 @@ typedef struct xfs_handle {
/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */
/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */
#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap)
#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64)
/*
* ioctl commands that replace IRIX syssgi()'s

View file

@ -144,12 +144,11 @@ xfs_growfs_data_private(
if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
return error;
dpct = pct - mp->m_sb.sb_imax_pct;
error = xfs_read_buf(mp, mp->m_ddev_targp,
XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
XFS_FSS_TO_BB(mp, 1), 0, &bp);
if (error)
return error;
ASSERT(bp);
bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp,
XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
BBTOB(XFS_FSS_TO_BB(mp, 1)), 0);
if (!bp)
return EIO;
xfs_buf_relse(bp);
new = nb; /* use new as a temporary here */
@ -597,7 +596,8 @@ xfs_reserve_blocks(
* the extra reserve blocks from the reserve.....
*/
int error;
error = xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, fdblks_delta, 0);
error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
fdblks_delta, 0);
if (error == ENOSPC)
goto retry;
}

View file

@ -212,7 +212,7 @@ xfs_ialloc_inode_init(
* to log a whole cluster of inodes instead of all the
* individual transactions causing a lot of log traffic.
*/
xfs_biozero(fbuf, 0, ninodes << mp->m_sb.sb_inodelog);
xfs_buf_zero(fbuf, 0, ninodes << mp->m_sb.sb_inodelog);
for (i = 0; i < ninodes; i++) {
int ioffset = i << mp->m_sb.sb_inodelog;
uint isize = sizeof(struct xfs_dinode);

View file

@ -183,38 +183,6 @@ xfs_inobt_key_diff(
cur->bc_rec.i.ir_startino;
}
STATIC int
xfs_inobt_kill_root(
struct xfs_btree_cur *cur,
struct xfs_buf *bp,
int level,
union xfs_btree_ptr *newroot)
{
int error;
XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
XFS_BTREE_STATS_INC(cur, killroot);
/*
* Update the root pointer, decreasing the level by 1 and then
* free the old root.
*/
xfs_inobt_set_root(cur, newroot, -1);
error = xfs_inobt_free_block(cur, bp);
if (error) {
XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
XFS_BTREE_STATS_INC(cur, free);
cur->bc_bufs[level] = NULL;
cur->bc_nlevels--;
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
}
#ifdef DEBUG
STATIC int
xfs_inobt_keys_inorder(
@ -309,7 +277,6 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
.dup_cursor = xfs_inobt_dup_cursor,
.set_root = xfs_inobt_set_root,
.kill_root = xfs_inobt_kill_root,
.alloc_block = xfs_inobt_alloc_block,
.free_block = xfs_inobt_free_block,
.get_minrecs = xfs_inobt_get_minrecs,

View file

@ -365,8 +365,8 @@ xfs_iget(
xfs_perag_t *pag;
xfs_agino_t agino;
/* the radix tree exists only in inode capable AGs */
if (XFS_INO_TO_AGNO(mp, ino) >= mp->m_maxagi)
/* reject inode numbers outside existing AGs */
if (XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount)
return EINVAL;
/* get the perag structure and ensure that it's inode capable */

View file

@ -660,7 +660,8 @@ xfs_dinode_from_disk(
to->di_uid = be32_to_cpu(from->di_uid);
to->di_gid = be32_to_cpu(from->di_gid);
to->di_nlink = be32_to_cpu(from->di_nlink);
to->di_projid = be16_to_cpu(from->di_projid);
to->di_projid_lo = be16_to_cpu(from->di_projid_lo);
to->di_projid_hi = be16_to_cpu(from->di_projid_hi);
memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
to->di_flushiter = be16_to_cpu(from->di_flushiter);
to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec);
@ -695,7 +696,8 @@ xfs_dinode_to_disk(
to->di_uid = cpu_to_be32(from->di_uid);
to->di_gid = cpu_to_be32(from->di_gid);
to->di_nlink = cpu_to_be32(from->di_nlink);
to->di_projid = cpu_to_be16(from->di_projid);
to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
to->di_flushiter = cpu_to_be16(from->di_flushiter);
to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec);
@ -874,7 +876,7 @@ xfs_iread(
if (ip->i_d.di_version == 1) {
ip->i_d.di_nlink = ip->i_d.di_onlink;
ip->i_d.di_onlink = 0;
ip->i_d.di_projid = 0;
xfs_set_projid(ip, 0);
}
ip->i_delayed_blks = 0;
@ -982,8 +984,7 @@ xfs_ialloc(
mode_t mode,
xfs_nlink_t nlink,
xfs_dev_t rdev,
cred_t *cr,
xfs_prid_t prid,
prid_t prid,
int okalloc,
xfs_buf_t **ialloc_context,
boolean_t *call_again,
@ -1027,7 +1028,7 @@ xfs_ialloc(
ASSERT(ip->i_d.di_nlink == nlink);
ip->i_d.di_uid = current_fsuid();
ip->i_d.di_gid = current_fsgid();
ip->i_d.di_projid = prid;
xfs_set_projid(ip, prid);
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
/*
@ -2725,7 +2726,7 @@ xfs_iflush_cluster(
XFS_BUF_UNDONE(bp);
XFS_BUF_STALE(bp);
XFS_BUF_ERROR(bp,EIO);
xfs_biodone(bp);
xfs_buf_ioend(bp, 0);
} else {
XFS_BUF_STALE(bp);
xfs_buf_relse(bp);
@ -3008,7 +3009,7 @@ xfs_iflush_int(
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
memset(&(dip->di_pad[0]), 0,
sizeof(dip->di_pad));
ASSERT(ip->i_d.di_projid == 0);
ASSERT(xfs_get_projid(ip) == 0);
}
}

View file

@ -134,8 +134,9 @@ typedef struct xfs_icdinode {
__uint32_t di_uid; /* owner's user id */
__uint32_t di_gid; /* owner's group id */
__uint32_t di_nlink; /* number of links to file */
__uint16_t di_projid; /* owner's project id */
__uint8_t di_pad[8]; /* unused, zeroed space */
__uint16_t di_projid_lo; /* lower part of owner's project id */
__uint16_t di_projid_hi; /* higher part of owner's project id */
__uint8_t di_pad[6]; /* unused, zeroed space */
__uint16_t di_flushiter; /* incremented on flush */
xfs_ictimestamp_t di_atime; /* time last accessed */
xfs_ictimestamp_t di_mtime; /* time last modified */
@ -212,7 +213,6 @@ typedef struct xfs_icdinode {
#ifdef __KERNEL__
struct bhv_desc;
struct cred;
struct xfs_buf;
struct xfs_bmap_free;
struct xfs_bmbt_irec;
@ -334,6 +334,25 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags)
return ret;
}
/*
* Project quota id helpers (previously projid was 16bit only
* and using two 16bit values to hold new 32bit projid was choosen
* to retain compatibility with "old" filesystems).
*/
static inline prid_t
xfs_get_projid(struct xfs_inode *ip)
{
return (prid_t)ip->i_d.di_projid_hi << 16 | ip->i_d.di_projid_lo;
}
static inline void
xfs_set_projid(struct xfs_inode *ip,
prid_t projid)
{
ip->i_d.di_projid_hi = (__uint16_t) (projid >> 16);
ip->i_d.di_projid_lo = (__uint16_t) (projid & 0xffff);
}
/*
* Manage the i_flush queue embedded in the inode. This completion
* queue synchronizes processes attempting to flush the in-core
@ -456,8 +475,8 @@ void xfs_inode_free(struct xfs_inode *ip);
* xfs_inode.c prototypes.
*/
int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t,
xfs_nlink_t, xfs_dev_t, cred_t *, xfs_prid_t,
int, struct xfs_buf **, boolean_t *, xfs_inode_t **);
xfs_nlink_t, xfs_dev_t, prid_t, int,
struct xfs_buf **, boolean_t *, xfs_inode_t **);
uint xfs_ip2xflags(struct xfs_inode *);
uint xfs_dic2xflags(struct xfs_dinode *);
@ -471,7 +490,6 @@ int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
void xfs_iext_realloc(xfs_inode_t *, int, int);
void xfs_iunpin_wait(xfs_inode_t *);
int xfs_iflush(xfs_inode_t *, uint);
void xfs_ichgtime(xfs_inode_t *, int);
void xfs_lock_inodes(xfs_inode_t **, int, uint);
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);

View file

@ -222,15 +222,6 @@ xfs_inode_item_format(
vecp++;
nvecs = 1;
/*
* Make sure the linux inode is dirty. We do this before
* clearing i_update_core as the VFS will call back into
* XFS here and set i_update_core, so we need to dirty the
* inode first so that the ordering of i_update_core and
* unlogged modifications still works as described below.
*/
xfs_mark_inode_dirty_sync(ip);
/*
* Clear i_update_core if the timestamps (or any other
* non-transactional modification) need flushing/logging

View file

@ -92,7 +92,8 @@ xfs_bulkstat_one_int(
* further change.
*/
buf->bs_nlink = dic->di_nlink;
buf->bs_projid = dic->di_projid;
buf->bs_projid_lo = dic->di_projid_lo;
buf->bs_projid_hi = dic->di_projid_hi;
buf->bs_ino = ino;
buf->bs_mode = dic->di_mode;
buf->bs_uid = dic->di_uid;

View file

@ -1118,7 +1118,8 @@ xlog_alloc_log(xfs_mount_t *mp,
iclog->ic_prev = prev_iclog;
prev_iclog = iclog;
bp = xfs_buf_get_noaddr(log->l_iclog_size, mp->m_logdev_targp);
bp = xfs_buf_get_uncached(mp->m_logdev_targp,
log->l_iclog_size, 0);
if (!bp)
goto out_free_iclog;
if (!XFS_BUF_CPSEMA(bp))
@ -1296,7 +1297,7 @@ xlog_bdstrat(
if (iclog->ic_state & XLOG_STATE_IOERROR) {
XFS_BUF_ERROR(bp, EIO);
XFS_BUF_STALE(bp);
xfs_biodone(bp);
xfs_buf_ioend(bp, 0);
/*
* It would seem logical to return EIO here, but we rely on
* the log state machine to propagate I/O errors instead of

View file

@ -145,102 +145,6 @@ xlog_cil_init_post_recovery(
log->l_curr_block);
}
/*
* Insert the log item into the CIL and calculate the difference in space
* consumed by the item. Add the space to the checkpoint ticket and calculate
* if the change requires additional log metadata. If it does, take that space
* as well. Remove the amount of space we addded to the checkpoint ticket from
* the current transaction ticket so that the accounting works out correctly.
*
* If this is the first time the item is being placed into the CIL in this
* context, pin it so it can't be written to disk until the CIL is flushed to
* the iclog and the iclog written to disk.
*/
static void
xlog_cil_insert(
struct log *log,
struct xlog_ticket *ticket,
struct xfs_log_item *item,
struct xfs_log_vec *lv)
{
struct xfs_cil *cil = log->l_cilp;
struct xfs_log_vec *old = lv->lv_item->li_lv;
struct xfs_cil_ctx *ctx = cil->xc_ctx;
int len;
int diff_iovecs;
int iclog_space;
if (old) {
/* existing lv on log item, space used is a delta */
ASSERT(!list_empty(&item->li_cil));
ASSERT(old->lv_buf && old->lv_buf_len && old->lv_niovecs);
len = lv->lv_buf_len - old->lv_buf_len;
diff_iovecs = lv->lv_niovecs - old->lv_niovecs;
kmem_free(old->lv_buf);
kmem_free(old);
} else {
/* new lv, must pin the log item */
ASSERT(!lv->lv_item->li_lv);
ASSERT(list_empty(&item->li_cil));
len = lv->lv_buf_len;
diff_iovecs = lv->lv_niovecs;
IOP_PIN(lv->lv_item);
}
len += diff_iovecs * sizeof(xlog_op_header_t);
/* attach new log vector to log item */
lv->lv_item->li_lv = lv;
spin_lock(&cil->xc_cil_lock);
list_move_tail(&item->li_cil, &cil->xc_cil);
ctx->nvecs += diff_iovecs;
/*
* If this is the first time the item is being committed to the CIL,
* store the sequence number on the log item so we can tell
* in future commits whether this is the first checkpoint the item is
* being committed into.
*/
if (!item->li_seq)
item->li_seq = ctx->sequence;
/*
* Now transfer enough transaction reservation to the context ticket
* for the checkpoint. The context ticket is special - the unit
* reservation has to grow as well as the current reservation as we
* steal from tickets so we can correctly determine the space used
* during the transaction commit.
*/
if (ctx->ticket->t_curr_res == 0) {
/* first commit in checkpoint, steal the header reservation */
ASSERT(ticket->t_curr_res >= ctx->ticket->t_unit_res + len);
ctx->ticket->t_curr_res = ctx->ticket->t_unit_res;
ticket->t_curr_res -= ctx->ticket->t_unit_res;
}
/* do we need space for more log record headers? */
iclog_space = log->l_iclog_size - log->l_iclog_hsize;
if (len > 0 && (ctx->space_used / iclog_space !=
(ctx->space_used + len) / iclog_space)) {
int hdrs;
hdrs = (len + iclog_space - 1) / iclog_space;
/* need to take into account split region headers, too */
hdrs *= log->l_iclog_hsize + sizeof(struct xlog_op_header);
ctx->ticket->t_unit_res += hdrs;
ctx->ticket->t_curr_res += hdrs;
ticket->t_curr_res -= hdrs;
ASSERT(ticket->t_curr_res >= len);
}
ticket->t_curr_res -= len;
ctx->space_used += len;
spin_unlock(&cil->xc_cil_lock);
}
/*
* Format log item into a flat buffers
*
@ -286,7 +190,7 @@ xlog_cil_format_items(
len += lv->lv_iovecp[index].i_len;
lv->lv_buf_len = len;
lv->lv_buf = kmem_zalloc(lv->lv_buf_len, KM_SLEEP|KM_NOFS);
lv->lv_buf = kmem_alloc(lv->lv_buf_len, KM_SLEEP|KM_NOFS);
ptr = lv->lv_buf;
for (index = 0; index < lv->lv_niovecs; index++) {
@ -300,21 +204,136 @@ xlog_cil_format_items(
}
}
/*
* Prepare the log item for insertion into the CIL. Calculate the difference in
* log space and vectors it will consume, and if it is a new item pin it as
* well.
*/
STATIC void
xfs_cil_prepare_item(
struct log *log,
struct xfs_log_vec *lv,
int *len,
int *diff_iovecs)
{
struct xfs_log_vec *old = lv->lv_item->li_lv;
if (old) {
/* existing lv on log item, space used is a delta */
ASSERT(!list_empty(&lv->lv_item->li_cil));
ASSERT(old->lv_buf && old->lv_buf_len && old->lv_niovecs);
*len += lv->lv_buf_len - old->lv_buf_len;
*diff_iovecs += lv->lv_niovecs - old->lv_niovecs;
kmem_free(old->lv_buf);
kmem_free(old);
} else {
/* new lv, must pin the log item */
ASSERT(!lv->lv_item->li_lv);
ASSERT(list_empty(&lv->lv_item->li_cil));
*len += lv->lv_buf_len;
*diff_iovecs += lv->lv_niovecs;
IOP_PIN(lv->lv_item);
}
/* attach new log vector to log item */
lv->lv_item->li_lv = lv;
/*
* If this is the first time the item is being committed to the
* CIL, store the sequence number on the log item so we can
* tell in future commits whether this is the first checkpoint
* the item is being committed into.
*/
if (!lv->lv_item->li_seq)
lv->lv_item->li_seq = log->l_cilp->xc_ctx->sequence;
}
/*
* Insert the log items into the CIL and calculate the difference in space
* consumed by the item. Add the space to the checkpoint ticket and calculate
* if the change requires additional log metadata. If it does, take that space
* as well. Remove the amount of space we addded to the checkpoint ticket from
* the current transaction ticket so that the accounting works out correctly.
*/
static void
xlog_cil_insert_items(
struct log *log,
struct xfs_log_vec *log_vector,
struct xlog_ticket *ticket,
xfs_lsn_t *start_lsn)
struct xlog_ticket *ticket)
{
struct xfs_log_vec *lv;
if (start_lsn)
*start_lsn = log->l_cilp->xc_ctx->sequence;
struct xfs_cil *cil = log->l_cilp;
struct xfs_cil_ctx *ctx = cil->xc_ctx;
struct xfs_log_vec *lv;
int len = 0;
int diff_iovecs = 0;
int iclog_space;
ASSERT(log_vector);
/*
* Do all the accounting aggregation and switching of log vectors
* around in a separate loop to the insertion of items into the CIL.
* Then we can do a separate loop to update the CIL within a single
* lock/unlock pair. This reduces the number of round trips on the CIL
* lock from O(nr_logvectors) to O(1) and greatly reduces the overall
* hold time for the transaction commit.
*
* If this is the first time the item is being placed into the CIL in
* this context, pin it so it can't be written to disk until the CIL is
* flushed to the iclog and the iclog written to disk.
*
* We can do this safely because the context can't checkpoint until we
* are done so it doesn't matter exactly how we update the CIL.
*/
for (lv = log_vector; lv; lv = lv->lv_next)
xlog_cil_insert(log, ticket, lv->lv_item, lv);
xfs_cil_prepare_item(log, lv, &len, &diff_iovecs);
/* account for space used by new iovec headers */
len += diff_iovecs * sizeof(xlog_op_header_t);
spin_lock(&cil->xc_cil_lock);
/* move the items to the tail of the CIL */
for (lv = log_vector; lv; lv = lv->lv_next)
list_move_tail(&lv->lv_item->li_cil, &cil->xc_cil);
ctx->nvecs += diff_iovecs;
/*
* Now transfer enough transaction reservation to the context ticket
* for the checkpoint. The context ticket is special - the unit
* reservation has to grow as well as the current reservation as we
* steal from tickets so we can correctly determine the space used
* during the transaction commit.
*/
if (ctx->ticket->t_curr_res == 0) {
/* first commit in checkpoint, steal the header reservation */
ASSERT(ticket->t_curr_res >= ctx->ticket->t_unit_res + len);
ctx->ticket->t_curr_res = ctx->ticket->t_unit_res;
ticket->t_curr_res -= ctx->ticket->t_unit_res;
}
/* do we need space for more log record headers? */
iclog_space = log->l_iclog_size - log->l_iclog_hsize;
if (len > 0 && (ctx->space_used / iclog_space !=
(ctx->space_used + len) / iclog_space)) {
int hdrs;
hdrs = (len + iclog_space - 1) / iclog_space;
/* need to take into account split region headers, too */
hdrs *= log->l_iclog_hsize + sizeof(struct xlog_op_header);
ctx->ticket->t_unit_res += hdrs;
ctx->ticket->t_curr_res += hdrs;
ticket->t_curr_res -= hdrs;
ASSERT(ticket->t_curr_res >= len);
}
ticket->t_curr_res -= len;
ctx->space_used += len;
spin_unlock(&cil->xc_cil_lock);
}
static void
@ -638,7 +657,10 @@ xfs_log_commit_cil(
/* lock out background commit */
down_read(&log->l_cilp->xc_ctx_lock);
xlog_cil_insert_items(log, log_vector, tp->t_ticket, commit_lsn);
if (commit_lsn)
*commit_lsn = log->l_cilp->xc_ctx->sequence;
xlog_cil_insert_items(log, log_vector, tp->t_ticket);
/* check we didn't blow the reservation */
if (tp->t_ticket->t_curr_res < 0)

View file

@ -107,7 +107,8 @@ xlog_get_bp(
nbblks += log->l_sectBBsize;
nbblks = round_up(nbblks, log->l_sectBBsize);
return xfs_buf_get_noaddr(BBTOB(nbblks), log->l_mp->m_logdev_targp);
return xfs_buf_get_uncached(log->l_mp->m_logdev_targp,
BBTOB(nbblks), 0);
}
STATIC void
@ -167,7 +168,7 @@ xlog_bread_noalign(
XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp);
xfsbdstrat(log->l_mp, bp);
error = xfs_iowait(bp);
error = xfs_buf_iowait(bp);
if (error)
xfs_ioerror_alert("xlog_bread", log->l_mp,
bp, XFS_BUF_ADDR(bp));
@ -321,12 +322,13 @@ xlog_recover_iodone(
* this during recovery. One strike!
*/
xfs_ioerror_alert("xlog_recover_iodone",
bp->b_mount, bp, XFS_BUF_ADDR(bp));
xfs_force_shutdown(bp->b_mount, SHUTDOWN_META_IO_ERROR);
bp->b_target->bt_mount, bp,
XFS_BUF_ADDR(bp));
xfs_force_shutdown(bp->b_target->bt_mount,
SHUTDOWN_META_IO_ERROR);
}
bp->b_mount = NULL;
XFS_BUF_CLR_IODONE_FUNC(bp);
xfs_biodone(bp);
xfs_buf_ioend(bp, 0);
}
/*
@ -2275,8 +2277,7 @@ xlog_recover_do_buffer_trans(
XFS_BUF_STALE(bp);
error = xfs_bwrite(mp, bp);
} else {
ASSERT(bp->b_mount == NULL || bp->b_mount == mp);
bp->b_mount = mp;
ASSERT(bp->b_target->bt_mount == mp);
XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone);
xfs_bdwrite(mp, bp);
}
@ -2540,8 +2541,7 @@ xlog_recover_do_inode_trans(
}
write_inode_buffer:
ASSERT(bp->b_mount == NULL || bp->b_mount == mp);
bp->b_mount = mp;
ASSERT(bp->b_target->bt_mount == mp);
XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone);
xfs_bdwrite(mp, bp);
error:
@ -2678,8 +2678,7 @@ xlog_recover_do_dquot_trans(
memcpy(ddq, recddq, item->ri_buf[1].i_len);
ASSERT(dq_f->qlf_size == 2);
ASSERT(bp->b_mount == NULL || bp->b_mount == mp);
bp->b_mount = mp;
ASSERT(bp->b_target->bt_mount == mp);
XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone);
xfs_bdwrite(mp, bp);
@ -3817,7 +3816,7 @@ xlog_do_recover(
XFS_BUF_READ(bp);
XFS_BUF_UNASYNC(bp);
xfsbdstrat(log->l_mp, bp);
error = xfs_iowait(bp);
error = xfs_buf_iowait(bp);
if (error) {
xfs_ioerror_alert("xlog_do_recover",
log->l_mp, bp, XFS_BUF_ADDR(bp));

View file

@ -52,16 +52,11 @@ STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t,
int);
STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t,
int);
STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,
int64_t, int);
STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
#else
#define xfs_icsb_balance_counter(mp, a, b) do { } while (0)
#define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0)
#define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0)
#endif
static const struct {
@ -199,6 +194,8 @@ xfs_uuid_unmount(
/*
* Reference counting access wrappers to the perag structures.
* Because we never free per-ag structures, the only thing we
* have to protect against changes is the tree structure itself.
*/
struct xfs_perag *
xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno)
@ -206,19 +203,43 @@ xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno)
struct xfs_perag *pag;
int ref = 0;
spin_lock(&mp->m_perag_lock);
rcu_read_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);
rcu_read_unlock();
trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
return pag;
}
/*
* search from @first to find the next perag with the given tag set.
*/
struct xfs_perag *
xfs_perag_get_tag(
struct xfs_mount *mp,
xfs_agnumber_t first,
int tag)
{
struct xfs_perag *pag;
int found;
int ref;
rcu_read_lock();
found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
(void **)&pag, first, 1, tag);
if (found <= 0) {
rcu_read_unlock();
return NULL;
}
ref = atomic_inc_return(&pag->pag_ref);
rcu_read_unlock();
trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
return pag;
}
void
xfs_perag_put(struct xfs_perag *pag)
{
@ -229,10 +250,18 @@ xfs_perag_put(struct xfs_perag *pag)
trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
}
STATIC void
__xfs_free_perag(
struct rcu_head *head)
{
struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
ASSERT(atomic_read(&pag->pag_ref) == 0);
kmem_free(pag);
}
/*
* Free up the resources associated with a mount structure. Assume that
* the structure was initially zeroed, so we can tell which fields got
* initialized.
* Free up the per-ag resources associated with the mount structure.
*/
STATIC void
xfs_free_perag(
@ -244,10 +273,9 @@ xfs_free_perag(
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
spin_lock(&mp->m_perag_lock);
pag = radix_tree_delete(&mp->m_perag_tree, agno);
ASSERT(pag);
ASSERT(atomic_read(&pag->pag_ref) == 0);
spin_unlock(&mp->m_perag_lock);
kmem_free(pag);
ASSERT(pag);
call_rcu(&pag->rcu_head, __xfs_free_perag);
}
}
@ -444,7 +472,10 @@ xfs_initialize_perag(
pag->pag_agno = index;
pag->pag_mount = mp;
rwlock_init(&pag->pag_ici_lock);
mutex_init(&pag->pag_ici_reclaim_lock);
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
spin_lock_init(&pag->pag_buf_lock);
pag->pag_buf_tree = RB_ROOT;
if (radix_tree_preload(GFP_NOFS))
goto out_unwind;
@ -639,7 +670,6 @@ int
xfs_readsb(xfs_mount_t *mp, int flags)
{
unsigned int sector_size;
unsigned int extra_flags;
xfs_buf_t *bp;
int error;
@ -652,28 +682,24 @@ xfs_readsb(xfs_mount_t *mp, int flags)
* access to the superblock.
*/
sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
extra_flags = XBF_LOCK | XBF_FS_MANAGED | XBF_MAPPED;
bp = xfs_buf_read(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size),
extra_flags);
if (!bp || XFS_BUF_ISERROR(bp)) {
xfs_fs_mount_cmn_err(flags, "SB read failed");
error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
goto fail;
reread:
bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp,
XFS_SB_DADDR, sector_size, 0);
if (!bp) {
xfs_fs_mount_cmn_err(flags, "SB buffer read failed");
return EIO;
}
ASSERT(XFS_BUF_ISBUSY(bp));
ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
/*
* Initialize the mount structure from the superblock.
* But first do some basic consistency checking.
*/
xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags);
if (error) {
xfs_fs_mount_cmn_err(flags, "SB validate failed");
goto fail;
goto release_buf;
}
/*
@ -684,7 +710,7 @@ xfs_readsb(xfs_mount_t *mp, int flags)
"device supports only %u byte sectors (not %u)",
sector_size, mp->m_sb.sb_sectsize);
error = ENOSYS;
goto fail;
goto release_buf;
}
/*
@ -692,33 +718,20 @@ xfs_readsb(xfs_mount_t *mp, int flags)
* re-read the superblock so the buffer is correctly sized.
*/
if (sector_size < mp->m_sb.sb_sectsize) {
XFS_BUF_UNMANAGE(bp);
xfs_buf_relse(bp);
sector_size = mp->m_sb.sb_sectsize;
bp = xfs_buf_read(mp->m_ddev_targp, XFS_SB_DADDR,
BTOBB(sector_size), extra_flags);
if (!bp || XFS_BUF_ISERROR(bp)) {
xfs_fs_mount_cmn_err(flags, "SB re-read failed");
error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
goto fail;
}
ASSERT(XFS_BUF_ISBUSY(bp));
ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
goto reread;
}
/* Initialize per-cpu counters */
xfs_icsb_reinit_counters(mp);
mp->m_sb_bp = bp;
xfs_buf_relse(bp);
ASSERT(XFS_BUF_VALUSEMA(bp) > 0);
xfs_buf_unlock(bp);
return 0;
fail:
if (bp) {
XFS_BUF_UNMANAGE(bp);
xfs_buf_relse(bp);
}
release_buf:
xfs_buf_relse(bp);
return error;
}
@ -991,42 +1004,35 @@ xfs_check_sizes(xfs_mount_t *mp)
{
xfs_buf_t *bp;
xfs_daddr_t d;
int error;
d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {
cmn_err(CE_WARN, "XFS: size check 1 failed");
cmn_err(CE_WARN, "XFS: filesystem size mismatch detected");
return XFS_ERROR(EFBIG);
}
error = xfs_read_buf(mp, mp->m_ddev_targp,
d - XFS_FSS_TO_BB(mp, 1),
XFS_FSS_TO_BB(mp, 1), 0, &bp);
if (!error) {
xfs_buf_relse(bp);
} else {
cmn_err(CE_WARN, "XFS: size check 2 failed");
if (error == ENOSPC)
error = XFS_ERROR(EFBIG);
return error;
bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp,
d - XFS_FSS_TO_BB(mp, 1),
BBTOB(XFS_FSS_TO_BB(mp, 1)), 0);
if (!bp) {
cmn_err(CE_WARN, "XFS: last sector read failed");
return EIO;
}
xfs_buf_relse(bp);
if (mp->m_logdev_targp != mp->m_ddev_targp) {
d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
cmn_err(CE_WARN, "XFS: size check 3 failed");
cmn_err(CE_WARN, "XFS: log size mismatch detected");
return XFS_ERROR(EFBIG);
}
error = xfs_read_buf(mp, mp->m_logdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_BB(mp, 1), 0, &bp);
if (!error) {
xfs_buf_relse(bp);
} else {
cmn_err(CE_WARN, "XFS: size check 3 failed");
if (error == ENOSPC)
error = XFS_ERROR(EFBIG);
return error;
bp = xfs_buf_read_uncached(mp, mp->m_logdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_B(mp, 1), 0);
if (!bp) {
cmn_err(CE_WARN, "XFS: log device read failed");
return EIO;
}
xfs_buf_relse(bp);
}
return 0;
}
@ -1601,7 +1607,7 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
XFS_BUF_UNASYNC(sbp);
ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp);
xfsbdstrat(mp, sbp);
error = xfs_iowait(sbp);
error = xfs_buf_iowait(sbp);
if (error)
xfs_ioerror_alert("xfs_unmountfs_writesb",
mp, sbp, XFS_BUF_ADDR(sbp));
@ -1832,135 +1838,72 @@ xfs_mod_incore_sb_unlocked(
*/
int
xfs_mod_incore_sb(
xfs_mount_t *mp,
xfs_sb_field_t field,
int64_t delta,
int rsvd)
struct xfs_mount *mp,
xfs_sb_field_t field,
int64_t delta,
int rsvd)
{
int status;
int status;
/* check for per-cpu counters */
switch (field) {
#ifdef HAVE_PERCPU_SB
case XFS_SBS_ICOUNT:
case XFS_SBS_IFREE:
case XFS_SBS_FDBLOCKS:
if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
status = xfs_icsb_modify_counters(mp, field,
delta, rsvd);
break;
}
/* FALLTHROUGH */
ASSERT(field < XFS_SBS_ICOUNT || field > XFS_SBS_FDBLOCKS);
#endif
default:
spin_lock(&mp->m_sb_lock);
status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
spin_unlock(&mp->m_sb_lock);
break;
}
spin_lock(&mp->m_sb_lock);
status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
spin_unlock(&mp->m_sb_lock);
return status;
}
/*
* xfs_mod_incore_sb_batch() is used to change more than one field
* in the in-core superblock structure at a time. This modification
* is protected by a lock internal to this module. The fields and
* changes to those fields are specified in the array of xfs_mod_sb
* structures passed in.
* Change more than one field in the in-core superblock structure at a time.
*
* Either all of the specified deltas will be applied or none of
* them will. If any modified field dips below 0, then all modifications
* will be backed out and EINVAL will be returned.
* The fields and changes to those fields are specified in the array of
* xfs_mod_sb structures passed in. Either all of the specified deltas
* will be applied or none of them will. If any modified field dips below 0,
* then all modifications will be backed out and EINVAL will be returned.
*
* Note that this function may not be used for the superblock values that
* are tracked with the in-memory per-cpu counters - a direct call to
* xfs_icsb_modify_counters is required for these.
*/
int
xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd)
xfs_mod_incore_sb_batch(
struct xfs_mount *mp,
xfs_mod_sb_t *msb,
uint nmsb,
int rsvd)
{
int status=0;
xfs_mod_sb_t *msbp;
xfs_mod_sb_t *msbp = &msb[0];
int error = 0;
/*
* Loop through the array of mod structures and apply each
* individually. If any fail, then back out all those
* which have already been applied. Do all of this within
* the scope of the m_sb_lock so that all of the changes will
* be atomic.
* Loop through the array of mod structures and apply each individually.
* If any fail, then back out all those which have already been applied.
* Do all of this within the scope of the m_sb_lock so that all of the
* changes will be atomic.
*/
spin_lock(&mp->m_sb_lock);
msbp = &msb[0];
for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) {
/*
* Apply the delta at index n. If it fails, break
* from the loop so we'll fall into the undo loop
* below.
*/
switch (msbp->msb_field) {
#ifdef HAVE_PERCPU_SB
case XFS_SBS_ICOUNT:
case XFS_SBS_IFREE:
case XFS_SBS_FDBLOCKS:
if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
spin_unlock(&mp->m_sb_lock);
status = xfs_icsb_modify_counters(mp,
msbp->msb_field,
msbp->msb_delta, rsvd);
spin_lock(&mp->m_sb_lock);
break;
}
/* FALLTHROUGH */
#endif
default:
status = xfs_mod_incore_sb_unlocked(mp,
msbp->msb_field,
msbp->msb_delta, rsvd);
break;
}
ASSERT(msbp->msb_field < XFS_SBS_ICOUNT ||
msbp->msb_field > XFS_SBS_FDBLOCKS);
if (status != 0) {
break;
}
}
/*
* If we didn't complete the loop above, then back out
* any changes made to the superblock. If you add code
* between the loop above and here, make sure that you
* preserve the value of status. Loop back until
* we step below the beginning of the array. Make sure
* we don't touch anything back there.
*/
if (status != 0) {
msbp--;
while (msbp >= msb) {
switch (msbp->msb_field) {
#ifdef HAVE_PERCPU_SB
case XFS_SBS_ICOUNT:
case XFS_SBS_IFREE:
case XFS_SBS_FDBLOCKS:
if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
spin_unlock(&mp->m_sb_lock);
status = xfs_icsb_modify_counters(mp,
msbp->msb_field,
-(msbp->msb_delta),
rsvd);
spin_lock(&mp->m_sb_lock);
break;
}
/* FALLTHROUGH */
#endif
default:
status = xfs_mod_incore_sb_unlocked(mp,
msbp->msb_field,
-(msbp->msb_delta),
rsvd);
break;
}
ASSERT(status == 0);
msbp--;
}
error = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field,
msbp->msb_delta, rsvd);
if (error)
goto unwind;
}
spin_unlock(&mp->m_sb_lock);
return status;
return 0;
unwind:
while (--msbp >= msb) {
error = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field,
-msbp->msb_delta, rsvd);
ASSERT(error == 0);
}
spin_unlock(&mp->m_sb_lock);
return error;
}
/*
@ -1998,18 +1941,13 @@ xfs_getsb(
*/
void
xfs_freesb(
xfs_mount_t *mp)
struct xfs_mount *mp)
{
xfs_buf_t *bp;
struct xfs_buf *bp = mp->m_sb_bp;
/*
* Use xfs_getsb() so that the buffer will be locked
* when we call xfs_buf_relse().
*/
bp = xfs_getsb(mp, 0);
XFS_BUF_UNMANAGE(bp);
xfs_buf_relse(bp);
xfs_buf_lock(bp);
mp->m_sb_bp = NULL;
xfs_buf_relse(bp);
}
/*
@ -2496,7 +2434,7 @@ xfs_icsb_balance_counter(
spin_unlock(&mp->m_sb_lock);
}
STATIC int
int
xfs_icsb_modify_counters(
xfs_mount_t *mp,
xfs_sb_field_t field,

View file

@ -53,7 +53,6 @@ typedef struct xfs_trans_reservations {
#include "xfs_sync.h"
struct cred;
struct log;
struct xfs_mount_args;
struct xfs_inode;
@ -91,6 +90,8 @@ extern void xfs_icsb_reinit_counters(struct xfs_mount *);
extern void xfs_icsb_destroy_counters(struct xfs_mount *);
extern void xfs_icsb_sync_counters(struct xfs_mount *, int);
extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int);
extern int xfs_icsb_modify_counters(struct xfs_mount *, xfs_sb_field_t,
int64_t, int);
#else
#define xfs_icsb_init_counters(mp) (0)
@ -98,6 +99,8 @@ extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int);
#define xfs_icsb_reinit_counters(mp) do { } while (0)
#define xfs_icsb_sync_counters(mp, flags) do { } while (0)
#define xfs_icsb_sync_counters_locked(mp, flags) do { } while (0)
#define xfs_icsb_modify_counters(mp, field, delta, rsvd) \
xfs_mod_incore_sb(mp, field, delta, rsvd)
#endif
typedef struct xfs_mount {
@ -232,8 +235,6 @@ typedef struct xfs_mount {
#define XFS_MOUNT_DIRSYNC (1ULL << 21) /* synchronous directory ops */
#define XFS_MOUNT_COMPAT_IOSIZE (1ULL << 22) /* don't report large preferred
* I/O size in stat() */
#define XFS_MOUNT_NO_PERCPU_SB (1ULL << 23) /* don't use per-cpu superblock
counters */
#define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams
allocator */
#define XFS_MOUNT_NOATTR2 (1ULL << 25) /* disable use of attr2 format */
@ -327,6 +328,8 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
* perag get/put wrappers for ref counting
*/
struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *mp, xfs_agnumber_t agno,
int tag);
void xfs_perag_put(struct xfs_perag *pag);
/*

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __XFS_REFCACHE_H__
#define __XFS_REFCACHE_H__
#ifdef HAVE_REFCACHE
/*
* Maximum size (in inodes) for the NFS reference cache
*/
#define XFS_REFCACHE_SIZE_MAX 512
struct xfs_inode;
struct xfs_mount;
extern void xfs_refcache_insert(struct xfs_inode *);
extern void xfs_refcache_purge_ip(struct xfs_inode *);
extern void xfs_refcache_purge_mp(struct xfs_mount *);
extern void xfs_refcache_purge_some(struct xfs_mount *);
extern void xfs_refcache_resize(int);
extern void xfs_refcache_destroy(void);
extern void xfs_refcache_iunlock(struct xfs_inode *, uint);
#else
#define xfs_refcache_insert(ip) do { } while (0)
#define xfs_refcache_purge_ip(ip) do { } while (0)
#define xfs_refcache_purge_mp(mp) do { } while (0)
#define xfs_refcache_purge_some(mp) do { } while (0)
#define xfs_refcache_resize(size) do { } while (0)
#define xfs_refcache_destroy() do { } while (0)
#define xfs_refcache_iunlock(ip, flags) xfs_iunlock(ip, flags)
#endif
#endif /* __XFS_REFCACHE_H__ */

View file

@ -183,7 +183,7 @@ xfs_rename(
* tree quota mechanism would be circumvented.
*/
if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
(target_dp->i_d.di_projid != src_ip->i_d.di_projid))) {
(xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) {
error = XFS_ERROR(EXDEV);
goto error_return;
}
@ -211,7 +211,9 @@ xfs_rename(
goto error_return;
if (error)
goto abort_return;
xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, target_dp,
XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
if (new_parent && src_is_directory) {
error = xfs_bumplink(tp, target_dp);
@ -249,7 +251,9 @@ xfs_rename(
&first_block, &free_list, spaceres);
if (error)
goto abort_return;
xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, target_dp,
XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
/*
* Decrement the link count on the target since the target
@ -292,7 +296,7 @@ xfs_rename(
* inode isn't really being changed, but old unix file systems did
* it and some incremental backup programs won't work without it.
*/
xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG);
/*
* Adjust the link count on src_dp. This is necessary when
@ -315,7 +319,7 @@ xfs_rename(
if (error)
goto abort_return;
xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
if (new_parent)
xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);

View file

@ -39,6 +39,7 @@
#include "xfs_trans_space.h"
#include "xfs_utils.h"
#include "xfs_trace.h"
#include "xfs_buf.h"
/*
@ -1883,13 +1884,13 @@ xfs_growfs_rt(
/*
* Read in the last block of the device, make sure it exists.
*/
error = xfs_read_buf(mp, mp->m_rtdev_targp,
XFS_FSB_TO_BB(mp, nrblocks - 1),
XFS_FSB_TO_BB(mp, 1), 0, &bp);
if (error)
return error;
ASSERT(bp);
bp = xfs_buf_read_uncached(mp, mp->m_rtdev_targp,
XFS_FSB_TO_BB(mp, nrblocks - 1),
XFS_FSB_TO_B(mp, 1), 0);
if (!bp)
return EIO;
xfs_buf_relse(bp);
/*
* Calculate new parameters. These are the final values to be reached.
*/
@ -2215,7 +2216,6 @@ xfs_rtmount_init(
{
xfs_buf_t *bp; /* buffer for last block of subvolume */
xfs_daddr_t d; /* address of last block of subvolume */
int error; /* error return value */
xfs_sb_t *sbp; /* filesystem superblock copy in mount */
sbp = &mp->m_sb;
@ -2242,15 +2242,12 @@ xfs_rtmount_init(
(unsigned long long) mp->m_sb.sb_rblocks);
return XFS_ERROR(EFBIG);
}
error = xfs_read_buf(mp, mp->m_rtdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_BB(mp, 1), 0, &bp);
if (error) {
cmn_err(CE_WARN,
"XFS: realtime mount -- xfs_read_buf failed, returned %d", error);
if (error == ENOSPC)
return XFS_ERROR(EFBIG);
return error;
bp = xfs_buf_read_uncached(mp, mp->m_rtdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
XFS_FSB_TO_B(mp, 1), 0);
if (!bp) {
cmn_err(CE_WARN, "XFS: realtime device size check failed");
return EIO;
}
xfs_buf_relse(bp);
return 0;

View file

@ -80,10 +80,12 @@ struct xfs_mount;
#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */
#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */
#define XFS_SB_VERSION2_OKREALFBITS \
(XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
XFS_SB_VERSION2_ATTR2BIT)
XFS_SB_VERSION2_ATTR2BIT | \
XFS_SB_VERSION2_PROJID32BIT)
#define XFS_SB_VERSION2_OKSASHFBITS \
(0)
#define XFS_SB_VERSION2_OKREALBITS \
@ -495,6 +497,12 @@ static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp)
sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT;
}
static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
{
return xfs_sb_version_hasmorebits(sbp) &&
(sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT);
}
/*
* end of superblock version macros
*/

View file

@ -696,7 +696,7 @@ xfs_trans_reserve(
* fail if the count would go below zero.
*/
if (blocks > 0) {
error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
error = xfs_icsb_modify_counters(tp->t_mountp, XFS_SBS_FDBLOCKS,
-((int64_t)blocks), rsvd);
if (error != 0) {
current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
@ -767,7 +767,7 @@ xfs_trans_reserve(
undo_blocks:
if (blocks > 0) {
(void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
xfs_icsb_modify_counters(tp->t_mountp, XFS_SBS_FDBLOCKS,
(int64_t)blocks, rsvd);
tp->t_blk_res = 0;
}
@ -1009,7 +1009,7 @@ void
xfs_trans_unreserve_and_mod_sb(
xfs_trans_t *tp)
{
xfs_mod_sb_t msb[14]; /* If you add cases, add entries */
xfs_mod_sb_t msb[9]; /* If you add cases, add entries */
xfs_mod_sb_t *msbp;
xfs_mount_t *mp = tp->t_mountp;
/* REFERENCED */
@ -1017,55 +1017,61 @@ xfs_trans_unreserve_and_mod_sb(
int rsvd;
int64_t blkdelta = 0;
int64_t rtxdelta = 0;
int64_t idelta = 0;
int64_t ifreedelta = 0;
msbp = msb;
rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
/* calculate free blocks delta */
/* calculate deltas */
if (tp->t_blk_res > 0)
blkdelta = tp->t_blk_res;
if ((tp->t_fdblocks_delta != 0) &&
(xfs_sb_version_haslazysbcount(&mp->m_sb) ||
(tp->t_flags & XFS_TRANS_SB_DIRTY)))
blkdelta += tp->t_fdblocks_delta;
if (blkdelta != 0) {
msbp->msb_field = XFS_SBS_FDBLOCKS;
msbp->msb_delta = blkdelta;
msbp++;
}
/* calculate free realtime extents delta */
if (tp->t_rtx_res > 0)
rtxdelta = tp->t_rtx_res;
if ((tp->t_frextents_delta != 0) &&
(tp->t_flags & XFS_TRANS_SB_DIRTY))
rtxdelta += tp->t_frextents_delta;
if (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
(tp->t_flags & XFS_TRANS_SB_DIRTY)) {
idelta = tp->t_icount_delta;
ifreedelta = tp->t_ifree_delta;
}
/* apply the per-cpu counters */
if (blkdelta) {
error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
blkdelta, rsvd);
if (error)
goto out;
}
if (idelta) {
error = xfs_icsb_modify_counters(mp, XFS_SBS_ICOUNT,
idelta, rsvd);
if (error)
goto out_undo_fdblocks;
}
if (ifreedelta) {
error = xfs_icsb_modify_counters(mp, XFS_SBS_IFREE,
ifreedelta, rsvd);
if (error)
goto out_undo_icount;
}
/* apply remaining deltas */
if (rtxdelta != 0) {
msbp->msb_field = XFS_SBS_FREXTENTS;
msbp->msb_delta = rtxdelta;
msbp++;
}
/* apply remaining deltas */
if (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
(tp->t_flags & XFS_TRANS_SB_DIRTY)) {
if (tp->t_icount_delta != 0) {
msbp->msb_field = XFS_SBS_ICOUNT;
msbp->msb_delta = tp->t_icount_delta;
msbp++;
}
if (tp->t_ifree_delta != 0) {
msbp->msb_field = XFS_SBS_IFREE;
msbp->msb_delta = tp->t_ifree_delta;
msbp++;
}
}
if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
if (tp->t_dblocks_delta != 0) {
msbp->msb_field = XFS_SBS_DBLOCKS;
@ -1115,8 +1121,24 @@ xfs_trans_unreserve_and_mod_sb(
if (msbp > msb) {
error = xfs_mod_incore_sb_batch(tp->t_mountp, msb,
(uint)(msbp - msb), rsvd);
ASSERT(error == 0);
if (error)
goto out_undo_ifreecount;
}
return;
out_undo_ifreecount:
if (ifreedelta)
xfs_icsb_modify_counters(mp, XFS_SBS_IFREE, -ifreedelta, rsvd);
out_undo_icount:
if (idelta)
xfs_icsb_modify_counters(mp, XFS_SBS_ICOUNT, -idelta, rsvd);
out_undo_fdblocks:
if (blkdelta)
xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, -blkdelta, rsvd);
out:
ASSERT(error = 0);
return;
}
/*
@ -1389,15 +1411,12 @@ xfs_trans_item_committed(
*/
STATIC void
xfs_trans_committed(
struct xfs_trans *tp,
void *arg,
int abortflag)
{
struct xfs_trans *tp = arg;
struct xfs_log_item_desc *lidp, *next;
/* Call the transaction's completion callback if there is one. */
if (tp->t_callback != NULL)
tp->t_callback(tp, tp->t_callarg);
list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
xfs_trans_item_committed(lidp->lid_item, tp->t_lsn, abortflag);
xfs_trans_free_item_desc(lidp);
@ -1525,7 +1544,7 @@ xfs_trans_commit_iclog(
* running in simulation mode (the log is explicitly turned
* off).
*/
tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed;
tp->t_logcb.cb_func = xfs_trans_committed;
tp->t_logcb.cb_arg = tp;
/*

View file

@ -399,8 +399,6 @@ typedef struct xfs_trans {
* transaction. */
struct xfs_mount *t_mountp; /* ptr to fs mount struct */
struct xfs_dquot_acct *t_dqinfo; /* acctg info for dquots */
xfs_trans_callback_t t_callback; /* transaction callback */
void *t_callarg; /* callback arg */
unsigned int t_flags; /* misc flags */
int64_t t_icount_delta; /* superblock icount change */
int64_t t_ifree_delta; /* superblock ifree change */
@ -473,6 +471,7 @@ void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *,
xfs_ino_t , uint, uint, struct xfs_inode **);
void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
void xfs_trans_ijoin_ref(struct xfs_trans *, struct xfs_inode *, uint);
void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *);
void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);

View file

@ -336,7 +336,7 @@ xfs_trans_read_buf(
ASSERT(!XFS_BUF_ISASYNC(bp));
XFS_BUF_READ(bp);
xfsbdstrat(tp->t_mountp, bp);
error = xfs_iowait(bp);
error = xfs_buf_iowait(bp);
if (error) {
xfs_ioerror_alert("xfs_trans_read_buf", mp,
bp, blkno);

View file

@ -117,6 +117,36 @@ xfs_trans_ijoin_ref(
ip->i_itemp->ili_lock_flags = lock_flags;
}
/*
* Transactional inode timestamp update. Requires the inode to be locked and
* joined to the transaction supplied. Relies on the transaction subsystem to
* track dirty state and update/writeback the inode accordingly.
*/
void
xfs_trans_ichgtime(
struct xfs_trans *tp,
struct xfs_inode *ip,
int flags)
{
struct inode *inode = VFS_I(ip);
timespec_t tv;
ASSERT(tp);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(ip->i_transp == tp);
tv = current_fs_time(inode->i_sb);
if ((flags & XFS_ICHGTIME_MOD) &&
!timespec_equal(&inode->i_mtime, &tv)) {
inode->i_mtime = tv;
}
if ((flags & XFS_ICHGTIME_CHG) &&
!timespec_equal(&inode->i_ctime, &tv)) {
inode->i_ctime = tv;
}
}
/*
* This is called to mark the fields indicated in fieldmask as needing
* to be logged when the transaction is committed. The inode must

View file

@ -73,8 +73,6 @@ typedef __int32_t xfs_tid_t; /* transaction identifier */
typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */
typedef __uint16_t xfs_prid_t; /* prid_t truncated to 16bits in XFS */
typedef __uint32_t xlog_tid_t; /* transaction ID type */
/*

View file

@ -56,7 +56,6 @@ xfs_dir_ialloc(
mode_t mode,
xfs_nlink_t nlink,
xfs_dev_t rdev,
cred_t *credp,
prid_t prid, /* project id */
int okalloc, /* ok to allocate new space */
xfs_inode_t **ipp, /* pointer to inode; it will be
@ -93,7 +92,7 @@ xfs_dir_ialloc(
* transaction commit so that no other process can steal
* the inode(s) that we've just allocated.
*/
code = xfs_ialloc(tp, dp, mode, nlink, rdev, credp, prid, okalloc,
code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, okalloc,
&ialloc_context, &call_again, &ip);
/*
@ -197,7 +196,7 @@ xfs_dir_ialloc(
* other allocations in this allocation group,
* this call should always succeed.
*/
code = xfs_ialloc(tp, dp, mode, nlink, rdev, credp, prid,
code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid,
okalloc, &ialloc_context, &call_again, &ip);
/*
@ -235,7 +234,7 @@ xfs_droplink(
{
int error;
xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
ASSERT (ip->i_d.di_nlink > 0);
ip->i_d.di_nlink--;
@ -299,7 +298,7 @@ xfs_bumplink(
{
if (ip->i_d.di_nlink >= XFS_MAXLINK)
return XFS_ERROR(EMLINK);
xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
ASSERT(ip->i_d.di_nlink > 0);
ip->i_d.di_nlink++;

View file

@ -19,8 +19,7 @@
#define __XFS_UTILS_H__
extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t,
xfs_dev_t, cred_t *, prid_t, int,
xfs_inode_t **, int *);
xfs_dev_t, prid_t, int, xfs_inode_t **, int *);
extern int xfs_droplink(xfs_trans_t *, xfs_inode_t *);
extern int xfs_bumplink(xfs_trans_t *, xfs_inode_t *);
extern void xfs_bump_ino_vers2(xfs_trans_t *, xfs_inode_t *);

View file

@ -114,7 +114,7 @@ xfs_setattr(
*/
ASSERT(udqp == NULL);
ASSERT(gdqp == NULL);
code = xfs_qm_vop_dqalloc(ip, uid, gid, ip->i_d.di_projid,
code = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
qflags, &udqp, &gdqp);
if (code)
return code;
@ -184,8 +184,11 @@ xfs_setattr(
ip->i_size == 0 && ip->i_d.di_nextents == 0) {
xfs_iunlock(ip, XFS_ILOCK_EXCL);
lock_flags &= ~XFS_ILOCK_EXCL;
if (mask & ATTR_CTIME)
xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
if (mask & ATTR_CTIME) {
inode->i_mtime = inode->i_ctime =
current_fs_time(inode->i_sb);
xfs_mark_inode_dirty_sync(ip);
}
code = 0;
goto error_return;
}
@ -1253,8 +1256,7 @@ xfs_create(
struct xfs_name *name,
mode_t mode,
xfs_dev_t rdev,
xfs_inode_t **ipp,
cred_t *credp)
xfs_inode_t **ipp)
{
int is_dir = S_ISDIR(mode);
struct xfs_mount *mp = dp->i_mount;
@ -1266,7 +1268,7 @@ xfs_create(
boolean_t unlock_dp_on_error = B_FALSE;
uint cancel_flags;
int committed;
xfs_prid_t prid;
prid_t prid;
struct xfs_dquot *udqp = NULL;
struct xfs_dquot *gdqp = NULL;
uint resblks;
@ -1279,9 +1281,9 @@ xfs_create(
return XFS_ERROR(EIO);
if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
prid = dp->i_d.di_projid;
prid = xfs_get_projid(dp);
else
prid = dfltprid;
prid = XFS_PROJID_DEFAULT;
/*
* Make sure that we have allocated dquot(s) on disk.
@ -1360,7 +1362,7 @@ xfs_create(
* entry pointing to them, but a directory also the "." entry
* pointing to itself.
*/
error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, credp,
error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev,
prid, resblks > 0, &ip, &committed);
if (error) {
if (error == ENOSPC)
@ -1391,7 +1393,7 @@ xfs_create(
ASSERT(error != ENOSPC);
goto out_trans_abort;
}
xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
if (is_dir) {
@ -1742,7 +1744,7 @@ xfs_remove(
ASSERT(error != ENOENT);
goto out_bmap_cancel;
}
xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
if (is_dir) {
/*
@ -1880,7 +1882,7 @@ xfs_link(
* the tree quota mechanism could be circumvented.
*/
if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
(tdp->i_d.di_projid != sip->i_d.di_projid))) {
(xfs_get_projid(tdp) != xfs_get_projid(sip)))) {
error = XFS_ERROR(EXDEV);
goto error_return;
}
@ -1895,7 +1897,7 @@ xfs_link(
&first_block, &free_list, resblks);
if (error)
goto abort_return;
xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
error = xfs_bumplink(tp, sip);
@ -1933,8 +1935,7 @@ xfs_symlink(
struct xfs_name *link_name,
const char *target_path,
mode_t mode,
xfs_inode_t **ipp,
cred_t *credp)
xfs_inode_t **ipp)
{
xfs_mount_t *mp = dp->i_mount;
xfs_trans_t *tp;
@ -1955,7 +1956,7 @@ xfs_symlink(
int byte_cnt;
int n;
xfs_buf_t *bp;
xfs_prid_t prid;
prid_t prid;
struct xfs_dquot *udqp, *gdqp;
uint resblks;
@ -1978,9 +1979,9 @@ xfs_symlink(
udqp = gdqp = NULL;
if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
prid = dp->i_d.di_projid;
prid = xfs_get_projid(dp);
else
prid = (xfs_prid_t)dfltprid;
prid = XFS_PROJID_DEFAULT;
/*
* Make sure that we have allocated dquot(s) on disk.
@ -2046,8 +2047,8 @@ xfs_symlink(
/*
* Allocate an inode for the symlink.
*/
error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT),
1, 0, credp, prid, resblks > 0, &ip, NULL);
error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
prid, resblks > 0, &ip, NULL);
if (error) {
if (error == ENOSPC)
goto error_return;
@ -2129,7 +2130,7 @@ xfs_symlink(
&first_block, &free_list, resblks);
if (error)
goto error1;
xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
/*
@ -2272,7 +2273,7 @@ xfs_alloc_file_space(
count = len;
imapp = &imaps[0];
nimaps = 1;
bmapi_flag = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
bmapi_flag = XFS_BMAPI_WRITE | alloc_type;
startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
allocatesize_fsb = XFS_B_TO_FSB(mp, count);
@ -2431,9 +2432,9 @@ xfs_zero_remaining_bytes(
if (endoff > ip->i_size)
endoff = ip->i_size;
bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize,
XFS_IS_REALTIME_INODE(ip) ?
mp->m_rtdev_targp : mp->m_ddev_targp);
bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
mp->m_rtdev_targp : mp->m_ddev_targp,
mp->m_sb.sb_blocksize, XBF_DONT_BLOCK);
if (!bp)
return XFS_ERROR(ENOMEM);
@ -2459,7 +2460,7 @@ xfs_zero_remaining_bytes(
XFS_BUF_READ(bp);
XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock));
xfsbdstrat(mp, bp);
error = xfs_iowait(bp);
error = xfs_buf_iowait(bp);
if (error) {
xfs_ioerror_alert("xfs_zero_remaining_bytes(read)",
mp, bp, XFS_BUF_ADDR(bp));
@ -2472,7 +2473,7 @@ xfs_zero_remaining_bytes(
XFS_BUF_UNREAD(bp);
XFS_BUF_WRITE(bp);
xfsbdstrat(mp, bp);
error = xfs_iowait(bp);
error = xfs_buf_iowait(bp);
if (error) {
xfs_ioerror_alert("xfs_zero_remaining_bytes(write)",
mp, bp, XFS_BUF_ADDR(bp));
@ -2711,6 +2712,7 @@ xfs_change_file_space(
xfs_off_t llen;
xfs_trans_t *tp;
struct iattr iattr;
int prealloc_type;
if (!S_ISREG(ip->i_d.di_mode))
return XFS_ERROR(EINVAL);
@ -2753,12 +2755,17 @@ xfs_change_file_space(
* size to be changed.
*/
setprealloc = clrprealloc = 0;
prealloc_type = XFS_BMAPI_PREALLOC;
switch (cmd) {
case XFS_IOC_ZERO_RANGE:
prealloc_type |= XFS_BMAPI_CONVERT;
xfs_tosspages(ip, startoffset, startoffset + bf->l_len, 0);
/* FALLTHRU */
case XFS_IOC_RESVSP:
case XFS_IOC_RESVSP64:
error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
1, attr_flags);
prealloc_type, attr_flags);
if (error)
return error;
setprealloc = 1;
@ -2827,7 +2834,7 @@ xfs_change_file_space(
if (ip->i_d.di_mode & S_IXGRP)
ip->i_d.di_mode &= ~S_ISGID;
xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
}
if (setprealloc)
ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;

View file

@ -2,7 +2,6 @@
#define _XFS_VNODEOPS_H 1
struct attrlist_cursor_kern;
struct cred;
struct file;
struct iattr;
struct inode;
@ -26,7 +25,7 @@ int xfs_inactive(struct xfs_inode *ip);
int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode **ipp, struct xfs_name *ci_name);
int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode,
xfs_dev_t rdev, struct xfs_inode **ipp, cred_t *credp);
xfs_dev_t rdev, struct xfs_inode **ipp);
int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode *ip);
int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
@ -34,8 +33,7 @@ int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize,
xfs_off_t *offset, filldir_t filldir);
int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
const char *target_path, mode_t mode, struct xfs_inode **ipp,
cred_t *credp);
const char *target_path, mode_t mode, struct xfs_inode **ipp);
int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state);
int xfs_change_file_space(struct xfs_inode *ip, int cmd,
xfs_flock64_t *bf, xfs_off_t offset, int attr_flags);