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

* 'for-linus' of git://oss.sgi.com/xfs/xfs: (184 commits)
  [XFS] Fix race in xfs_write() between direct and buffered I/O with DMAPI
  [XFS] handle unaligned data in xfs_bmbt_disk_get_all
  [XFS] avoid memory allocations in xfs_fs_vcmn_err
  [XFS] Fix speculative allocation beyond eof
  [XFS] Remove XFS_BUF_SHUT() and friends
  [XFS] Use the incore inode size in xfs_file_readdir()
  [XFS] set b_error from bio error in xfs_buf_bio_end_io
  [XFS] use inode_change_ok for setattr permission checking
  [XFS] add a FMODE flag to make XFS invisible I/O less hacky
  [XFS] resync headers with libxfs
  [XFS] simplify projid check in xfs_rename
  [XFS] replace b_fspriv with b_mount
  [XFS] Remove unused tracing code
  [XFS] Remove unnecessary assertion
  [XFS] Remove unused variable in ktrace_free()
  [XFS] Check return value of xfs_buf_get_noaddr()
  [XFS] Fix hang after disallowed rename across directory quota domains
  [XFS] Fix compile with CONFIG_COMPAT enabled
  move inode tracing out of xfs_vnode.
  move vn_iowait / vn_iowake into xfs_aops.c
  ...
This commit is contained in:
Linus Torvalds 2008-12-30 17:48:25 -08:00
commit 6a94cb7306
112 changed files with 10586 additions and 12940 deletions

View File

@ -229,10 +229,6 @@ The following sysctls are available for the XFS filesystem:
ISGID bit is cleared if the irix_sgid_inherit compatibility sysctl
is set.
fs.xfs.restrict_chown (Min: 0 Default: 1 Max: 1)
Controls whether unprivileged users can use chown to "give away"
a file to another user.
fs.xfs.inherit_sync (Min: 0 Default: 1 Max: 1)
Setting this to "1" will cause the "sync" flag set
by the xfs_io(8) chattr command on a directory to be

View File

@ -108,83 +108,99 @@ static void wake_up_inode(struct inode *inode)
wake_up_bit(&inode->i_state, __I_LOCK);
}
static struct inode *alloc_inode(struct super_block *sb)
/**
* inode_init_always - perform inode structure intialisation
* @sb - superblock inode belongs to.
* @inode - inode to initialise
*
* These are initializations that need to be done on every inode
* allocation as the fields are not initialised by slab allocation.
*/
struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
{
static const struct address_space_operations empty_aops;
static struct inode_operations empty_iops;
static const struct file_operations empty_fops;
struct address_space * const mapping = &inode->i_data;
inode->i_sb = sb;
inode->i_blkbits = sb->s_blocksize_bits;
inode->i_flags = 0;
atomic_set(&inode->i_count, 1);
inode->i_op = &empty_iops;
inode->i_fop = &empty_fops;
inode->i_nlink = 1;
atomic_set(&inode->i_writecount, 0);
inode->i_size = 0;
inode->i_blocks = 0;
inode->i_bytes = 0;
inode->i_generation = 0;
#ifdef CONFIG_QUOTA
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
#endif
inode->i_pipe = NULL;
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_rdev = 0;
inode->dirtied_when = 0;
if (security_inode_alloc(inode)) {
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
kmem_cache_free(inode_cachep, (inode));
return NULL;
}
spin_lock_init(&inode->i_lock);
lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
mutex_init(&inode->i_mutex);
lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key);
init_rwsem(&inode->i_alloc_sem);
lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
mapping->a_ops = &empty_aops;
mapping->host = inode;
mapping->flags = 0;
mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE);
mapping->assoc_mapping = NULL;
mapping->backing_dev_info = &default_backing_dev_info;
mapping->writeback_index = 0;
/*
* If the block_device provides a backing_dev_info for client
* inodes then use that. Otherwise the inode share the bdev's
* backing_dev_info.
*/
if (sb->s_bdev) {
struct backing_dev_info *bdi;
bdi = sb->s_bdev->bd_inode_backing_dev_info;
if (!bdi)
bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
mapping->backing_dev_info = bdi;
}
inode->i_private = NULL;
inode->i_mapping = mapping;
return inode;
}
EXPORT_SYMBOL(inode_init_always);
static struct inode *alloc_inode(struct super_block *sb)
{
struct inode *inode;
if (sb->s_op->alloc_inode)
inode = sb->s_op->alloc_inode(sb);
else
inode = (struct inode *) kmem_cache_alloc(inode_cachep, GFP_KERNEL);
inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);
if (inode) {
struct address_space * const mapping = &inode->i_data;
inode->i_sb = sb;
inode->i_blkbits = sb->s_blocksize_bits;
inode->i_flags = 0;
atomic_set(&inode->i_count, 1);
inode->i_op = &empty_iops;
inode->i_fop = &empty_fops;
inode->i_nlink = 1;
atomic_set(&inode->i_writecount, 0);
inode->i_size = 0;
inode->i_blocks = 0;
inode->i_bytes = 0;
inode->i_generation = 0;
#ifdef CONFIG_QUOTA
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
#endif
inode->i_pipe = NULL;
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_rdev = 0;
inode->dirtied_when = 0;
if (security_inode_alloc(inode)) {
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
kmem_cache_free(inode_cachep, (inode));
return NULL;
}
spin_lock_init(&inode->i_lock);
lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
mutex_init(&inode->i_mutex);
lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key);
init_rwsem(&inode->i_alloc_sem);
lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
mapping->a_ops = &empty_aops;
mapping->host = inode;
mapping->flags = 0;
mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE);
mapping->assoc_mapping = NULL;
mapping->backing_dev_info = &default_backing_dev_info;
mapping->writeback_index = 0;
/*
* If the block_device provides a backing_dev_info for client
* inodes then use that. Otherwise the inode share the bdev's
* backing_dev_info.
*/
if (sb->s_bdev) {
struct backing_dev_info *bdi;
bdi = sb->s_bdev->bd_inode_backing_dev_info;
if (!bdi)
bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
mapping->backing_dev_info = bdi;
}
inode->i_private = NULL;
inode->i_mapping = mapping;
}
return inode;
if (inode)
return inode_init_always(sb, inode);
return NULL;
}
void destroy_inode(struct inode *inode)
@ -196,6 +212,7 @@ void destroy_inode(struct inode *inode)
else
kmem_cache_free(inode_cachep, (inode));
}
EXPORT_SYMBOL(destroy_inode);
/*
@ -534,6 +551,49 @@ repeat:
return node ? inode : NULL;
}
static unsigned long hash(struct super_block *sb, unsigned long hashval)
{
unsigned long tmp;
tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
L1_CACHE_BYTES;
tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
return tmp & I_HASHMASK;
}
static inline void
__inode_add_to_lists(struct super_block *sb, struct hlist_head *head,
struct inode *inode)
{
inodes_stat.nr_inodes++;
list_add(&inode->i_list, &inode_in_use);
list_add(&inode->i_sb_list, &sb->s_inodes);
if (head)
hlist_add_head(&inode->i_hash, head);
}
/**
* inode_add_to_lists - add a new inode to relevant lists
* @sb - superblock inode belongs to.
* @inode - inode to mark in use
*
* When an inode is allocated it needs to be accounted for, added to the in use
* list, the owning superblock and the inode hash. This needs to be done under
* the inode_lock, so export a function to do this rather than the inode lock
* itself. We calculate the hash list to add to here so it is all internal
* which requires the caller to have already set up the inode number in the
* inode to add.
*/
void inode_add_to_lists(struct super_block *sb, struct inode *inode)
{
struct hlist_head *head = inode_hashtable + hash(sb, inode->i_ino);
spin_lock(&inode_lock);
__inode_add_to_lists(sb, head, inode);
spin_unlock(&inode_lock);
}
EXPORT_SYMBOL_GPL(inode_add_to_lists);
/**
* new_inode - obtain an inode
* @sb: superblock
@ -561,9 +621,7 @@ struct inode *new_inode(struct super_block *sb)
inode = alloc_inode(sb);
if (inode) {
spin_lock(&inode_lock);
inodes_stat.nr_inodes++;
list_add(&inode->i_list, &inode_in_use);
list_add(&inode->i_sb_list, &sb->s_inodes);
__inode_add_to_lists(sb, NULL, inode);
inode->i_ino = ++last_ino;
inode->i_state = 0;
spin_unlock(&inode_lock);
@ -622,10 +680,7 @@ static struct inode * get_new_inode(struct super_block *sb, struct hlist_head *h
if (set(inode, data))
goto set_failed;
inodes_stat.nr_inodes++;
list_add(&inode->i_list, &inode_in_use);
list_add(&inode->i_sb_list, &sb->s_inodes);
hlist_add_head(&inode->i_hash, head);
__inode_add_to_lists(sb, head, inode);
inode->i_state = I_LOCK|I_NEW;
spin_unlock(&inode_lock);
@ -671,10 +726,7 @@ static struct inode * get_new_inode_fast(struct super_block *sb, struct hlist_he
old = find_inode_fast(sb, head, ino);
if (!old) {
inode->i_ino = ino;
inodes_stat.nr_inodes++;
list_add(&inode->i_list, &inode_in_use);
list_add(&inode->i_sb_list, &sb->s_inodes);
hlist_add_head(&inode->i_hash, head);
__inode_add_to_lists(sb, head, inode);
inode->i_state = I_LOCK|I_NEW;
spin_unlock(&inode_lock);
@ -698,16 +750,6 @@ static struct inode * get_new_inode_fast(struct super_block *sb, struct hlist_he
return inode;
}
static unsigned long hash(struct super_block *sb, unsigned long hashval)
{
unsigned long tmp;
tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
L1_CACHE_BYTES;
tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
return tmp & I_HASHMASK;
}
/**
* iunique - get a unique inode number
* @sb: superblock
@ -1292,6 +1334,7 @@ int inode_wait(void *word)
schedule();
return 0;
}
EXPORT_SYMBOL(inode_wait);
/*
* If we try to find an inode in the inode hash while it is being

View File

@ -85,13 +85,13 @@ xfs-y += xfs_alloc.o \
xfs_trans_inode.o \
xfs_trans_item.o \
xfs_utils.o \
xfs_vfsops.o \
xfs_vnodeops.o \
xfs_rw.o \
xfs_dmops.o \
xfs_qmops.o
xfs-$(CONFIG_XFS_TRACE) += xfs_dir2_trace.o
xfs-$(CONFIG_XFS_TRACE) += xfs_btree_trace.o \
xfs_dir2_trace.o
# Objects in linux/
xfs-y += $(addprefix $(XFS_LINUX)/, \
@ -106,7 +106,7 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \
xfs_iops.o \
xfs_lrw.o \
xfs_super.o \
xfs_vnode.o \
xfs_sync.o \
xfs_xattr.o)
# Objects in support/

View File

@ -32,23 +32,15 @@ typedef struct sv_s {
wait_queue_head_t waiters;
} sv_t;
#define SV_FIFO 0x0 /* sv_t is FIFO type */
#define SV_LIFO 0x2 /* sv_t is LIFO type */
#define SV_PRIO 0x4 /* sv_t is PRIO type */
#define SV_KEYED 0x6 /* sv_t is KEYED type */
#define SV_DEFAULT SV_FIFO
static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state,
unsigned long timeout)
static inline void _sv_wait(sv_t *sv, spinlock_t *lock)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue_exclusive(&sv->waiters, &wait);
__set_current_state(state);
__set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock(lock);
schedule_timeout(timeout);
schedule();
remove_wait_queue(&sv->waiters, &wait);
}
@ -58,13 +50,7 @@ static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state,
#define sv_destroy(sv) \
/*NOTHING*/
#define sv_wait(sv, pri, lock, s) \
_sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
#define sv_wait_sig(sv, pri, lock, s) \
_sv_wait(sv, lock, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
#define sv_timedwait(sv, pri, lock, s, svf, ts, rts) \
_sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, timespec_to_jiffies(ts))
#define sv_timedwait_sig(sv, pri, lock, s, svf, ts, rts) \
_sv_wait(sv, lock, TASK_INTERRUPTIBLE, timespec_to_jiffies(ts))
_sv_wait(sv, lock)
#define sv_signal(sv) \
wake_up(&(sv)->waiters)
#define sv_broadcast(sv) \

View File

@ -42,6 +42,40 @@
#include <linux/pagevec.h>
#include <linux/writeback.h>
/*
* Prime number of hash buckets since address is used as the key.
*/
#define NVSYNC 37
#define to_ioend_wq(v) (&xfs_ioend_wq[((unsigned long)v) % NVSYNC])
static wait_queue_head_t xfs_ioend_wq[NVSYNC];
void __init
xfs_ioend_init(void)
{
int i;
for (i = 0; i < NVSYNC; i++)
init_waitqueue_head(&xfs_ioend_wq[i]);
}
void
xfs_ioend_wait(
xfs_inode_t *ip)
{
wait_queue_head_t *wq = to_ioend_wq(ip);
wait_event(*wq, (atomic_read(&ip->i_iocount) == 0));
}
STATIC void
xfs_ioend_wake(
xfs_inode_t *ip)
{
if (atomic_dec_and_test(&ip->i_iocount))
wake_up(to_ioend_wq(ip));
}
STATIC void
xfs_count_page_state(
struct page *page,
@ -146,16 +180,25 @@ xfs_destroy_ioend(
xfs_ioend_t *ioend)
{
struct buffer_head *bh, *next;
struct xfs_inode *ip = XFS_I(ioend->io_inode);
for (bh = ioend->io_buffer_head; bh; bh = next) {
next = bh->b_private;
bh->b_end_io(bh, !ioend->io_error);
}
if (unlikely(ioend->io_error)) {
vn_ioerror(XFS_I(ioend->io_inode), ioend->io_error,
__FILE__,__LINE__);
/*
* Volume managers supporting multiple paths can send back ENODEV
* when the final path disappears. In this case continuing to fill
* the page cache with dirty data which cannot be written out is
* evil, so prevent that.
*/
if (unlikely(ioend->io_error == -ENODEV)) {
xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ,
__FILE__, __LINE__);
}
vn_iowake(XFS_I(ioend->io_inode));
xfs_ioend_wake(ip);
mempool_free(ioend, xfs_ioend_pool);
}
@ -191,7 +234,7 @@ xfs_setfilesize(
ip->i_d.di_size = isize;
ip->i_update_core = 1;
ip->i_update_size = 1;
mark_inode_dirty_sync(ioend->io_inode);
xfs_mark_inode_dirty_sync(ip);
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@ -317,14 +360,9 @@ xfs_map_blocks(
xfs_iomap_t *mapp,
int flags)
{
xfs_inode_t *ip = XFS_I(inode);
int error, nmaps = 1;
int nmaps = 1;
error = xfs_iomap(ip, offset, count,
flags, mapp, &nmaps);
if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)))
xfs_iflags_set(ip, XFS_IMODIFIED);
return -error;
return -xfs_iomap(XFS_I(inode), offset, count, flags, mapp, &nmaps);
}
STATIC_INLINE int
@ -512,7 +550,7 @@ xfs_cancel_ioend(
unlock_buffer(bh);
} while ((bh = next_bh) != NULL);
vn_iowake(XFS_I(ioend->io_inode));
xfs_ioend_wake(XFS_I(ioend->io_inode));
mempool_free(ioend, xfs_ioend_pool);
} while ((ioend = next) != NULL);
}

View File

@ -43,4 +43,7 @@ typedef struct xfs_ioend {
extern const struct address_space_operations xfs_address_space_operations;
extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
extern void xfs_ioend_init(void);
extern void xfs_ioend_wait(struct xfs_inode *);
#endif /* __XFS_AOPS_H__ */

View File

@ -630,6 +630,29 @@ xfs_buf_get_flags(
return NULL;
}
STATIC int
_xfs_buf_read(
xfs_buf_t *bp,
xfs_buf_flags_t flags)
{
int status;
XB_TRACE(bp, "_xfs_buf_read", (unsigned long)flags);
ASSERT(!(flags & (XBF_DELWRI|XBF_WRITE)));
ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL);
bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_DELWRI | \
XBF_READ_AHEAD | _XBF_RUN_QUEUES);
bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | \
XBF_READ_AHEAD | _XBF_RUN_QUEUES);
status = xfs_buf_iorequest(bp);
if (!status && !(flags & XBF_ASYNC))
status = xfs_buf_iowait(bp);
return status;
}
xfs_buf_t *
xfs_buf_read_flags(
xfs_buftarg_t *target,
@ -646,7 +669,7 @@ xfs_buf_read_flags(
if (!XFS_BUF_ISDONE(bp)) {
XB_TRACE(bp, "read", (unsigned long)flags);
XFS_STATS_INC(xb_get_read);
xfs_buf_iostart(bp, flags);
_xfs_buf_read(bp, flags);
} else if (flags & XBF_ASYNC) {
XB_TRACE(bp, "read_async", (unsigned long)flags);
/*
@ -1048,50 +1071,39 @@ xfs_buf_ioerror(
XB_TRACE(bp, "ioerror", (unsigned long)error);
}
/*
* Initiate I/O on a buffer, based on the flags supplied.
* The b_iodone routine in the buffer supplied will only be called
* when all of the subsidiary I/O requests, if any, have been completed.
*/
int
xfs_buf_iostart(
xfs_buf_t *bp,
xfs_buf_flags_t flags)
xfs_bawrite(
void *mp,
struct xfs_buf *bp)
{
int status = 0;
XB_TRACE(bp, "bawrite", 0);
XB_TRACE(bp, "iostart", (unsigned long)flags);
ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL);
if (flags & XBF_DELWRI) {
bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_ASYNC);
bp->b_flags |= flags & (XBF_DELWRI | XBF_ASYNC);
xfs_buf_delwri_queue(bp, 1);
return 0;
}
xfs_buf_delwri_dequeue(bp);
bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_ASYNC | XBF_DELWRI | \
XBF_READ_AHEAD | _XBF_RUN_QUEUES);
bp->b_flags |= flags & (XBF_READ | XBF_WRITE | XBF_ASYNC | \
XBF_READ_AHEAD | _XBF_RUN_QUEUES);
bp->b_flags &= ~(XBF_READ | XBF_DELWRI | XBF_READ_AHEAD);
bp->b_flags |= (XBF_WRITE | XBF_ASYNC | _XBF_RUN_QUEUES);
BUG_ON(bp->b_bn == XFS_BUF_DADDR_NULL);
bp->b_mount = mp;
bp->b_strat = xfs_bdstrat_cb;
return xfs_bdstrat_cb(bp);
}
/* For writes allow an alternate strategy routine to precede
* the actual I/O request (which may not be issued at all in
* a shutdown situation, for example).
*/
status = (flags & XBF_WRITE) ?
xfs_buf_iostrategy(bp) : xfs_buf_iorequest(bp);
void
xfs_bdwrite(
void *mp,
struct xfs_buf *bp)
{
XB_TRACE(bp, "bdwrite", 0);
/* Wait for I/O if we are not an async request.
* Note: async I/O request completion will release the buffer,
* and that can already be done by this point. So using the
* buffer pointer from here on, after async I/O, is invalid.
*/
if (!status && !(flags & XBF_ASYNC))
status = xfs_buf_iowait(bp);
bp->b_strat = xfs_bdstrat_cb;
bp->b_mount = mp;
return status;
bp->b_flags &= ~XBF_READ;
bp->b_flags |= (XBF_DELWRI | XBF_ASYNC);
xfs_buf_delwri_queue(bp, 1);
}
STATIC_INLINE void
@ -1114,8 +1126,7 @@ xfs_buf_bio_end_io(
unsigned int blocksize = bp->b_target->bt_bsize;
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
bp->b_error = EIO;
xfs_buf_ioerror(bp, -error);
do {
struct page *page = bvec->bv_page;

View File

@ -168,7 +168,7 @@ typedef struct xfs_buf {
struct completion b_iowait; /* queue for I/O waiters */
void *b_fspriv;
void *b_fspriv2;
void *b_fspriv3;
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 */
@ -214,9 +214,10 @@ extern void xfs_buf_lock(xfs_buf_t *);
extern void xfs_buf_unlock(xfs_buf_t *);
/* Buffer Read and Write Routines */
extern int xfs_bawrite(void *mp, xfs_buf_t *bp);
extern void xfs_bdwrite(void *mp, xfs_buf_t *bp);
extern void xfs_buf_ioend(xfs_buf_t *, int);
extern void xfs_buf_ioerror(xfs_buf_t *, int);
extern int xfs_buf_iostart(xfs_buf_t *, xfs_buf_flags_t);
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, xfs_caddr_t,
@ -311,10 +312,6 @@ extern void xfs_buf_trace(xfs_buf_t *, char *, void *, void *);
#define XFS_BUF_UNORDERED(bp) ((bp)->b_flags &= ~XBF_ORDERED)
#define XFS_BUF_ISORDERED(bp) ((bp)->b_flags & XBF_ORDERED)
#define XFS_BUF_SHUT(bp) do { } while (0)
#define XFS_BUF_UNSHUT(bp) do { } while (0)
#define XFS_BUF_ISSHUT(bp) (0)
#define XFS_BUF_HOLD(bp) xfs_buf_hold(bp)
#define XFS_BUF_READ(bp) ((bp)->b_flags |= XBF_READ)
#define XFS_BUF_UNREAD(bp) ((bp)->b_flags &= ~XBF_READ)
@ -334,8 +331,6 @@ extern void xfs_buf_trace(xfs_buf_t *, char *, void *, void *);
#define XFS_BUF_SET_FSPRIVATE(bp, val) ((bp)->b_fspriv = (void*)(val))
#define XFS_BUF_FSPRIVATE2(bp, type) ((type)(bp)->b_fspriv2)
#define XFS_BUF_SET_FSPRIVATE2(bp, val) ((bp)->b_fspriv2 = (void*)(val))
#define XFS_BUF_FSPRIVATE3(bp, type) ((type)(bp)->b_fspriv3)
#define XFS_BUF_SET_FSPRIVATE3(bp, val) ((bp)->b_fspriv3 = (void*)(val))
#define XFS_BUF_SET_START(bp) do { } while (0)
#define XFS_BUF_SET_BRELSE_FUNC(bp, func) ((bp)->b_relse = (func))
@ -366,14 +361,6 @@ extern void xfs_buf_trace(xfs_buf_t *, char *, void *, void *);
#define XFS_BUF_TARGET(bp) ((bp)->b_target)
#define XFS_BUFTARG_NAME(target) xfs_buf_target_name(target)
static inline int xfs_bawrite(void *mp, xfs_buf_t *bp)
{
bp->b_fspriv3 = mp;
bp->b_strat = xfs_bdstrat_cb;
xfs_buf_delwri_dequeue(bp);
return xfs_buf_iostart(bp, XBF_WRITE | XBF_ASYNC | _XBF_RUN_QUEUES);
}
static inline void xfs_buf_relse(xfs_buf_t *bp)
{
if (!bp->b_relse)
@ -414,17 +401,6 @@ static inline int XFS_bwrite(xfs_buf_t *bp)
return error;
}
/*
* No error can be returned from xfs_buf_iostart for delwri
* buffers as they are queued and no I/O is issued.
*/
static inline void xfs_bdwrite(void *mp, xfs_buf_t *bp)
{
bp->b_strat = xfs_bdstrat_cb;
bp->b_fspriv3 = mp;
(void)xfs_buf_iostart(bp, XBF_DELWRI | XBF_ASYNC);
}
#define XFS_bdstrat(bp) xfs_buf_iorequest(bp)
#define xfs_iowait(bp) xfs_buf_iowait(bp)

View File

@ -25,12 +25,4 @@
*/
typedef const struct cred cred_t;
extern cred_t *sys_cred;
/* this is a hack.. (assumes sys_cred is the only cred_t in the system) */
static inline int capable_cred(cred_t *cr, int cid)
{
return (cr == sys_cred) ? 1 : capable(cid);
}
#endif /* __XFS_CRED_H__ */

View File

@ -29,7 +29,6 @@
#include "xfs_vnodeops.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
#include "xfs_vfsops.h"
/*
* Note that we only accept fileids which are long enough rather than allow

View File

@ -36,31 +36,15 @@
#include "xfs_inode.h"
#include "xfs_error.h"
#include "xfs_rw.h"
#include "xfs_ioctl32.h"
#include "xfs_vnodeops.h"
#include "xfs_da_btree.h"
#include "xfs_ioctl.h"
#include <linux/dcache.h>
#include <linux/smp_lock.h>
static struct vm_operations_struct xfs_file_vm_ops;
STATIC_INLINE ssize_t
__xfs_file_read(
struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs,
int ioflags,
loff_t pos)
{
struct file *file = iocb->ki_filp;
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT;
return xfs_read(XFS_I(file->f_path.dentry->d_inode), iocb, iov,
nr_segs, &iocb->ki_pos, ioflags);
}
STATIC ssize_t
xfs_file_aio_read(
struct kiocb *iocb,
@ -68,34 +52,16 @@ xfs_file_aio_read(
unsigned long nr_segs,
loff_t pos)
{
return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO, pos);
}
STATIC ssize_t
xfs_file_aio_read_invis(
struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs,
loff_t pos)
{
return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
}
STATIC_INLINE ssize_t
__xfs_file_write(
struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs,
int ioflags,
loff_t pos)
{
struct file *file = iocb->ki_filp;
struct file *file = iocb->ki_filp;
int ioflags = IO_ISAIO;
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT;
return xfs_write(XFS_I(file->f_mapping->host), iocb, iov, nr_segs,
&iocb->ki_pos, ioflags);
if (file->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
return xfs_read(XFS_I(file->f_path.dentry->d_inode), iocb, iov,
nr_segs, &iocb->ki_pos, ioflags);
}
STATIC ssize_t
@ -105,17 +71,16 @@ xfs_file_aio_write(
unsigned long nr_segs,
loff_t pos)
{
return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO, pos);
}
struct file *file = iocb->ki_filp;
int ioflags = IO_ISAIO;
STATIC ssize_t
xfs_file_aio_write_invis(
struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs,
loff_t pos)
{
return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT;
if (file->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
return xfs_write(XFS_I(file->f_mapping->host), iocb, iov, nr_segs,
&iocb->ki_pos, ioflags);
}
STATIC ssize_t
@ -126,20 +91,13 @@ xfs_file_splice_read(
size_t len,
unsigned int flags)
{
return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode),
infilp, ppos, pipe, len, flags, 0);
}
int ioflags = 0;
if (infilp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
STATIC ssize_t
xfs_file_splice_read_invis(
struct file *infilp,
loff_t *ppos,
struct pipe_inode_info *pipe,
size_t len,
unsigned int flags)
{
return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode),
infilp, ppos, pipe, len, flags, IO_INVIS);
infilp, ppos, pipe, len, flags, ioflags);
}
STATIC ssize_t
@ -150,30 +108,49 @@ xfs_file_splice_write(
size_t len,
unsigned int flags)
{
return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode),
pipe, outfilp, ppos, len, flags, 0);
}
int ioflags = 0;
if (outfilp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
STATIC ssize_t
xfs_file_splice_write_invis(
struct pipe_inode_info *pipe,
struct file *outfilp,
loff_t *ppos,
size_t len,
unsigned int flags)
{
return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode),
pipe, outfilp, ppos, len, flags, IO_INVIS);
pipe, outfilp, ppos, len, flags, ioflags);
}
STATIC int
xfs_file_open(
struct inode *inode,
struct file *filp)
struct file *file)
{
if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
return -EFBIG;
return -xfs_open(XFS_I(inode));
if (XFS_FORCED_SHUTDOWN(XFS_M(inode->i_sb)))
return -EIO;
return 0;
}
STATIC int
xfs_dir_open(
struct inode *inode,
struct file *file)
{
struct xfs_inode *ip = XFS_I(inode);
int mode;
int error;
error = xfs_file_open(inode, file);
if (error)
return error;
/*
* If there are any blocks, read-ahead block 0 as we're almost
* certain to have the next operation be a read there.
*/
mode = xfs_ilock_map_shared(ip);
if (ip->i_d.di_nextents > 0)
xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK);
xfs_iunlock(ip, mode);
return 0;
}
STATIC int
@ -227,7 +204,7 @@ xfs_file_readdir(
* point we can change the ->readdir prototype to include the
* buffer size.
*/
bufsize = (size_t)min_t(loff_t, PAGE_SIZE, inode->i_size);
bufsize = (size_t)min_t(loff_t, PAGE_SIZE, ip->i_d.di_size);
error = xfs_readdir(ip, dirent, bufsize,
(xfs_off_t *)&filp->f_pos, filldir);
@ -248,48 +225,6 @@ xfs_file_mmap(
return 0;
}
STATIC long
xfs_file_ioctl(
struct file *filp,
unsigned int cmd,
unsigned long p)
{
int error;
struct inode *inode = filp->f_path.dentry->d_inode;
error = xfs_ioctl(XFS_I(inode), filp, 0, cmd, (void __user *)p);
xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED);
/* NOTE: some of the ioctl's return positive #'s as a
* byte count indicating success, such as
* readlink_by_handle. So we don't "sign flip"
* like most other routines. This means true
* errors need to be returned as a negative value.
*/
return error;
}
STATIC long
xfs_file_ioctl_invis(
struct file *filp,
unsigned int cmd,
unsigned long p)
{
int error;
struct inode *inode = filp->f_path.dentry->d_inode;
error = xfs_ioctl(XFS_I(inode), filp, IO_INVIS, cmd, (void __user *)p);
xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED);
/* NOTE: some of the ioctl's return positive #'s as a
* byte count indicating success, such as
* readlink_by_handle. So we don't "sign flip"
* like most other routines. This means true
* errors need to be returned as a negative value.
*/
return error;
}
/*
* mmap()d file has taken write protection fault and is being made
* writable. We can set the page state up correctly for a writable
@ -325,26 +260,8 @@ const struct file_operations xfs_file_operations = {
#endif
};
const struct file_operations xfs_invis_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = xfs_file_aio_read_invis,
.aio_write = xfs_file_aio_write_invis,
.splice_read = xfs_file_splice_read_invis,
.splice_write = xfs_file_splice_write_invis,
.unlocked_ioctl = xfs_file_ioctl_invis,
#ifdef CONFIG_COMPAT
.compat_ioctl = xfs_file_compat_invis_ioctl,
#endif
.mmap = xfs_file_mmap,
.open = xfs_file_open,
.release = xfs_file_release,
.fsync = xfs_file_fsync,
};
const struct file_operations xfs_dir_file_operations = {
.open = xfs_dir_open,
.read = generic_read_dir,
.readdir = xfs_file_readdir,
.llseek = generic_file_llseek,

View File

@ -24,6 +24,10 @@ int fs_noerr(void) { return 0; }
int fs_nosys(void) { return ENOSYS; }
void fs_noval(void) { return; }
/*
* note: all filemap functions return negative error codes. These
* need to be inverted before returning to the xfs core functions.
*/
void
xfs_tosspages(
xfs_inode_t *ip,
@ -53,7 +57,7 @@ xfs_flushinval_pages(
if (!ret)
truncate_inode_pages(mapping, first);
}
return ret;
return -ret;
}
int
@ -72,10 +76,23 @@ xfs_flush_pages(
xfs_iflags_clear(ip, XFS_ITRUNCATED);
ret = filemap_fdatawrite(mapping);
if (flags & XFS_B_ASYNC)
return ret;
return -ret;
ret2 = filemap_fdatawait(mapping);
if (!ret)
ret = ret2;
}
return ret;
return -ret;
}
int
xfs_wait_on_pages(
xfs_inode_t *ip,
xfs_off_t first,
xfs_off_t last)
{
struct address_space *mapping = VFS_I(ip)->i_mapping;
if (mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK))
return -filemap_fdatawait(mapping);
return 0;
}

View File

@ -26,7 +26,6 @@
*/
xfs_param_t xfs_params = {
/* MIN DFLT MAX */
.restrict_chown = { 0, 1, 1 },
.sgid_inherit = { 0, 0, 1 },
.symlink_mode = { 0, 0, 1 },
.panic_mask = { 0, 0, 255 },
@ -43,10 +42,3 @@ xfs_param_t xfs_params = {
.inherit_nodfrg = { 0, 1, 1 },
.fstrm_timer = { 1, 30*100, 3600*100},
};
/*
* Global system credential structure.
*/
static cred_t sys_cred_val;
cred_t *sys_cred = &sys_cred_val;

View File

@ -19,6 +19,5 @@
#define __XFS_GLOBALS_H__
extern uint64_t xfs_panic_mask; /* set to cause more panics */
extern cred_t *sys_cred;
#endif /* __XFS_GLOBALS_H__ */

View File

@ -68,26 +68,22 @@
* XFS_IOC_PATH_TO_HANDLE
* returns full handle for a path
*/
STATIC int
int
xfs_find_handle(
unsigned int cmd,
void __user *arg)
xfs_fsop_handlereq_t *hreq)
{
int hsize;
xfs_handle_t handle;
xfs_fsop_handlereq_t hreq;
struct inode *inode;
if (copy_from_user(&hreq, arg, sizeof(hreq)))
return -XFS_ERROR(EFAULT);
memset((char *)&handle, 0, sizeof(handle));
switch (cmd) {
case XFS_IOC_PATH_TO_FSHANDLE:
case XFS_IOC_PATH_TO_HANDLE: {
struct path path;
int error = user_lpath((const char __user *)hreq.path, &path);
int error = user_lpath((const char __user *)hreq->path, &path);
if (error)
return error;
@ -101,7 +97,7 @@ xfs_find_handle(
case XFS_IOC_FD_TO_HANDLE: {
struct file *file;
file = fget(hreq.fd);
file = fget(hreq->fd);
if (!file)
return -EBADF;
@ -158,8 +154,8 @@ xfs_find_handle(
}
/* now copy our handle into the user buffer & write out the size */
if (copy_to_user(hreq.ohandle, &handle, hsize) ||
copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) {
if (copy_to_user(hreq->ohandle, &handle, hsize) ||
copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) {
iput(inode);
return -XFS_ERROR(EFAULT);
}
@ -249,10 +245,10 @@ xfs_vget_fsop_handlereq(
return 0;
}
STATIC int
int
xfs_open_by_handle(
xfs_mount_t *mp,
void __user *arg,
xfs_fsop_handlereq_t *hreq,
struct file *parfilp,
struct inode *parinode)
{
@ -263,14 +259,11 @@ xfs_open_by_handle(
struct file *filp;
struct inode *inode;
struct dentry *dentry;
xfs_fsop_handlereq_t hreq;
if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);
if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);
error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &inode);
error = xfs_vget_fsop_handlereq(mp, parinode, hreq, &inode);
if (error)
return -error;
@ -281,10 +274,10 @@ xfs_open_by_handle(
}
#if BITS_PER_LONG != 32
hreq.oflags |= O_LARGEFILE;
hreq->oflags |= O_LARGEFILE;
#endif
/* Put open permission in namei format. */
permflag = hreq.oflags;
permflag = hreq->oflags;
if ((permflag+1) & O_ACCMODE)
permflag++;
if (permflag & O_TRUNC)
@ -322,15 +315,16 @@ xfs_open_by_handle(
mntget(parfilp->f_path.mnt);
/* Create file pointer. */
filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags, cred);
filp = dentry_open(dentry, parfilp->f_path.mnt, hreq->oflags, cred);
if (IS_ERR(filp)) {
put_unused_fd(new_fd);
return -XFS_ERROR(-PTR_ERR(filp));
}
if (inode->i_mode & S_IFREG) {
/* invisible operation should not change atime */
filp->f_flags |= O_NOATIME;
filp->f_op = &xfs_invis_file_operations;
filp->f_mode |= FMODE_NOCMTIME;
}
fd_install(new_fd, filp);
@ -363,24 +357,21 @@ do_readlink(
}
STATIC int
int
xfs_readlink_by_handle(
xfs_mount_t *mp,
void __user *arg,
xfs_fsop_handlereq_t *hreq,
struct inode *parinode)
{
struct inode *inode;
xfs_fsop_handlereq_t hreq;
__u32 olen;
void *link;
int error;
if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);
if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);
error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &inode);
error = xfs_vget_fsop_handlereq(mp, parinode, hreq, &inode);
if (error)
return -error;
@ -390,7 +381,7 @@ xfs_readlink_by_handle(
goto out_iput;
}
if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {
if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) {
error = -XFS_ERROR(EFAULT);
goto out_iput;
}
@ -402,7 +393,7 @@ xfs_readlink_by_handle(
error = -xfs_readlink(XFS_I(inode), link);
if (error)
goto out_kfree;
error = do_readlink(hreq.ohandle, olen, link);
error = do_readlink(hreq->ohandle, olen, link);
if (error)
goto out_kfree;
@ -501,7 +492,7 @@ xfs_attrlist_by_handle(
return -error;
}
STATIC int
int
xfs_attrmulti_attr_get(
struct inode *inode,
char *name,
@ -530,7 +521,7 @@ xfs_attrmulti_attr_get(
return error;
}
STATIC int
int
xfs_attrmulti_attr_set(
struct inode *inode,
char *name,
@ -560,7 +551,7 @@ xfs_attrmulti_attr_set(
return error;
}
STATIC int
int
xfs_attrmulti_attr_remove(
struct inode *inode,
char *name,
@ -662,19 +653,26 @@ xfs_attrmulti_by_handle(
return -error;
}
STATIC int
int
xfs_ioc_space(
struct xfs_inode *ip,
struct inode *inode,
struct file *filp,
int ioflags,
unsigned int cmd,
void __user *arg)
xfs_flock64_t *bf)
{
xfs_flock64_t bf;
int attr_flags = 0;
int error;
/*
* Only allow the sys admin to reserve space unless
* unwritten extents are enabled.
*/
if (!xfs_sb_version_hasextflgbit(&ip->i_mount->m_sb) &&
!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);
if (inode->i_flags & (S_IMMUTABLE|S_APPEND))
return -XFS_ERROR(EPERM);
@ -684,16 +682,12 @@ xfs_ioc_space(
if (!S_ISREG(inode->i_mode))
return -XFS_ERROR(EINVAL);
if (copy_from_user(&bf, arg, sizeof(bf)))
return -XFS_ERROR(EFAULT);
if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
attr_flags |= XFS_ATTR_NONBLOCK;
if (ioflags & IO_INVIS)
attr_flags |= XFS_ATTR_DMI;
error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos,
NULL, attr_flags);
error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags);
return -error;
}
@ -1105,10 +1099,6 @@ xfs_ioctl_setattr(
/*
* Change file ownership. Must be the owner or privileged.
* If the system was configured with the "restricted_chown"
* option, the owner is not permitted to give away the file,
* and can change the group id only to a group of which he
* or she is a member.
*/
if (mask & FSX_PROJID) {
/*
@ -1137,7 +1127,7 @@ xfs_ioctl_setattr(
* the superblock version number since projids didn't
* exist before DINODE_VERSION_2 and SB_VERSION_NLINK.
*/
if (ip->i_d.di_version == XFS_DINODE_VERSION_1)
if (ip->i_d.di_version == 1)
xfs_bump_ino_vers2(tp, ip);
}
@ -1255,6 +1245,19 @@ xfs_ioc_setxflags(
return -xfs_ioctl_setattr(ip, &fa, mask);
}
STATIC int
xfs_getbmap_format(void **ap, struct getbmapx *bmv, int *full)
{
struct getbmap __user *base = *ap;
/* copy only getbmap portion (not getbmapx) */
if (copy_to_user(base, bmv, sizeof(struct getbmap)))
return XFS_ERROR(EFAULT);
*ap += sizeof(struct getbmap);
return 0;
}
STATIC int
xfs_ioc_getbmap(
struct xfs_inode *ip,
@ -1262,37 +1265,48 @@ xfs_ioc_getbmap(
unsigned int cmd,
void __user *arg)
{
struct getbmap bm;
int iflags;
struct getbmapx bmx;
int error;
if (copy_from_user(&bm, arg, sizeof(bm)))
if (copy_from_user(&bmx, arg, sizeof(struct getbmapx)))
return -XFS_ERROR(EFAULT);
if (bm.bmv_count < 2)
if (bmx.bmv_count < 2)
return -XFS_ERROR(EINVAL);
iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
if (ioflags & IO_INVIS)
iflags |= BMV_IF_NO_DMAPI_READ;
bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
error = xfs_getbmap(ip, &bm, (struct getbmap __user *)arg+1, iflags);
error = xfs_getbmap(ip, &bmx, xfs_getbmap_format,
(struct getbmap *)arg+1);
if (error)
return -error;
if (copy_to_user(arg, &bm, sizeof(bm)))
/* copy back header - only size of getbmap */
if (copy_to_user(arg, &bmx, sizeof(struct getbmap)))
return -XFS_ERROR(EFAULT);
return 0;
}
STATIC int
xfs_getbmapx_format(void **ap, struct getbmapx *bmv, int *full)
{
struct getbmapx __user *base = *ap;
if (copy_to_user(base, bmv, sizeof(struct getbmapx)))
return XFS_ERROR(EFAULT);
*ap += sizeof(struct getbmapx);
return 0;
}
STATIC int
xfs_ioc_getbmapx(
struct xfs_inode *ip,
void __user *arg)
{
struct getbmapx bmx;
struct getbmap bm;
int iflags;
int error;
if (copy_from_user(&bmx, arg, sizeof(bmx)))
@ -1301,46 +1315,46 @@ xfs_ioc_getbmapx(
if (bmx.bmv_count < 2)
return -XFS_ERROR(EINVAL);
/*
* Map input getbmapx structure to a getbmap
* structure for xfs_getbmap.
*/
GETBMAP_CONVERT(bmx, bm);
iflags = bmx.bmv_iflags;
if (iflags & (~BMV_IF_VALID))
if (bmx.bmv_iflags & (~BMV_IF_VALID))
return -XFS_ERROR(EINVAL);
iflags |= BMV_IF_EXTENDED;
error = xfs_getbmap(ip, &bm, (struct getbmapx __user *)arg+1, iflags);
error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format,
(struct getbmapx *)arg+1);
if (error)
return -error;
GETBMAP_CONVERT(bm, bmx);
if (copy_to_user(arg, &bmx, sizeof(bmx)))
/* copy back header */
if (copy_to_user(arg, &bmx, sizeof(struct getbmapx)))
return -XFS_ERROR(EFAULT);
return 0;
}
int
xfs_ioctl(
xfs_inode_t *ip,
/*
* Note: some of the ioctl's return positive numbers as a
* byte count indicating success, such as readlink_by_handle.
* So we don't "sign flip" like most other routines. This means
* true errors need to be returned as a negative value.
*/
long
xfs_file_ioctl(
struct file *filp,
int ioflags,
unsigned int cmd,
void __user *arg)
unsigned long p)
{
struct inode *inode = filp->f_path.dentry->d_inode;
xfs_mount_t *mp = ip->i_mount;
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
void __user *arg = (void __user *)p;
int ioflags = 0;
int error;
xfs_itrace_entry(XFS_I(inode));
switch (cmd) {
if (filp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
xfs_itrace_entry(ip);
switch (cmd) {
case XFS_IOC_ALLOCSP:
case XFS_IOC_FREESP:
case XFS_IOC_RESVSP:
@ -1348,17 +1362,13 @@ xfs_ioctl(
case XFS_IOC_ALLOCSP64:
case XFS_IOC_FREESP64:
case XFS_IOC_RESVSP64:
case XFS_IOC_UNRESVSP64:
/*
* Only allow the sys admin to reserve space unless
* unwritten extents are enabled.
*/
if (!xfs_sb_version_hasextflgbit(&mp->m_sb) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
return xfs_ioc_space(ip, inode, filp, ioflags, cmd, arg);
case XFS_IOC_UNRESVSP64: {
xfs_flock64_t bf;
if (copy_from_user(&bf, arg, sizeof(bf)))
return -XFS_ERROR(EFAULT);
return xfs_ioc_space(ip, inode, filp, ioflags, cmd, &bf);
}
case XFS_IOC_DIOINFO: {
struct dioattr da;
xfs_buftarg_t *target =
@ -1418,18 +1428,30 @@ xfs_ioctl(
case XFS_IOC_FD_TO_HANDLE:
case XFS_IOC_PATH_TO_HANDLE:
case XFS_IOC_PATH_TO_FSHANDLE:
return xfs_find_handle(cmd, arg);
case XFS_IOC_PATH_TO_FSHANDLE: {
xfs_fsop_handlereq_t hreq;
case XFS_IOC_OPEN_BY_HANDLE:
return xfs_open_by_handle(mp, arg, filp, inode);
if (copy_from_user(&hreq, arg, sizeof(hreq)))
return -XFS_ERROR(EFAULT);
return xfs_find_handle(cmd, &hreq);
}
case XFS_IOC_OPEN_BY_HANDLE: {
xfs_fsop_handlereq_t hreq;
if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);
return xfs_open_by_handle(mp, &hreq, filp, inode);
}
case XFS_IOC_FSSETDM_BY_HANDLE:
return xfs_fssetdm_by_handle(mp, arg, inode);
case XFS_IOC_READLINK_BY_HANDLE:
return xfs_readlink_by_handle(mp, arg, inode);
case XFS_IOC_READLINK_BY_HANDLE: {
xfs_fsop_handlereq_t hreq;
if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);
return xfs_readlink_by_handle(mp, &hreq, inode);
}
case XFS_IOC_ATTRLIST_BY_HANDLE:
return xfs_attrlist_by_handle(mp, arg, inode);
@ -1437,7 +1459,11 @@ xfs_ioctl(
return xfs_attrmulti_by_handle(mp, arg, filp, inode);
case XFS_IOC_SWAPEXT: {
error = xfs_swapext((struct xfs_swapext __user *)arg);
struct xfs_swapext sxp;
if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t)))
return -XFS_ERROR(EFAULT);
error = xfs_swapext(&sxp);
return -error;
}
@ -1493,9 +1519,6 @@ xfs_ioctl(
case XFS_IOC_FSGROWFSDATA: {
xfs_growfs_data_t in;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);
@ -1506,9 +1529,6 @@ xfs_ioctl(
case XFS_IOC_FSGROWFSLOG: {
xfs_growfs_log_t in;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);
@ -1519,9 +1539,6 @@ xfs_ioctl(
case XFS_IOC_FSGROWFSRT: {
xfs_growfs_rt_t in;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2008 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_IOCTL_H__
#define __XFS_IOCTL_H__
extern int
xfs_ioc_space(
struct xfs_inode *ip,
struct inode *inode,
struct file *filp,
int ioflags,
unsigned int cmd,
xfs_flock64_t *bf);
extern int
xfs_find_handle(
unsigned int cmd,
xfs_fsop_handlereq_t *hreq);
extern int
xfs_open_by_handle(
xfs_mount_t *mp,
xfs_fsop_handlereq_t *hreq,
struct file *parfilp,
struct inode *parinode);
extern int
xfs_readlink_by_handle(
xfs_mount_t *mp,
xfs_fsop_handlereq_t *hreq,
struct inode *parinode);
extern int
xfs_attrmulti_attr_get(
struct inode *inode,
char *name,
char __user *ubuf,
__uint32_t *len,
__uint32_t flags);
extern int
xfs_attrmulti_attr_set(
struct inode *inode,
char *name,
const char __user *ubuf,
__uint32_t len,
__uint32_t flags);
extern int
xfs_attrmulti_attr_remove(
struct inode *inode,
char *name,
__uint32_t flags);
extern long
xfs_file_ioctl(
struct file *filp,
unsigned int cmd,
unsigned long p);
extern long
xfs_file_compat_ioctl(
struct file *file,
unsigned int cmd,
unsigned long arg);
#endif

View File

@ -16,11 +16,7 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/compat.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/syscalls.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include "xfs.h"
#include "xfs_fs.h"
@ -36,7 +32,6 @@
#include "xfs_bmap_btree.h"
#include "xfs_attr_sf.h"
#include "xfs_dir2_sf.h"
#include "xfs_vfs.h"
#include "xfs_vnode.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
@ -44,221 +39,219 @@
#include "xfs_error.h"
#include "xfs_dfrag.h"
#include "xfs_vnodeops.h"
#include "xfs_fsops.h"
#include "xfs_alloc.h"
#include "xfs_rtalloc.h"
#include "xfs_attr.h"
#include "xfs_ioctl.h"
#include "xfs_ioctl32.h"
#define _NATIVE_IOC(cmd, type) \
_IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type))
#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
#define BROKEN_X86_ALIGNMENT
#define _PACKED __attribute__((packed))
/* on ia32 l_start is on a 32-bit boundary */
typedef struct xfs_flock64_32 {
__s16 l_type;
__s16 l_whence;
__s64 l_start __attribute__((packed));
/* len == 0 means until end of file */
__s64 l_len __attribute__((packed));
__s32 l_sysid;
__u32 l_pid;
__s32 l_pad[4]; /* reserve area */
} xfs_flock64_32_t;
#define XFS_IOC_ALLOCSP_32 _IOW ('X', 10, struct xfs_flock64_32)
#define XFS_IOC_FREESP_32 _IOW ('X', 11, struct xfs_flock64_32)
#define XFS_IOC_ALLOCSP64_32 _IOW ('X', 36, struct xfs_flock64_32)
#define XFS_IOC_FREESP64_32 _IOW ('X', 37, struct xfs_flock64_32)
#define XFS_IOC_RESVSP_32 _IOW ('X', 40, struct xfs_flock64_32)
#define XFS_IOC_UNRESVSP_32 _IOW ('X', 41, struct xfs_flock64_32)
#define XFS_IOC_RESVSP64_32 _IOW ('X', 42, struct xfs_flock64_32)
#define XFS_IOC_UNRESVSP64_32 _IOW ('X', 43, struct xfs_flock64_32)
/* just account for different alignment */
STATIC unsigned long
xfs_ioctl32_flock(
unsigned long arg)
#ifdef BROKEN_X86_ALIGNMENT
STATIC int
xfs_compat_flock64_copyin(
xfs_flock64_t *bf,
compat_xfs_flock64_t __user *arg32)
{
xfs_flock64_32_t __user *p32 = (void __user *)arg;
xfs_flock64_t __user *p = compat_alloc_user_space(sizeof(*p));
if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) ||
copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) ||
copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) ||
copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) ||
copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) ||
copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) ||
copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32)))
return -EFAULT;
return (unsigned long)p;
if (get_user(bf->l_type, &arg32->l_type) ||
get_user(bf->l_whence, &arg32->l_whence) ||
get_user(bf->l_start, &arg32->l_start) ||
get_user(bf->l_len, &arg32->l_len) ||
get_user(bf->l_sysid, &arg32->l_sysid) ||
get_user(bf->l_pid, &arg32->l_pid) ||
copy_from_user(bf->l_pad, &arg32->l_pad, 4*sizeof(u32)))
return -XFS_ERROR(EFAULT);
return 0;
}
typedef struct compat_xfs_fsop_geom_v1 {
__u32 blocksize; /* filesystem (data) block size */
__u32 rtextsize; /* realtime extent size */
__u32 agblocks; /* fsblocks in an AG */
__u32 agcount; /* number of allocation groups */
__u32 logblocks; /* fsblocks in the log */
__u32 sectsize; /* (data) sector size, bytes */
__u32 inodesize; /* inode size in bytes */
__u32 imaxpct; /* max allowed inode space(%) */
__u64 datablocks; /* fsblocks in data subvolume */
__u64 rtblocks; /* fsblocks in realtime subvol */
__u64 rtextents; /* rt extents in realtime subvol*/
__u64 logstart; /* starting fsblock of the log */
unsigned char uuid[16]; /* unique id of the filesystem */
__u32 sunit; /* stripe unit, fsblocks */
__u32 swidth; /* stripe width, fsblocks */
__s32 version; /* structure version */
__u32 flags; /* superblock version flags */
__u32 logsectsize; /* log sector size, bytes */
__u32 rtsectsize; /* realtime sector size, bytes */
__u32 dirblocksize; /* directory block size, bytes */
} __attribute__((packed)) compat_xfs_fsop_geom_v1_t;
#define XFS_IOC_FSGEOMETRY_V1_32 \
_IOR ('X', 100, struct compat_xfs_fsop_geom_v1)
STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg)
STATIC int
xfs_compat_ioc_fsgeometry_v1(
struct xfs_mount *mp,
compat_xfs_fsop_geom_v1_t __user *arg32)
{
compat_xfs_fsop_geom_v1_t __user *p32 = (void __user *)arg;
xfs_fsop_geom_v1_t __user *p = compat_alloc_user_space(sizeof(*p));
xfs_fsop_geom_t fsgeo;
int error;
if (copy_in_user(p, p32, sizeof(*p32)))
return -EFAULT;
return (unsigned long)p;
error = xfs_fs_geometry(mp, &fsgeo, 3);
if (error)
return -error;
/* The 32-bit variant simply has some padding at the end */
if (copy_to_user(arg32, &fsgeo, sizeof(struct compat_xfs_fsop_geom_v1)))
return -XFS_ERROR(EFAULT);
return 0;
}
typedef struct compat_xfs_inogrp {
__u64 xi_startino; /* starting inode number */
__s32 xi_alloccount; /* # bits set in allocmask */
__u64 xi_allocmask; /* mask of allocated inodes */
} __attribute__((packed)) compat_xfs_inogrp_t;
STATIC int xfs_inumbers_fmt_compat(
void __user *ubuffer,
const xfs_inogrp_t *buffer,
long count,
long *written)
STATIC int
xfs_compat_growfs_data_copyin(
struct xfs_growfs_data *in,
compat_xfs_growfs_data_t __user *arg32)
{
compat_xfs_inogrp_t __user *p32 = ubuffer;
long i;
if (get_user(in->newblocks, &arg32->newblocks) ||
get_user(in->imaxpct, &arg32->imaxpct))
return -XFS_ERROR(EFAULT);
return 0;
}
STATIC int
xfs_compat_growfs_rt_copyin(
struct xfs_growfs_rt *in,
compat_xfs_growfs_rt_t __user *arg32)
{
if (get_user(in->newblocks, &arg32->newblocks) ||
get_user(in->extsize, &arg32->extsize))
return -XFS_ERROR(EFAULT);
return 0;
}
STATIC int
xfs_inumbers_fmt_compat(
void __user *ubuffer,
const xfs_inogrp_t *buffer,
long count,
long *written)
{
compat_xfs_inogrp_t __user *p32 = ubuffer;
long i;
for (i = 0; i < count; i++) {
if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) ||
put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) ||
put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask))
return -EFAULT;
return -XFS_ERROR(EFAULT);
}
*written = count * sizeof(*p32);
return 0;
}
#else
#define xfs_inumbers_fmt_compat xfs_inumbers_fmt
#define _PACKED
#endif /* BROKEN_X86_ALIGNMENT */
#endif
STATIC int
xfs_ioctl32_bstime_copyin(
xfs_bstime_t *bstime,
compat_xfs_bstime_t __user *bstime32)
{
compat_time_t sec32; /* tv_sec differs on 64 vs. 32 */
if (get_user(sec32, &bstime32->tv_sec) ||
get_user(bstime->tv_nsec, &bstime32->tv_nsec))
return -XFS_ERROR(EFAULT);
bstime->tv_sec = sec32;
return 0;
}
/* xfs_bstat_t has differing alignment on intel, & bstime_t sizes everywhere */
STATIC int
xfs_ioctl32_bstat_copyin(
xfs_bstat_t *bstat,
compat_xfs_bstat_t __user *bstat32)
{
if (get_user(bstat->bs_ino, &bstat32->bs_ino) ||
get_user(bstat->bs_mode, &bstat32->bs_mode) ||
get_user(bstat->bs_nlink, &bstat32->bs_nlink) ||
get_user(bstat->bs_uid, &bstat32->bs_uid) ||
get_user(bstat->bs_gid, &bstat32->bs_gid) ||
get_user(bstat->bs_rdev, &bstat32->bs_rdev) ||
get_user(bstat->bs_blksize, &bstat32->bs_blksize) ||
get_user(bstat->bs_size, &bstat32->bs_size) ||
xfs_ioctl32_bstime_copyin(&bstat->bs_atime, &bstat32->bs_atime) ||
xfs_ioctl32_bstime_copyin(&bstat->bs_mtime, &bstat32->bs_mtime) ||
xfs_ioctl32_bstime_copyin(&bstat->bs_ctime, &bstat32->bs_ctime) ||
get_user(bstat->bs_blocks, &bstat32->bs_size) ||
get_user(bstat->bs_xflags, &bstat32->bs_size) ||
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_dmevmask, &bstat32->bs_dmevmask) ||
get_user(bstat->bs_dmstate, &bstat32->bs_dmstate) ||
get_user(bstat->bs_aextents, &bstat32->bs_aextents))
return -XFS_ERROR(EFAULT);
return 0;
}
/* XFS_IOC_FSBULKSTAT and friends */
typedef struct compat_xfs_bstime {
__s32 tv_sec; /* seconds */
__s32 tv_nsec; /* and nanoseconds */
} compat_xfs_bstime_t;
STATIC int xfs_bstime_store_compat(
compat_xfs_bstime_t __user *p32,
const xfs_bstime_t *p)
STATIC int
xfs_bstime_store_compat(
compat_xfs_bstime_t __user *p32,
const xfs_bstime_t *p)
{
__s32 sec32;
__s32 sec32;
sec32 = p->tv_sec;
if (put_user(sec32, &p32->tv_sec) ||
put_user(p->tv_nsec, &p32->tv_nsec))
return -EFAULT;
return -XFS_ERROR(EFAULT);
return 0;
}
typedef struct compat_xfs_bstat {
__u64 bs_ino; /* inode number */
__u16 bs_mode; /* type and mode */
__u16 bs_nlink; /* number of links */
__u32 bs_uid; /* user id */
__u32 bs_gid; /* group id */
__u32 bs_rdev; /* device value */
__s32 bs_blksize; /* block size */
__s64 bs_size; /* file size */
compat_xfs_bstime_t bs_atime; /* access time */
compat_xfs_bstime_t bs_mtime; /* modify time */
compat_xfs_bstime_t bs_ctime; /* inode change time */
int64_t bs_blocks; /* number of blocks */
__u32 bs_xflags; /* extended flags */
__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 */
__u32 bs_dmevmask; /* DMIG event mask */
__u16 bs_dmstate; /* DMIG state info */
__u16 bs_aextents; /* attribute number of extents */
} _PACKED compat_xfs_bstat_t;
STATIC int xfs_bulkstat_one_fmt_compat(
/* Return 0 on success or positive error (to xfs_bulkstat()) */
STATIC int
xfs_bulkstat_one_fmt_compat(
void __user *ubuffer,
int ubsize,
int *ubused,
const xfs_bstat_t *buffer)
{
compat_xfs_bstat_t __user *p32 = ubuffer;
compat_xfs_bstat_t __user *p32 = ubuffer;
if (put_user(buffer->bs_ino, &p32->bs_ino) ||
put_user(buffer->bs_mode, &p32->bs_mode) ||
put_user(buffer->bs_nlink, &p32->bs_nlink) ||
put_user(buffer->bs_uid, &p32->bs_uid) ||
put_user(buffer->bs_gid, &p32->bs_gid) ||
put_user(buffer->bs_rdev, &p32->bs_rdev) ||
put_user(buffer->bs_blksize, &p32->bs_blksize) ||
put_user(buffer->bs_size, &p32->bs_size) ||
if (ubsize < sizeof(*p32))
return XFS_ERROR(ENOMEM);
if (put_user(buffer->bs_ino, &p32->bs_ino) ||
put_user(buffer->bs_mode, &p32->bs_mode) ||
put_user(buffer->bs_nlink, &p32->bs_nlink) ||
put_user(buffer->bs_uid, &p32->bs_uid) ||
put_user(buffer->bs_gid, &p32->bs_gid) ||
put_user(buffer->bs_rdev, &p32->bs_rdev) ||
put_user(buffer->bs_blksize, &p32->bs_blksize) ||
put_user(buffer->bs_size, &p32->bs_size) ||
xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) ||
xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) ||
xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) ||
put_user(buffer->bs_blocks, &p32->bs_blocks) ||
put_user(buffer->bs_xflags, &p32->bs_xflags) ||
put_user(buffer->bs_extsize, &p32->bs_extsize) ||
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_dmevmask, &p32->bs_dmevmask) ||
put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
put_user(buffer->bs_blocks, &p32->bs_blocks) ||
put_user(buffer->bs_xflags, &p32->bs_xflags) ||
put_user(buffer->bs_extsize, &p32->bs_extsize) ||
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_dmevmask, &p32->bs_dmevmask) ||
put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
put_user(buffer->bs_aextents, &p32->bs_aextents))
return -EFAULT;
return sizeof(*p32);
return XFS_ERROR(EFAULT);
if (ubused)
*ubused = sizeof(*p32);
return 0;
}
typedef struct compat_xfs_fsop_bulkreq {
compat_uptr_t lastip; /* last inode # pointer */
__s32 icount; /* count of entries in buffer */
compat_uptr_t ubuffer; /* user buffer for inode desc. */
compat_uptr_t ocount; /* output count pointer */
} compat_xfs_fsop_bulkreq_t;
#define XFS_IOC_FSBULKSTAT_32 \
_IOWR('X', 101, struct compat_xfs_fsop_bulkreq)
#define XFS_IOC_FSBULKSTAT_SINGLE_32 \
_IOWR('X', 102, struct compat_xfs_fsop_bulkreq)
#define XFS_IOC_FSINUMBERS_32 \
_IOWR('X', 103, struct compat_xfs_fsop_bulkreq)
STATIC int
xfs_bulkstat_one_compat(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t ino, /* inode number to get data for */
void __user *buffer, /* buffer to place output in */
int ubsize, /* size of buffer */
void *private_data, /* my private data */
xfs_daddr_t bno, /* starting bno of inode cluster */
int *ubused, /* bytes used by me */
void *dibuff, /* on-disk inode buffer */
int *stat) /* BULKSTAT_RV_... */
{
return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
xfs_bulkstat_one_fmt_compat, bno,
ubused, dibuff, stat);
}
/* copied from xfs_ioctl.c */
STATIC int
xfs_ioc_bulkstat_compat(
xfs_mount_t *mp,
unsigned int cmd,
void __user *arg)
xfs_compat_ioc_bulkstat(
xfs_mount_t *mp,
unsigned int cmd,
compat_xfs_fsop_bulkreq_t __user *p32)
{
compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg;
u32 addr;
xfs_fsop_bulkreq_t bulkreq;
int count; /* # of records returned */
@ -270,20 +263,20 @@ xfs_ioc_bulkstat_compat(
/* should be called again (unused here, but used in dmapi) */
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return -XFS_ERROR(EPERM);
if (XFS_FORCED_SHUTDOWN(mp))
return -XFS_ERROR(EIO);
if (get_user(addr, &p32->lastip))
return -EFAULT;
return -XFS_ERROR(EFAULT);
bulkreq.lastip = compat_ptr(addr);
if (get_user(bulkreq.icount, &p32->icount) ||
get_user(addr, &p32->ubuffer))
return -EFAULT;
return -XFS_ERROR(EFAULT);
bulkreq.ubuffer = compat_ptr(addr);
if (get_user(addr, &p32->ocount))
return -EFAULT;
return -XFS_ERROR(EFAULT);
bulkreq.ocount = compat_ptr(addr);
if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
@ -295,17 +288,22 @@ xfs_ioc_bulkstat_compat(
if (bulkreq.ubuffer == NULL)
return -XFS_ERROR(EINVAL);
if (cmd == XFS_IOC_FSINUMBERS)
if (cmd == XFS_IOC_FSINUMBERS_32) {
error = xfs_inumbers(mp, &inlast, &count,
bulkreq.ubuffer, xfs_inumbers_fmt_compat);
else {
/* declare a var to get a warning in case the type changes */
bulkstat_one_fmt_pf formatter = xfs_bulkstat_one_fmt_compat;
} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
int res;
error = xfs_bulkstat_one_compat(mp, inlast, bulkreq.ubuffer,
sizeof(compat_xfs_bstat_t),
NULL, 0, NULL, NULL, &res);
} else if (cmd == XFS_IOC_FSBULKSTAT_32) {
error = xfs_bulkstat(mp, &inlast, &count,
xfs_bulkstat_one, formatter,
xfs_bulkstat_one_compat, NULL,
sizeof(compat_xfs_bstat_t), bulkreq.ubuffer,
BULKSTAT_FG_QUICK, &done);
}
} else
error = XFS_ERROR(EINVAL);
if (error)
return -error;
@ -321,63 +319,306 @@ xfs_ioc_bulkstat_compat(
return 0;
}
typedef struct compat_xfs_fsop_handlereq {
__u32 fd; /* fd for FD_TO_HANDLE */
compat_uptr_t path; /* user pathname */
__u32 oflags; /* open flags */
compat_uptr_t ihandle; /* user supplied handle */
__u32 ihandlen; /* user supplied length */
compat_uptr_t ohandle; /* user buffer for handle */
compat_uptr_t ohandlen; /* user buffer length */
} compat_xfs_fsop_handlereq_t;
#define XFS_IOC_PATH_TO_FSHANDLE_32 \
_IOWR('X', 104, struct compat_xfs_fsop_handlereq)
#define XFS_IOC_PATH_TO_HANDLE_32 \
_IOWR('X', 105, struct compat_xfs_fsop_handlereq)
#define XFS_IOC_FD_TO_HANDLE_32 \
_IOWR('X', 106, struct compat_xfs_fsop_handlereq)
#define XFS_IOC_OPEN_BY_HANDLE_32 \
_IOWR('X', 107, struct compat_xfs_fsop_handlereq)
#define XFS_IOC_READLINK_BY_HANDLE_32 \
_IOWR('X', 108, struct compat_xfs_fsop_handlereq)
STATIC unsigned long xfs_ioctl32_fshandle(unsigned long arg)
STATIC int
xfs_compat_handlereq_copyin(
xfs_fsop_handlereq_t *hreq,
compat_xfs_fsop_handlereq_t __user *arg32)
{
compat_xfs_fsop_handlereq_t __user *p32 = (void __user *)arg;
xfs_fsop_handlereq_t __user *p = compat_alloc_user_space(sizeof(*p));
u32 addr;
compat_xfs_fsop_handlereq_t hreq32;
if (copy_in_user(&p->fd, &p32->fd, sizeof(__u32)) ||
get_user(addr, &p32->path) ||
put_user(compat_ptr(addr), &p->path) ||
copy_in_user(&p->oflags, &p32->oflags, sizeof(__u32)) ||
get_user(addr, &p32->ihandle) ||
put_user(compat_ptr(addr), &p->ihandle) ||
copy_in_user(&p->ihandlen, &p32->ihandlen, sizeof(__u32)) ||
get_user(addr, &p32->ohandle) ||
put_user(compat_ptr(addr), &p->ohandle) ||
get_user(addr, &p32->ohandlen) ||
put_user(compat_ptr(addr), &p->ohandlen))
return -EFAULT;
if (copy_from_user(&hreq32, arg32, sizeof(compat_xfs_fsop_handlereq_t)))
return -XFS_ERROR(EFAULT);
return (unsigned long)p;
hreq->fd = hreq32.fd;
hreq->path = compat_ptr(hreq32.path);
hreq->oflags = hreq32.oflags;
hreq->ihandle = compat_ptr(hreq32.ihandle);
hreq->ihandlen = hreq32.ihandlen;
hreq->ohandle = compat_ptr(hreq32.ohandle);
hreq->ohandlen = compat_ptr(hreq32.ohandlen);
return 0;
}
STATIC long
xfs_compat_ioctl(
int mode,
struct file *file,
unsigned cmd,
unsigned long arg)
/*
* Convert userspace handle data into inode.
*
* We use the fact that all the fsop_handlereq ioctl calls have a data
* structure argument whose first component is always a xfs_fsop_handlereq_t,
* so we can pass that sub structure into this handy, shared routine.
*
* If no error, caller must always iput the returned inode.
*/
STATIC int
xfs_vget_fsop_handlereq_compat(
xfs_mount_t *mp,
struct inode *parinode, /* parent inode pointer */
compat_xfs_fsop_handlereq_t *hreq,
struct inode **inode)
{
struct inode *inode = file->f_path.dentry->d_inode;
int error;
void __user *hanp;
size_t hlen;
xfs_fid_t *xfid;
xfs_handle_t *handlep;
xfs_handle_t handle;
xfs_inode_t *ip;
xfs_ino_t ino;
__u32 igen;
int error;
/*
* Only allow handle opens under a directory.
*/
if (!S_ISDIR(parinode->i_mode))
return XFS_ERROR(ENOTDIR);
hanp = compat_ptr(hreq->ihandle);
hlen = hreq->ihandlen;
handlep = &handle;
if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))
return XFS_ERROR(EINVAL);
if (copy_from_user(handlep, hanp, hlen))
return XFS_ERROR(EFAULT);
if (hlen < sizeof(*handlep))
memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
if (hlen > sizeof(handlep->ha_fsid)) {
if (handlep->ha_fid.fid_len !=
(hlen - sizeof(handlep->ha_fsid) -
sizeof(handlep->ha_fid.fid_len)) ||
handlep->ha_fid.fid_pad)
return XFS_ERROR(EINVAL);
}
/*
* Crack the handle, obtain the inode # & generation #
*/
xfid = (struct xfs_fid *)&handlep->ha_fid;
if (xfid->fid_len == sizeof(*xfid) - sizeof(xfid->fid_len)) {
ino = xfid->fid_ino;
igen = xfid->fid_gen;
} else {
return XFS_ERROR(EINVAL);
}
/*
* Get the XFS inode, building a Linux inode to go with it.
*/
error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);
if (error)
return error;
if (ip == NULL)
return XFS_ERROR(EIO);
if (ip->i_d.di_gen != igen) {
xfs_iput_new(ip, XFS_ILOCK_SHARED);
return XFS_ERROR(ENOENT);
}
xfs_iunlock(ip, XFS_ILOCK_SHARED);
*inode = VFS_I(ip);
return 0;
}
STATIC int
xfs_compat_attrlist_by_handle(
xfs_mount_t *mp,
void __user *arg,
struct inode *parinode)
{
int error;
attrlist_cursor_kern_t *cursor;
compat_xfs_fsop_attrlist_handlereq_t al_hreq;
struct inode *inode;
char *kbuf;
if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);
if (copy_from_user(&al_hreq, arg,
sizeof(compat_xfs_fsop_attrlist_handlereq_t)))
return -XFS_ERROR(EFAULT);
if (al_hreq.buflen > XATTR_LIST_MAX)
return -XFS_ERROR(EINVAL);
/*
* Reject flags, only allow namespaces.
*/
if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE))
return -XFS_ERROR(EINVAL);
error = xfs_vget_fsop_handlereq_compat(mp, parinode, &al_hreq.hreq,
&inode);
if (error)
goto out;
kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
if (!kbuf)
goto out_vn_rele;
cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
error = xfs_attr_list(XFS_I(inode), kbuf, al_hreq.buflen,
al_hreq.flags, cursor);
if (error)
goto out_kfree;
if (copy_to_user(compat_ptr(al_hreq.buffer), kbuf, al_hreq.buflen))
error = -EFAULT;
out_kfree:
kfree(kbuf);
out_vn_rele:
iput(inode);
out:
return -error;
}
STATIC int
xfs_compat_attrmulti_by_handle(
xfs_mount_t *mp,
void __user *arg,
struct inode *parinode)
{
int error;
compat_xfs_attr_multiop_t *ops;
compat_xfs_fsop_attrmulti_handlereq_t am_hreq;
struct inode *inode;
unsigned int i, size;
char *attr_name;
if (!capable(CAP_SYS_ADMIN))
return -XFS_ERROR(EPERM);
if (copy_from_user(&am_hreq, arg,
sizeof(compat_xfs_fsop_attrmulti_handlereq_t)))
return -XFS_ERROR(EFAULT);
error = xfs_vget_fsop_handlereq_compat(mp, parinode, &am_hreq.hreq,
&inode);
if (error)
goto out;
error = E2BIG;
size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t);
if (!size || size > 16 * PAGE_SIZE)
goto out_vn_rele;
error = ENOMEM;
ops = kmalloc(size, GFP_KERNEL);
if (!ops)
goto out_vn_rele;
error = EFAULT;
if (copy_from_user(ops, compat_ptr(am_hreq.ops), size))
goto out_kfree_ops;
attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
if (!attr_name)
goto out_kfree_ops;
error = 0;
for (i = 0; i < am_hreq.opcount; i++) {
ops[i].am_error = strncpy_from_user(attr_name,
compat_ptr(ops[i].am_attrname),
MAXNAMELEN);
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
error = -ERANGE;
if (ops[i].am_error < 0)
break;
switch (ops[i].am_opcode) {
case ATTR_OP_GET:
ops[i].am_error = xfs_attrmulti_attr_get(inode,
attr_name,
compat_ptr(ops[i].am_attrvalue),
&ops[i].am_length, ops[i].am_flags);
break;
case ATTR_OP_SET:
ops[i].am_error = xfs_attrmulti_attr_set(inode,
attr_name,
compat_ptr(ops[i].am_attrvalue),
ops[i].am_length, ops[i].am_flags);
break;
case ATTR_OP_REMOVE:
ops[i].am_error = xfs_attrmulti_attr_remove(inode,
attr_name, ops[i].am_flags);
break;
default:
ops[i].am_error = EINVAL;
}
}
if (copy_to_user(compat_ptr(am_hreq.ops), ops, size))
error = XFS_ERROR(EFAULT);
kfree(attr_name);
out_kfree_ops:
kfree(ops);
out_vn_rele:
iput(inode);
out:
return -error;
}
STATIC int
xfs_compat_fssetdm_by_handle(
xfs_mount_t *mp,
void __user *arg,
struct inode *parinode)
{
int error;
struct fsdmidata fsd;
compat_xfs_fsop_setdm_handlereq_t dmhreq;
struct inode *inode;
if (!capable(CAP_MKNOD))
return -XFS_ERROR(EPERM);
if (copy_from_user(&dmhreq, arg,
sizeof(compat_xfs_fsop_setdm_handlereq_t)))
return -XFS_ERROR(EFAULT);
error = xfs_vget_fsop_handlereq_compat(mp, parinode, &dmhreq.hreq,
&inode);
if (error)
return -error;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
error = -XFS_ERROR(EPERM);
goto out;
}
if (copy_from_user(&fsd, compat_ptr(dmhreq.data), sizeof(fsd))) {
error = -XFS_ERROR(EFAULT);
goto out;
}
error = -xfs_set_dmattrs(XFS_I(inode), fsd.fsd_dmevmask,
fsd.fsd_dmstate);
out:
iput(inode);
return error;
}
long
xfs_file_compat_ioctl(
struct file *filp,
unsigned cmd,
unsigned long p)
{
struct inode *inode = filp->f_path.dentry->d_inode;
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
void __user *arg = (void __user *)p;
int ioflags = 0;
int error;
if (filp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
xfs_itrace_entry(ip);
switch (cmd) {
/* No size or alignment issues on any arch */
case XFS_IOC_DIOINFO:
case XFS_IOC_FSGEOMETRY:
case XFS_IOC_FSGETXATTR:
@ -387,48 +628,18 @@ xfs_compat_ioctl(
case XFS_IOC_GETBMAP:
case XFS_IOC_GETBMAPA:
case XFS_IOC_GETBMAPX:
/* not handled
case XFS_IOC_FSSETDM_BY_HANDLE:
case XFS_IOC_ATTRLIST_BY_HANDLE:
case XFS_IOC_ATTRMULTI_BY_HANDLE:
*/
case XFS_IOC_FSCOUNTS:
case XFS_IOC_SET_RESBLKS:
case XFS_IOC_GET_RESBLKS:
case XFS_IOC_FSGROWFSDATA:
case XFS_IOC_FSGROWFSLOG:
case XFS_IOC_FSGROWFSRT:
case XFS_IOC_FREEZE:
case XFS_IOC_THAW:
case XFS_IOC_GOINGDOWN:
case XFS_IOC_ERROR_INJECTION:
case XFS_IOC_ERROR_CLEARALL:
break;
case XFS_IOC32_GETXFLAGS:
case XFS_IOC32_SETXFLAGS:
case XFS_IOC32_GETVERSION:
cmd = _NATIVE_IOC(cmd, long);
break;
#ifdef BROKEN_X86_ALIGNMENT
/* xfs_flock_t has wrong u32 vs u64 alignment */
case XFS_IOC_ALLOCSP_32:
case XFS_IOC_FREESP_32:
case XFS_IOC_ALLOCSP64_32:
case XFS_IOC_FREESP64_32:
case XFS_IOC_RESVSP_32:
case XFS_IOC_UNRESVSP_32:
case XFS_IOC_RESVSP64_32:
case XFS_IOC_UNRESVSP64_32:
arg = xfs_ioctl32_flock(arg);
cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
break;
case XFS_IOC_FSGEOMETRY_V1_32:
arg = xfs_ioctl32_geom_v1(arg);
cmd = _NATIVE_IOC(cmd, struct xfs_fsop_geom_v1);
break;
#else /* These are handled fine if no alignment issues */
return xfs_file_ioctl(filp, cmd, p);
#ifndef BROKEN_X86_ALIGNMENT
/* These are handled fine if no alignment issues */
case XFS_IOC_ALLOCSP:
case XFS_IOC_FREESP:
case XFS_IOC_RESVSP:
@ -438,51 +649,97 @@ xfs_compat_ioctl(
case XFS_IOC_RESVSP64:
case XFS_IOC_UNRESVSP64:
case XFS_IOC_FSGEOMETRY_V1:
break;
case XFS_IOC_FSGROWFSDATA:
case XFS_IOC_FSGROWFSRT:
return xfs_file_ioctl(filp, cmd, p);
#else
case XFS_IOC_ALLOCSP_32:
case XFS_IOC_FREESP_32:
case XFS_IOC_ALLOCSP64_32:
case XFS_IOC_FREESP64_32:
case XFS_IOC_RESVSP_32:
case XFS_IOC_UNRESVSP_32:
case XFS_IOC_RESVSP64_32:
case XFS_IOC_UNRESVSP64_32: {
struct xfs_flock64 bf;
/* xfs_bstat_t still has wrong u32 vs u64 alignment */
case XFS_IOC_SWAPEXT:
break;
if (xfs_compat_flock64_copyin(&bf, arg))
return -XFS_ERROR(EFAULT);
cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
return xfs_ioc_space(ip, inode, filp, ioflags, cmd, &bf);
}
case XFS_IOC_FSGEOMETRY_V1_32:
return xfs_compat_ioc_fsgeometry_v1(mp, arg);
case XFS_IOC_FSGROWFSDATA_32: {
struct xfs_growfs_data in;
if (xfs_compat_growfs_data_copyin(&in, arg))
return -XFS_ERROR(EFAULT);
error = xfs_growfs_data(mp, &in);
return -error;
}
case XFS_IOC_FSGROWFSRT_32: {
struct xfs_growfs_rt in;
if (xfs_compat_growfs_rt_copyin(&in, arg))
return -XFS_ERROR(EFAULT);
error = xfs_growfs_rt(mp, &in);
return -error;
}
#endif
/* long changes size, but xfs only copiese out 32 bits */
case XFS_IOC_GETXFLAGS_32:
case XFS_IOC_SETXFLAGS_32:
case XFS_IOC_GETVERSION_32:
cmd = _NATIVE_IOC(cmd, long);
return xfs_file_ioctl(filp, cmd, p);
case XFS_IOC_SWAPEXT: {
struct xfs_swapext sxp;
struct compat_xfs_swapext __user *sxu = arg;
/* Bulk copy in up to the sx_stat field, then copy bstat */
if (copy_from_user(&sxp, sxu,
offsetof(struct xfs_swapext, sx_stat)) ||
xfs_ioctl32_bstat_copyin(&sxp.sx_stat, &sxu->sx_stat))
return -XFS_ERROR(EFAULT);
error = xfs_swapext(&sxp);
return -error;
}
case XFS_IOC_FSBULKSTAT_32:
case XFS_IOC_FSBULKSTAT_SINGLE_32:
case XFS_IOC_FSINUMBERS_32:
cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq);
return xfs_ioc_bulkstat_compat(XFS_I(inode)->i_mount,
cmd, (void __user*)arg);
return xfs_compat_ioc_bulkstat(mp, cmd, arg);
case XFS_IOC_FD_TO_HANDLE_32:
case XFS_IOC_PATH_TO_HANDLE_32:
case XFS_IOC_PATH_TO_FSHANDLE_32:
case XFS_IOC_OPEN_BY_HANDLE_32:
case XFS_IOC_READLINK_BY_HANDLE_32:
arg = xfs_ioctl32_fshandle(arg);
case XFS_IOC_PATH_TO_FSHANDLE_32: {
struct xfs_fsop_handlereq hreq;
if (xfs_compat_handlereq_copyin(&hreq, arg))
return -XFS_ERROR(EFAULT);
cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq);
break;
default:
return -ENOIOCTLCMD;
return xfs_find_handle(cmd, &hreq);
}
case XFS_IOC_OPEN_BY_HANDLE_32: {
struct xfs_fsop_handlereq hreq;
error = xfs_ioctl(XFS_I(inode), file, mode, cmd, (void __user *)arg);
xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED);
if (xfs_compat_handlereq_copyin(&hreq, arg))
return -XFS_ERROR(EFAULT);
return xfs_open_by_handle(mp, &hreq, filp, inode);
}
case XFS_IOC_READLINK_BY_HANDLE_32: {
struct xfs_fsop_handlereq hreq;
return error;
}
long
xfs_file_compat_ioctl(
struct file *file,
unsigned cmd,
unsigned long arg)
{
return xfs_compat_ioctl(0, file, cmd, arg);
}
long
xfs_file_compat_invis_ioctl(
struct file *file,
unsigned cmd,
unsigned long arg)
{
return xfs_compat_ioctl(IO_INVIS, file, cmd, arg);
if (xfs_compat_handlereq_copyin(&hreq, arg))
return -XFS_ERROR(EFAULT);
return xfs_readlink_by_handle(mp, &hreq, inode);
}
case XFS_IOC_ATTRLIST_BY_HANDLE_32:
return xfs_compat_attrlist_by_handle(mp, arg, inode);
case XFS_IOC_ATTRMULTI_BY_HANDLE_32:
return xfs_compat_attrmulti_by_handle(mp, arg, inode);
case XFS_IOC_FSSETDM_BY_HANDLE_32:
return xfs_compat_fssetdm_by_handle(mp, arg, inode);
default:
return -XFS_ERROR(ENOIOCTLCMD);
}
}

View File

@ -18,7 +18,217 @@
#ifndef __XFS_IOCTL32_H__
#define __XFS_IOCTL32_H__
extern long xfs_file_compat_ioctl(struct file *, unsigned, unsigned long);
extern long xfs_file_compat_invis_ioctl(struct file *, unsigned, unsigned long);
#include <linux/compat.h>
/*
* on 32-bit arches, ioctl argument structures may have different sizes
* and/or alignment. We define compat structures which match the
* 32-bit sizes/alignments here, and their associated ioctl numbers.
*
* xfs_ioctl32.c contains routines to copy these structures in and out.
*/
/* stock kernel-level ioctls we support */
#define XFS_IOC_GETXFLAGS_32 FS_IOC32_GETFLAGS
#define XFS_IOC_SETXFLAGS_32 FS_IOC32_SETFLAGS
#define XFS_IOC_GETVERSION_32 FS_IOC32_GETVERSION
/*
* On intel, even if sizes match, alignment and/or padding may differ.
*/
#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
#define BROKEN_X86_ALIGNMENT
#define __compat_packed __attribute__((packed))
#else
#define __compat_packed
#endif
typedef struct compat_xfs_bstime {
compat_time_t tv_sec; /* seconds */
__s32 tv_nsec; /* and nanoseconds */
} compat_xfs_bstime_t;
typedef struct compat_xfs_bstat {
__u64 bs_ino; /* inode number */
__u16 bs_mode; /* type and mode */
__u16 bs_nlink; /* number of links */
__u32 bs_uid; /* user id */
__u32 bs_gid; /* group id */
__u32 bs_rdev; /* device value */
__s32 bs_blksize; /* block size */
__s64 bs_size; /* file size */
compat_xfs_bstime_t bs_atime; /* access time */
compat_xfs_bstime_t bs_mtime; /* modify time */
compat_xfs_bstime_t bs_ctime; /* inode change time */
int64_t bs_blocks; /* number of blocks */
__u32 bs_xflags; /* extended flags */
__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 */
__u32 bs_dmevmask; /* DMIG event mask */
__u16 bs_dmstate; /* DMIG state info */
__u16 bs_aextents; /* attribute number of extents */
} __compat_packed compat_xfs_bstat_t;
typedef struct compat_xfs_fsop_bulkreq {
compat_uptr_t lastip; /* last inode # pointer */
__s32 icount; /* count of entries in buffer */
compat_uptr_t ubuffer; /* user buffer for inode desc. */
compat_uptr_t ocount; /* output count pointer */
} compat_xfs_fsop_bulkreq_t;
#define XFS_IOC_FSBULKSTAT_32 \
_IOWR('X', 101, struct compat_xfs_fsop_bulkreq)
#define XFS_IOC_FSBULKSTAT_SINGLE_32 \
_IOWR('X', 102, struct compat_xfs_fsop_bulkreq)
#define XFS_IOC_FSINUMBERS_32 \
_IOWR('X', 103, struct compat_xfs_fsop_bulkreq)
typedef struct compat_xfs_fsop_handlereq {
__u32 fd; /* fd for FD_TO_HANDLE */
compat_uptr_t path; /* user pathname */
__u32 oflags; /* open flags */
compat_uptr_t ihandle; /* user supplied handle */
__u32 ihandlen; /* user supplied length */
compat_uptr_t ohandle; /* user buffer for handle */
compat_uptr_t ohandlen; /* user buffer length */
} compat_xfs_fsop_handlereq_t;
#define XFS_IOC_PATH_TO_FSHANDLE_32 \
_IOWR('X', 104, struct compat_xfs_fsop_handlereq)
#define XFS_IOC_PATH_TO_HANDLE_32 \
_IOWR('X', 105, struct compat_xfs_fsop_handlereq)
#define XFS_IOC_FD_TO_HANDLE_32 \
_IOWR('X', 106, struct compat_xfs_fsop_handlereq)
#define XFS_IOC_OPEN_BY_HANDLE_32 \
_IOWR('X', 107, struct compat_xfs_fsop_handlereq)
#define XFS_IOC_READLINK_BY_HANDLE_32 \
_IOWR('X', 108, struct compat_xfs_fsop_handlereq)
/* The bstat field in the swapext struct needs translation */
typedef struct compat_xfs_swapext {
__int64_t sx_version; /* version */
__int64_t sx_fdtarget; /* fd of target file */
__int64_t sx_fdtmp; /* fd of tmp file */
xfs_off_t sx_offset; /* offset into file */
xfs_off_t sx_length; /* leng from offset */
char sx_pad[16]; /* pad space, unused */
compat_xfs_bstat_t sx_stat; /* stat of target b4 copy */
} __compat_packed compat_xfs_swapext_t;
#define XFS_IOC_SWAPEXT_32 _IOWR('X', 109, struct compat_xfs_swapext)
typedef struct compat_xfs_fsop_attrlist_handlereq {
struct compat_xfs_fsop_handlereq hreq; /* handle interface structure */
struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
__u32 flags; /* which namespace to use */
__u32 buflen; /* length of buffer supplied */
compat_uptr_t buffer; /* returned names */
} __compat_packed compat_xfs_fsop_attrlist_handlereq_t;
/* Note: actually this is read/write */
#define XFS_IOC_ATTRLIST_BY_HANDLE_32 \
_IOW('X', 122, struct compat_xfs_fsop_attrlist_handlereq)
/* am_opcodes defined in xfs_fs.h */
typedef struct compat_xfs_attr_multiop {
__u32 am_opcode;
__s32 am_error;
compat_uptr_t am_attrname;
compat_uptr_t am_attrvalue;
__u32 am_length;
__u32 am_flags;
} compat_xfs_attr_multiop_t;
typedef struct compat_xfs_fsop_attrmulti_handlereq {
struct compat_xfs_fsop_handlereq hreq; /* handle interface structure */
__u32 opcount;/* count of following multiop */
/* ptr to compat_xfs_attr_multiop */
compat_uptr_t ops; /* attr_multi data */
} compat_xfs_fsop_attrmulti_handlereq_t;
#define XFS_IOC_ATTRMULTI_BY_HANDLE_32 \
_IOW('X', 123, struct compat_xfs_fsop_attrmulti_handlereq)
typedef struct compat_xfs_fsop_setdm_handlereq {
struct compat_xfs_fsop_handlereq hreq; /* handle information */
/* ptr to struct fsdmidata */
compat_uptr_t data; /* DMAPI data */
} compat_xfs_fsop_setdm_handlereq_t;
#define XFS_IOC_FSSETDM_BY_HANDLE_32 \
_IOW('X', 121, struct compat_xfs_fsop_setdm_handlereq)
#ifdef BROKEN_X86_ALIGNMENT
/* on ia32 l_start is on a 32-bit boundary */
typedef struct compat_xfs_flock64 {
__s16 l_type;
__s16 l_whence;
__s64 l_start __attribute__((packed));
/* len == 0 means until end of file */
__s64 l_len __attribute__((packed));
__s32 l_sysid;
__u32 l_pid;
__s32 l_pad[4]; /* reserve area */
} compat_xfs_flock64_t;
#define XFS_IOC_ALLOCSP_32 _IOW('X', 10, struct compat_xfs_flock64)
#define XFS_IOC_FREESP_32 _IOW('X', 11, struct compat_xfs_flock64)
#define XFS_IOC_ALLOCSP64_32 _IOW('X', 36, struct compat_xfs_flock64)
#define XFS_IOC_FREESP64_32 _IOW('X', 37, struct compat_xfs_flock64)
#define XFS_IOC_RESVSP_32 _IOW('X', 40, struct compat_xfs_flock64)
#define XFS_IOC_UNRESVSP_32 _IOW('X', 41, struct compat_xfs_flock64)
#define XFS_IOC_RESVSP64_32 _IOW('X', 42, struct compat_xfs_flock64)
#define XFS_IOC_UNRESVSP64_32 _IOW('X', 43, struct compat_xfs_flock64)
typedef struct compat_xfs_fsop_geom_v1 {
__u32 blocksize; /* filesystem (data) block size */
__u32 rtextsize; /* realtime extent size */
__u32 agblocks; /* fsblocks in an AG */
__u32 agcount; /* number of allocation groups */
__u32 logblocks; /* fsblocks in the log */
__u32 sectsize; /* (data) sector size, bytes */
__u32 inodesize; /* inode size in bytes */
__u32 imaxpct; /* max allowed inode space(%) */
__u64 datablocks; /* fsblocks in data subvolume */
__u64 rtblocks; /* fsblocks in realtime subvol */
__u64 rtextents; /* rt extents in realtime subvol*/
__u64 logstart; /* starting fsblock of the log */
unsigned char uuid[16]; /* unique id of the filesystem */
__u32 sunit; /* stripe unit, fsblocks */
__u32 swidth; /* stripe width, fsblocks */
__s32 version; /* structure version */
__u32 flags; /* superblock version flags */
__u32 logsectsize; /* log sector size, bytes */
__u32 rtsectsize; /* realtime sector size, bytes */
__u32 dirblocksize; /* directory block size, bytes */
} __attribute__((packed)) compat_xfs_fsop_geom_v1_t;
#define XFS_IOC_FSGEOMETRY_V1_32 \
_IOR('X', 100, struct compat_xfs_fsop_geom_v1)
typedef struct compat_xfs_inogrp {
__u64 xi_startino; /* starting inode number */
__s32 xi_alloccount; /* # bits set in allocmask */
__u64 xi_allocmask; /* mask of allocated inodes */
} __attribute__((packed)) compat_xfs_inogrp_t;
/* These growfs input structures have padding on the end, so must translate */
typedef struct compat_xfs_growfs_data {
__u64 newblocks; /* new data subvol size, fsblocks */
__u32 imaxpct; /* new inode space percentage limit */
} __attribute__((packed)) compat_xfs_growfs_data_t;
typedef struct compat_xfs_growfs_rt {
__u64 newblocks; /* new realtime size, fsblocks */
__u32 extsize; /* new realtime extent size, fsblocks */
} __attribute__((packed)) compat_xfs_growfs_rt_t;
#define XFS_IOC_FSGROWFSDATA_32 _IOW('X', 110, struct compat_xfs_growfs_data)
#define XFS_IOC_FSGROWFSRT_32 _IOW('X', 112, struct compat_xfs_growfs_rt)
#endif /* BROKEN_X86_ALIGNMENT */
#endif /* __XFS_IOCTL32_H__ */

View File

@ -53,6 +53,7 @@
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/falloc.h>
#include <linux/fiemap.h>
/*
* Bring the atime in the XFS inode uptodate.
@ -64,14 +65,14 @@ xfs_synchronize_atime(
{
struct inode *inode = VFS_I(ip);
if (inode) {
if (!(inode->i_state & I_CLEAR)) {
ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
}
}
/*
* If the linux inode exists, mark it dirty.
* If the linux inode is valid, mark it dirty.
* Used when commiting a dirty inode into a transaction so that
* the inode will get written back by the linux code
*/
@ -81,7 +82,7 @@ xfs_mark_inode_dirty_sync(
{
struct inode *inode = VFS_I(ip);
if (inode)
if (!(inode->i_state & (I_WILL_FREE|I_FREEING|I_CLEAR)))
mark_inode_dirty_sync(inode);
}
@ -128,7 +129,7 @@ xfs_ichgtime(
if (sync_it) {
SYNCHRONIZE();
ip->i_update_core = 1;
mark_inode_dirty_sync(inode);
xfs_mark_inode_dirty_sync(ip);
}
}
@ -158,8 +159,6 @@ xfs_init_security(
}
error = xfs_attr_set(ip, name, value, length, ATTR_SECURE);
if (!error)
xfs_iflags_set(ip, XFS_IMODIFIED);
kfree(name);
kfree(value);
@ -260,7 +259,6 @@ xfs_vn_mknod(
error = _ACL_INHERIT(inode, mode, default_acl);
if (unlikely(error))
goto out_cleanup_inode;
xfs_iflags_set(ip, XFS_IMODIFIED);
_ACL_FREE(default_acl);
}
@ -366,21 +364,17 @@ xfs_vn_link(
struct inode *dir,
struct dentry *dentry)
{
struct inode *inode; /* inode of guy being linked to */
struct inode *inode = old_dentry->d_inode;
struct xfs_name name;
int error;
inode = old_dentry->d_inode;
xfs_dentry_to_name(&name, dentry);
igrab(inode);
error = xfs_link(XFS_I(dir), XFS_I(inode), &name);
if (unlikely(error)) {
iput(inode);
if (unlikely(error))
return -error;
}
xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED);
atomic_inc(&inode->i_count);
d_instantiate(dentry, inode);
return 0;
}
@ -601,7 +595,7 @@ xfs_vn_setattr(
struct dentry *dentry,
struct iattr *iattr)
{
return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0, NULL);
return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0);
}
/*
@ -642,7 +636,7 @@ xfs_vn_fallocate(
xfs_ilock(ip, XFS_IOLOCK_EXCL);
error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf,
0, NULL, XFS_ATTR_NOLOCK);
0, XFS_ATTR_NOLOCK);
if (!error && !(mode & FALLOC_FL_KEEP_SIZE) &&
offset + len > i_size_read(inode))
new_size = offset + len;
@ -653,7 +647,7 @@ xfs_vn_fallocate(
iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = new_size;
error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK, NULL);
error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK);
}
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
@ -661,6 +655,88 @@ out_error:
return error;
}
#define XFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
/*
* Call fiemap helper to fill in user data.
* Returns positive errors to xfs_getbmap.
*/
STATIC int
xfs_fiemap_format(
void **arg,
struct getbmapx *bmv,
int *full)
{
int error;
struct fiemap_extent_info *fieinfo = *arg;
u32 fiemap_flags = 0;
u64 logical, physical, length;
/* Do nothing for a hole */
if (bmv->bmv_block == -1LL)
return 0;
logical = BBTOB(bmv->bmv_offset);
physical = BBTOB(bmv->bmv_block);
length = BBTOB(bmv->bmv_length);
if (bmv->bmv_oflags & BMV_OF_PREALLOC)
fiemap_flags |= FIEMAP_EXTENT_UNWRITTEN;
else if (bmv->bmv_oflags & BMV_OF_DELALLOC) {
fiemap_flags |= FIEMAP_EXTENT_DELALLOC;
physical = 0; /* no block yet */
}
if (bmv->bmv_oflags & BMV_OF_LAST)
fiemap_flags |= FIEMAP_EXTENT_LAST;
error = fiemap_fill_next_extent(fieinfo, logical, physical,
length, fiemap_flags);
if (error > 0) {
error = 0;
*full = 1; /* user array now full */
}
return -error;
}
STATIC int
xfs_vn_fiemap(
struct inode *inode,
struct fiemap_extent_info *fieinfo,
u64 start,
u64 length)
{
xfs_inode_t *ip = XFS_I(inode);
struct getbmapx bm;
int error;
error = fiemap_check_flags(fieinfo, XFS_FIEMAP_FLAGS);
if (error)
return error;
/* Set up bmap header for xfs internal routine */
bm.bmv_offset = BTOBB(start);
/* Special case for whole file */
if (length == FIEMAP_MAX_OFFSET)
bm.bmv_length = -1LL;
else
bm.bmv_length = BTOBB(length);
/* our formatter will tell xfs_getbmap when to stop. */
bm.bmv_count = MAXEXTNUM;
bm.bmv_iflags = BMV_IF_PREALLOC;
if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR)
bm.bmv_iflags |= BMV_IF_ATTRFORK;
if (!(fieinfo->fi_flags & FIEMAP_FLAG_SYNC))
bm.bmv_iflags |= BMV_IF_DELALLOC;
error = xfs_getbmap(ip, &bm, xfs_fiemap_format, fieinfo);
if (error)
return -error;
return 0;
}
static const struct inode_operations xfs_inode_operations = {
.permission = xfs_vn_permission,
.truncate = xfs_vn_truncate,
@ -671,6 +747,7 @@ static const struct inode_operations xfs_inode_operations = {
.removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
.fallocate = xfs_vn_fallocate,
.fiemap = xfs_vn_fiemap,
};
static const struct inode_operations xfs_dir_inode_operations = {
@ -766,12 +843,20 @@ xfs_diflags_to_iflags(
* When reading existing inodes from disk this is called directly
* from xfs_iget, when creating a new inode it is called from
* xfs_ialloc after setting up the inode.
*
* We are always called with an uninitialised linux inode here.
* We need to initialise the necessary fields and take a reference
* on it.
*/
void
xfs_setup_inode(
struct xfs_inode *ip)
{
struct inode *inode = ip->i_vnode;
struct inode *inode = &ip->i_vnode;
inode->i_ino = ip->i_ino;
inode->i_state = I_NEW|I_LOCK;
inode_add_to_lists(ip->i_mount->m_super, inode);
inode->i_mode = ip->i_d.di_mode;
inode->i_nlink = ip->i_d.di_nlink;
@ -799,7 +884,6 @@ xfs_setup_inode(
inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec;
inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec;
xfs_diflags_to_iflags(inode, ip);
xfs_iflags_clear(ip, XFS_IMODIFIED);
switch (inode->i_mode & S_IFMT) {
case S_IFREG:

View File

@ -22,7 +22,6 @@ struct xfs_inode;
extern const struct file_operations xfs_file_operations;
extern const struct file_operations xfs_dir_file_operations;
extern const struct file_operations xfs_invis_file_operations;
extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);

View File

@ -21,18 +21,12 @@
#include <linux/types.h>
/*
* Some types are conditional depending on the target system.
* XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits.
* XFS_BIG_INUMS needs the VFS inode number to be 64 bits, as well
* as requiring XFS_BIG_BLKNOS to be set.
* XFS_BIG_INUMS requires XFS_BIG_BLKNOS to be set.
*/
#if defined(CONFIG_LBD) || (BITS_PER_LONG == 64)
# define XFS_BIG_BLKNOS 1
# if BITS_PER_LONG == 64
# define XFS_BIG_INUMS 1
# else
# define XFS_BIG_INUMS 0
# endif
# define XFS_BIG_INUMS 1
#else
# define XFS_BIG_BLKNOS 0
# define XFS_BIG_INUMS 0
@ -77,6 +71,7 @@
#include <linux/spinlock.h>
#include <linux/random.h>
#include <linux/ctype.h>
#include <linux/writeback.h>
#include <asm/page.h>
#include <asm/div64.h>
@ -85,7 +80,6 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <xfs_vfs.h>
#include <xfs_cred.h>
#include <xfs_vnode.h>
#include <xfs_stats.h>
@ -107,7 +101,6 @@
#undef HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */
#endif
#define restricted_chown xfs_params.restrict_chown.val
#define irix_sgid_inherit xfs_params.sgid_inherit.val
#define irix_symlink_mode xfs_params.symlink_mode.val
#define xfs_panic_mask xfs_params.panic_mask.val

View File

@ -51,7 +51,6 @@
#include "xfs_vnodeops.h"
#include <linux/capability.h>
#include <linux/mount.h>
#include <linux/writeback.h>
@ -243,7 +242,7 @@ xfs_read(
if (unlikely(ioflags & IO_ISDIRECT)) {
if (inode->i_mapping->nrpages)
ret = xfs_flushinval_pages(ip, (*offset & PAGE_CACHE_MASK),
ret = -xfs_flushinval_pages(ip, (*offset & PAGE_CACHE_MASK),
-1, FI_REMAPF_LOCKED);
mutex_unlock(&inode->i_mutex);
if (ret) {
@ -668,15 +667,8 @@ start:
if (new_size > xip->i_size)
xip->i_new_size = new_size;
/*
* We're not supposed to change timestamps in readonly-mounted
* filesystems. Throw it away if anyone asks us.
*/
if (likely(!(ioflags & IO_INVIS) &&
!mnt_want_write(file->f_path.mnt))) {
if (likely(!(ioflags & IO_INVIS)))
xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
mnt_drop_write(file->f_path.mnt);
}
/*
* If the offset is beyond the size of the file, we have a couple
@ -715,7 +707,6 @@ start:
}
}
retry:
/* We can write back this queue in page reclaim */
current->backing_dev_info = mapping->backing_dev_info;
@ -771,6 +762,17 @@ retry:
if (ret == -EIOCBQUEUED && !(ioflags & IO_ISAIO))
ret = wait_on_sync_kiocb(iocb);
isize = i_size_read(inode);
if (unlikely(ret < 0 && ret != -EFAULT && *offset > isize))
*offset = isize;
if (*offset > xip->i_size) {
xfs_ilock(xip, XFS_ILOCK_EXCL);
if (*offset > xip->i_size)
xip->i_size = *offset;
xfs_iunlock(xip, XFS_ILOCK_EXCL);
}
if (ret == -ENOSPC &&
DM_EVENT_ENABLED(xip, DM_EVENT_NOSPACE) && !(ioflags & IO_INVIS)) {
xfs_iunlock(xip, iolock);
@ -784,20 +786,7 @@ retry:
xfs_ilock(xip, iolock);
if (error)
goto out_unlock_internal;
pos = xip->i_size;
ret = 0;
goto retry;
}
isize = i_size_read(inode);
if (unlikely(ret < 0 && ret != -EFAULT && *offset > isize))
*offset = isize;
if (*offset > xip->i_size) {
xfs_ilock(xip, XFS_ILOCK_EXCL);
if (*offset > xip->i_size)
xip->i_size = *offset;
xfs_iunlock(xip, XFS_ILOCK_EXCL);
goto start;
}
error = -ret;
@ -855,13 +844,7 @@ retry:
int
xfs_bdstrat_cb(struct xfs_buf *bp)
{
xfs_mount_t *mp;
mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *);
if (!XFS_FORCED_SHUTDOWN(mp)) {
xfs_buf_iorequest(bp);
return 0;
} else {
if (XFS_FORCED_SHUTDOWN(bp->b_mount)) {
xfs_buftrace("XFS__BDSTRAT IOERROR", bp);
/*
* Metadata write that didn't get logged but
@ -874,6 +857,9 @@ xfs_bdstrat_cb(struct xfs_buf *bp)
else
return (xfs_bioerror(bp));
}
xfs_buf_iorequest(bp);
return 0;
}
/*

View File

@ -53,11 +53,15 @@ xfs_read_xfsstats(
{ "icluster", XFSSTAT_END_INODE_CLUSTER },
{ "vnodes", XFSSTAT_END_VNODE_OPS },
{ "buf", XFSSTAT_END_BUF },
{ "abtb2", XFSSTAT_END_ABTB_V2 },
{ "abtc2", XFSSTAT_END_ABTC_V2 },
{ "bmbt2", XFSSTAT_END_BMBT_V2 },
{ "ibt2", XFSSTAT_END_IBT_V2 },
};
/* Loop over all stats groups */
for (i=j=len = 0; i < ARRAY_SIZE(xstats); i++) {
len += sprintf(buffer + len, xstats[i].desc);
len += sprintf(buffer + len, "%s", xstats[i].desc);
/* inner loop does each group */
while (j < xstats[i].endpoint) {
val = 0;

View File

@ -118,6 +118,71 @@ struct xfsstats {
__uint32_t xb_page_retries;
__uint32_t xb_page_found;
__uint32_t xb_get_read;
/* Version 2 btree counters */
#define XFSSTAT_END_ABTB_V2 (XFSSTAT_END_BUF+15)
__uint32_t xs_abtb_2_lookup;
__uint32_t xs_abtb_2_compare;
__uint32_t xs_abtb_2_insrec;
__uint32_t xs_abtb_2_delrec;
__uint32_t xs_abtb_2_newroot;
__uint32_t xs_abtb_2_killroot;
__uint32_t xs_abtb_2_increment;
__uint32_t xs_abtb_2_decrement;
__uint32_t xs_abtb_2_lshift;
__uint32_t xs_abtb_2_rshift;
__uint32_t xs_abtb_2_split;
__uint32_t xs_abtb_2_join;
__uint32_t xs_abtb_2_alloc;
__uint32_t xs_abtb_2_free;
__uint32_t xs_abtb_2_moves;
#define XFSSTAT_END_ABTC_V2 (XFSSTAT_END_ABTB_V2+15)
__uint32_t xs_abtc_2_lookup;
__uint32_t xs_abtc_2_compare;
__uint32_t xs_abtc_2_insrec;
__uint32_t xs_abtc_2_delrec;
__uint32_t xs_abtc_2_newroot;
__uint32_t xs_abtc_2_killroot;
__uint32_t xs_abtc_2_increment;
__uint32_t xs_abtc_2_decrement;
__uint32_t xs_abtc_2_lshift;
__uint32_t xs_abtc_2_rshift;
__uint32_t xs_abtc_2_split;
__uint32_t xs_abtc_2_join;
__uint32_t xs_abtc_2_alloc;
__uint32_t xs_abtc_2_free;
__uint32_t xs_abtc_2_moves;
#define XFSSTAT_END_BMBT_V2 (XFSSTAT_END_ABTC_V2+15)
__uint32_t xs_bmbt_2_lookup;
__uint32_t xs_bmbt_2_compare;
__uint32_t xs_bmbt_2_insrec;
__uint32_t xs_bmbt_2_delrec;
__uint32_t xs_bmbt_2_newroot;
__uint32_t xs_bmbt_2_killroot;
__uint32_t xs_bmbt_2_increment;
__uint32_t xs_bmbt_2_decrement;
__uint32_t xs_bmbt_2_lshift;
__uint32_t xs_bmbt_2_rshift;
__uint32_t xs_bmbt_2_split;
__uint32_t xs_bmbt_2_join;
__uint32_t xs_bmbt_2_alloc;
__uint32_t xs_bmbt_2_free;
__uint32_t xs_bmbt_2_moves;
#define XFSSTAT_END_IBT_V2 (XFSSTAT_END_BMBT_V2+15)
__uint32_t xs_ibt_2_lookup;
__uint32_t xs_ibt_2_compare;
__uint32_t xs_ibt_2_insrec;
__uint32_t xs_ibt_2_delrec;
__uint32_t xs_ibt_2_newroot;
__uint32_t xs_ibt_2_killroot;
__uint32_t xs_ibt_2_increment;
__uint32_t xs_ibt_2_decrement;
__uint32_t xs_ibt_2_lshift;
__uint32_t xs_ibt_2_rshift;
__uint32_t xs_ibt_2_split;
__uint32_t xs_ibt_2_join;
__uint32_t xs_ibt_2_alloc;
__uint32_t xs_ibt_2_free;
__uint32_t xs_ibt_2_moves;
/* Extra precision counters */
__uint64_t xs_xstrat_bytes;
__uint64_t xs_write_bytes;

File diff suppressed because it is too large Load Diff

View File

@ -20,24 +20,12 @@
#include <linux/exportfs.h>
#ifdef CONFIG_XFS_DMAPI
# define vfs_insertdmapi(vfs) vfs_insertops(vfsp, &xfs_dmops)
# define vfs_initdmapi() dmapi_init()
# define vfs_exitdmapi() dmapi_uninit()
#else
# define vfs_insertdmapi(vfs) do { } while (0)
# define vfs_initdmapi() do { } while (0)
# define vfs_exitdmapi() do { } while (0)
#endif
#ifdef CONFIG_XFS_QUOTA
# define vfs_insertquota(vfs) vfs_insertops(vfsp, &xfs_qmops)
extern void xfs_qm_init(void);
extern void xfs_qm_exit(void);
# define vfs_initquota() xfs_qm_init()
# define vfs_exitquota() xfs_qm_exit()
#else
# define vfs_insertquota(vfs) do { } while (0)
# define vfs_initquota() do { } while (0)
# define vfs_exitquota() do { } while (0)
#endif
@ -101,9 +89,6 @@ struct block_device;
extern __uint64_t xfs_max_file_offset(unsigned int);
extern void xfs_flush_inode(struct xfs_inode *);
extern void xfs_flush_device(struct xfs_inode *);
extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
extern const struct export_operations xfs_export_operations;

762
fs/xfs/linux-2.6/xfs_sync.c Normal file
View File

@ -0,0 +1,762 @@
/*
* Copyright (c) 2000-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
*/
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
#include "xfs_btree.h"
#include "xfs_dir2_sf.h"
#include "xfs_attr_sf.h"
#include "xfs_inode.h"
#include "xfs_dinode.h"
#include "xfs_error.h"
#include "xfs_mru_cache.h"
#include "xfs_filestream.h"
#include "xfs_vnodeops.h"
#include "xfs_utils.h"
#include "xfs_buf_item.h"
#include "xfs_inode_item.h"
#include "xfs_rw.h"
#include <linux/kthread.h>
#include <linux/freezer.h>
/*
* Sync all the inodes in the given AG according to the
* direction given by the flags.
*/
STATIC int
xfs_sync_inodes_ag(
xfs_mount_t *mp,
int ag,
int flags)
{
xfs_perag_t *pag = &mp->m_perag[ag];
int nr_found;
uint32_t first_index = 0;
int error = 0;
int last_error = 0;
int fflag = XFS_B_ASYNC;
if (flags & SYNC_DELWRI)
fflag = XFS_B_DELWRI;
if (flags & SYNC_WAIT)
fflag = 0; /* synchronous overrides all */
do {
struct inode *inode;
xfs_inode_t *ip = NULL;
int lock_flags = XFS_ILOCK_SHARED;
/*
* 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.
*/
read_lock(&pag->pag_ici_lock);
nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
(void**)&ip, first_index, 1);
if (!nr_found) {
read_unlock(&pag->pag_ici_lock);
break;
}
/*
* 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)) {
read_unlock(&pag->pag_ici_lock);
break;
}
/* nothing to sync during shutdown */
if (XFS_FORCED_SHUTDOWN(mp)) {
read_unlock(&pag->pag_ici_lock);
return 0;
}
/*
* If we can't get a reference on the inode, it must be
* in reclaim. Leave it for the reclaim code to flush.
*/
inode = VFS_I(ip);
if (!igrab(inode)) {
read_unlock(&pag->pag_ici_lock);
continue;
}
read_unlock(&pag->pag_ici_lock);
/* avoid new or bad inodes */
if (is_bad_inode(inode) ||
xfs_iflags_test(ip, XFS_INEW)) {
IRELE(ip);
continue;
}
/*
* If we have to flush data or wait for I/O completion
* we need to hold the iolock.
*/
if ((flags & SYNC_DELWRI) && VN_DIRTY(inode)) {
xfs_ilock(ip, XFS_IOLOCK_SHARED);
lock_flags |= XFS_IOLOCK_SHARED;
error = xfs_flush_pages(ip, 0, -1, fflag, FI_NONE);
if (flags & SYNC_IOWAIT)
xfs_ioend_wait(ip);
}
xfs_ilock(ip, XFS_ILOCK_SHARED);
if ((flags & SYNC_ATTR) && !xfs_inode_clean(ip)) {
if (flags & SYNC_WAIT) {
xfs_iflock(ip);
if (!xfs_inode_clean(ip))
error = xfs_iflush(ip, XFS_IFLUSH_SYNC);
else
xfs_ifunlock(ip);
} else if (xfs_iflock_nowait(ip)) {
if (!xfs_inode_clean(ip))
error = xfs_iflush(ip, XFS_IFLUSH_DELWRI);
else
xfs_ifunlock(ip);
}
}
xfs_iput(ip, lock_flags);
if (error)
last_error = error;
/*
* bail out if the filesystem is corrupted.
*/
if (error == EFSCORRUPTED)
return XFS_ERROR(error);
} while (nr_found);
return last_error;
}
int
xfs_sync_inodes(
xfs_mount_t *mp,
int flags)
{
int error;
int last_error;
int i;
int lflags = XFS_LOG_FORCE;
if (mp->m_flags & XFS_MOUNT_RDONLY)
return 0;
error = 0;
last_error = 0;
if (flags & SYNC_WAIT)
lflags |= XFS_LOG_SYNC;
for (i = 0; i < mp->m_sb.sb_agcount; i++) {
if (!mp->m_perag[i].pag_ici_init)
continue;
error = xfs_sync_inodes_ag(mp, i, flags);
if (error)
last_error = error;
if (error == EFSCORRUPTED)
break;
}
if (flags & SYNC_DELWRI)
xfs_log_force(mp, 0, lflags);
return XFS_ERROR(last_error);
}
STATIC int
xfs_commit_dummy_trans(
struct xfs_mount *mp,
uint log_flags)
{
struct xfs_inode *ip = mp->m_rootip;
struct xfs_trans *tp;
int error;
/*
* Put a dummy transaction in the log to tell recovery
* that all others are OK.
*/
tp = xfs_trans_alloc(mp, XFS_TRANS_DUMMY1);
error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
if (error) {
xfs_trans_cancel(tp, 0);
return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_ihold(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
/* XXX(hch): ignoring the error here.. */
error = xfs_trans_commit(tp, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_log_force(mp, 0, log_flags);
return 0;
}
int
xfs_sync_fsdata(
struct xfs_mount *mp,
int flags)
{
struct xfs_buf *bp;
struct xfs_buf_log_item *bip;
int error = 0;
/*
* If this is xfssyncd() then only sync the superblock if we can
* lock it without sleeping and it is not pinned.
*/
if (flags & SYNC_BDFLUSH) {
ASSERT(!(flags & SYNC_WAIT));
bp = xfs_getsb(mp, XFS_BUF_TRYLOCK);
if (!bp)
goto out;
bip = XFS_BUF_FSPRIVATE(bp, struct xfs_buf_log_item *);
if (!bip || !xfs_buf_item_dirty(bip) || XFS_BUF_ISPINNED(bp))
goto out_brelse;
} else {
bp = xfs_getsb(mp, 0);
/*
* If the buffer is pinned then push on the log so we won't
* get stuck waiting in the write for someone, maybe
* ourselves, to flush the log.
*
* Even though we just pushed the log above, we did not have
* the superblock buffer locked at that point so it can
* become pinned in between there and here.
*/
if (XFS_BUF_ISPINNED(bp))
xfs_log_force(mp, 0, XFS_LOG_FORCE);
}
if (flags & SYNC_WAIT)
XFS_BUF_UNASYNC(bp);
else
XFS_BUF_ASYNC(bp);
return xfs_bwrite(mp, bp);
out_brelse:
xfs_buf_relse(bp);
out:
return error;
}
/*
* When remounting a filesystem read-only or freezing the filesystem, we have
* two phases to execute. This first phase is syncing the data before we
* quiesce the filesystem, and the second is flushing all the inodes out after
* we've waited for all the transactions created by the first phase to
* complete. The second phase ensures that the inodes are written to their
* location on disk rather than just existing in transactions in the log. This
* means after a quiesce there is no log replay required to write the inodes to
* disk (this is the main difference between a sync and a quiesce).
*/
/*
* First stage of freeze - no writers will make progress now we are here,
* so we flush delwri and delalloc buffers here, then wait for all I/O to
* complete. Data is frozen at that point. Metadata is not frozen,
* transactions can still occur here so don't bother flushing the buftarg
* because it'll just get dirty again.
*/
int
xfs_quiesce_data(
struct xfs_mount *mp)
{
int error;
/* push non-blocking */
xfs_sync_inodes(mp, SYNC_DELWRI|SYNC_BDFLUSH);
XFS_QM_DQSYNC(mp, SYNC_BDFLUSH);
xfs_filestream_flush(mp);
/* push and block */
xfs_sync_inodes(mp, SYNC_DELWRI|SYNC_WAIT|SYNC_IOWAIT);
XFS_QM_DQSYNC(mp, SYNC_WAIT);
/* write superblock and hoover up shutdown errors */
error = xfs_sync_fsdata(mp, 0);
/* flush data-only devices */
if (mp->m_rtdev_targp)
XFS_bflush(mp->m_rtdev_targp);
return error;
}
STATIC void
xfs_quiesce_fs(
struct xfs_mount *mp)
{
int count = 0, pincount;
xfs_flush_buftarg(mp->m_ddev_targp, 0);
xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
/*
* This loop must run at least twice. The first instance of the loop
* will flush most meta data but that will generate more meta data
* (typically directory updates). Which then must be flushed and
* logged before we can write the unmount record.
*/
do {
xfs_sync_inodes(mp, SYNC_ATTR|SYNC_WAIT);
pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
if (!pincount) {
delay(50);
count++;
}
} while (count < 2);
}
/*
* Second stage of a quiesce. The data is already synced, now we have to take
* care of the metadata. New transactions are already blocked, so we need to
* wait for any remaining transactions to drain out before proceding.
*/
void
xfs_quiesce_attr(
struct xfs_mount *mp)
{
int error = 0;
/* wait for all modifications to complete */
while (atomic_read(&mp->m_active_trans) > 0)
delay(100);
/* flush inodes and push all remaining buffers out to disk */
xfs_quiesce_fs(mp);
ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0);
/* Push the superblock and write an unmount record */
error = xfs_log_sbcount(mp, 1);
if (error)
xfs_fs_cmn_err(CE_WARN, mp,
"xfs_attr_quiesce: failed to log sb changes. "
"Frozen image may not be consistent.");
xfs_log_unmount_write(mp);
xfs_unmountfs_writesb(mp);
}
/*
* Enqueue a work item to be picked up by the vfs xfssyncd thread.
* Doing this has two advantages:
* - It saves on stack space, which is tight in certain situations
* - It can be used (with care) as a mechanism to avoid deadlocks.
* Flushing while allocating in a full filesystem requires both.
*/
STATIC void
xfs_syncd_queue_work(
struct xfs_mount *mp,
void *data,
void (*syncer)(struct xfs_mount *, void *))
{
struct bhv_vfs_sync_work *work;
work = kmem_alloc(sizeof(struct bhv_vfs_sync_work), KM_SLEEP);
INIT_LIST_HEAD(&work->w_list);
work->w_syncer = syncer;
work->w_data = data;
work->w_mount = mp;
spin_lock(&mp->m_sync_lock);
list_add_tail(&work->w_list, &mp->m_sync_list);
spin_unlock(&mp->m_sync_lock);
wake_up_process(mp->m_sync_task);
}
/*
* Flush delayed allocate data, attempting to free up reserved space
* from existing allocations. At this point a new allocation attempt
* has failed with ENOSPC and we are in the process of scratching our
* heads, looking about for more room...
*/
STATIC void
xfs_flush_inode_work(
struct xfs_mount *mp,
void *arg)
{
struct inode *inode = arg;
filemap_flush(inode->i_mapping);
iput(inode);
}
void
xfs_flush_inode(
xfs_inode_t *ip)
{
struct inode *inode = VFS_I(ip);
igrab(inode);
xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inode_work);
delay(msecs_to_jiffies(500));
}
/*
* This is the "bigger hammer" version of xfs_flush_inode_work...
* (IOW, "If at first you don't succeed, use a Bigger Hammer").
*/
STATIC void
xfs_flush_device_work(
struct xfs_mount *mp,
void *arg)
{
struct inode *inode = arg;
sync_blockdev(mp->m_super->s_bdev);
iput(inode);
}
void
xfs_flush_device(
xfs_inode_t *ip)
{
struct inode *inode = VFS_I(ip);
igrab(inode);
xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_device_work);
delay(msecs_to_jiffies(500));
xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
}
/*
* Every sync period we need to unpin all items, reclaim inodes, sync
* quota and write out the superblock. We might need to cover the log
* to indicate it is idle.
*/
STATIC void
xfs_sync_worker(
struct xfs_mount *mp,
void *unused)
{
int error;
if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_DELWRI_ELSE_ASYNC);
/* dgc: errors ignored here */
error = XFS_QM_DQSYNC(mp, SYNC_BDFLUSH);
error = xfs_sync_fsdata(mp, SYNC_BDFLUSH);
if (xfs_log_need_covered(mp))
error = xfs_commit_dummy_trans(mp, XFS_LOG_FORCE);
}
mp->m_sync_seq++;
wake_up(&mp->m_wait_single_sync_task);
}
STATIC int
xfssyncd(
void *arg)
{
struct xfs_mount *mp = arg;
long timeleft;
bhv_vfs_sync_work_t *work, *n;
LIST_HEAD (tmp);
set_freezable();
timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10);
for (;;) {
timeleft = schedule_timeout_interruptible(timeleft);
/* swsusp */
try_to_freeze();
if (kthread_should_stop() && list_empty(&mp->m_sync_list))
break;
spin_lock(&mp->m_sync_lock);
/*
* We can get woken by laptop mode, to do a sync -
* that's the (only!) case where the list would be
* empty with time remaining.
*/
if (!timeleft || list_empty(&mp->m_sync_list)) {
if (!timeleft)
timeleft = xfs_syncd_centisecs *
msecs_to_jiffies(10);
INIT_LIST_HEAD(&mp->m_sync_work.w_list);
list_add_tail(&mp->m_sync_work.w_list,
&mp->m_sync_list);
}
list_for_each_entry_safe(work, n, &mp->m_sync_list, w_list)
list_move(&work->w_list, &tmp);
spin_unlock(&mp->m_sync_lock);
list_for_each_entry_safe(work, n, &tmp, w_list) {
(*work->w_syncer)(mp, work->w_data);
list_del(&work->w_list);
if (work == &mp->m_sync_work)
continue;
kmem_free(work);
}
}
return 0;
}
int
xfs_syncd_init(
struct xfs_mount *mp)
{
mp->m_sync_work.w_syncer = xfs_sync_worker;
mp->m_sync_work.w_mount = mp;
mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd");
if (IS_ERR(mp->m_sync_task))
return -PTR_ERR(mp->m_sync_task);
return 0;
}
void
xfs_syncd_stop(
struct xfs_mount *mp)
{
kthread_stop(mp->m_sync_task);
}
int
xfs_reclaim_inode(
xfs_inode_t *ip,
int locked,
int sync_mode)
{
xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino);
/* The hash lock here protects a thread in xfs_iget_core from
* racing with us on linking the inode back with a vnode.
* Once we have the XFS_IRECLAIM flag set it will not touch
* us.
*/
write_lock(&pag->pag_ici_lock);
spin_lock(&ip->i_flags_lock);
if (__xfs_iflags_test(ip, XFS_IRECLAIM) ||
!__xfs_iflags_test(ip, XFS_IRECLAIMABLE)) {
spin_unlock(&ip->i_flags_lock);
write_unlock(&pag->pag_ici_lock);
if (locked) {
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
return 1;
}
__xfs_iflags_set(ip, XFS_IRECLAIM);
spin_unlock(&ip->i_flags_lock);
write_unlock(&pag->pag_ici_lock);
xfs_put_perag(ip->i_mount, pag);
/*
* If the inode is still dirty, then flush it out. If the inode
* is not in the AIL, then it will be OK to flush it delwri as
* long as xfs_iflush() does not keep any references to the inode.
* We leave that decision up to xfs_iflush() since it has the
* knowledge of whether it's OK to simply do a delwri flush of
* the inode or whether we need to wait until the inode is
* pulled from the AIL.
* We get the flush lock regardless, though, just to make sure
* we don't free it while it is being flushed.
*/
if (!locked) {
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_iflock(ip);
}
/*
* In the case of a forced shutdown we rely on xfs_iflush() to
* wait for the inode to be unpinned before returning an error.
*/
if (!is_bad_inode(VFS_I(ip)) && xfs_iflush(ip, sync_mode) == 0) {
/* synchronize with xfs_iflush_done */
xfs_iflock(ip);
xfs_ifunlock(ip);
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_ireclaim(ip);
return 0;
}
/*
* We set the inode flag atomically with the radix tree tag.
* Once we get tag lookups on the radix tree, this inode flag
* can go away.
*/
void
xfs_inode_set_reclaim_tag(
xfs_inode_t *ip)
{
xfs_mount_t *mp = ip->i_mount;
xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino);
read_lock(&pag->pag_ici_lock);
spin_lock(&ip->i_flags_lock);
radix_tree_tag_set(&pag->pag_ici_root,
XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
__xfs_iflags_set(ip, XFS_IRECLAIMABLE);
spin_unlock(&ip->i_flags_lock);
read_unlock(&pag->pag_ici_lock);
xfs_put_perag(mp, pag);
}
void
__xfs_inode_clear_reclaim_tag(
xfs_mount_t *mp,
xfs_perag_t *pag,
xfs_inode_t *ip)
{
radix_tree_tag_clear(&pag->pag_ici_root,
XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
}
void
xfs_inode_clear_reclaim_tag(
xfs_inode_t *ip)
{
xfs_mount_t *mp = ip->i_mount;
xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino);
read_lock(&pag->pag_ici_lock);
spin_lock(&ip->i_flags_lock);
__xfs_inode_clear_reclaim_tag(mp, pag, ip);
spin_unlock(&ip->i_flags_lock);
read_unlock(&pag->pag_ici_lock);
xfs_put_perag(mp, pag);
}
STATIC void
xfs_reclaim_inodes_ag(
xfs_mount_t *mp,
int ag,
int noblock,
int mode)
{
xfs_inode_t *ip = NULL;
xfs_perag_t *pag = &mp->m_perag[ag];
int nr_found;
uint32_t first_index;
int skipped;
restart:
first_index = 0;
skipped = 0;
do {
/*
* 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.
*/
read_lock(&pag->pag_ici_lock);
nr_found = radix_tree_gang_lookup_tag(&pag->pag_ici_root,
(void**)&ip, first_index, 1,
XFS_ICI_RECLAIM_TAG);
if (!nr_found) {
read_unlock(&pag->pag_ici_lock);
break;
}
/*
* 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)) {
read_unlock(&pag->pag_ici_lock);
break;
}
/* ignore if already under reclaim */
if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
read_unlock(&pag->pag_ici_lock);
continue;
}
if (noblock) {
if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
read_unlock(&pag->pag_ici_lock);
continue;
}
if (xfs_ipincount(ip) ||
!xfs_iflock_nowait(ip)) {
xfs_iunlock(ip, XFS_ILOCK_EXCL);
read_unlock(&pag->pag_ici_lock);
continue;
}
}
read_unlock(&pag->pag_ici_lock);
/*
* hmmm - this is an inode already in reclaim. Do
* we even bother catching it here?
*/
if (xfs_reclaim_inode(ip, noblock, mode))
skipped++;
} while (nr_found);
if (skipped) {
delay(1);
goto restart;
}
return;
}
int
xfs_reclaim_inodes(
xfs_mount_t *mp,
int noblock,
int mode)
{
int i;
for (i = 0; i < mp->m_sb.sb_agcount; i++) {
if (!mp->m_perag[i].pag_ici_init)
continue;
xfs_reclaim_inodes_ag(mp, i, noblock, mode);
}
return 0;
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2000-2006 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_SYNC_H
#define XFS_SYNC_H 1
struct xfs_mount;
typedef struct bhv_vfs_sync_work {
struct list_head w_list;
struct xfs_mount *w_mount;
void *w_data; /* syncer routine argument */
void (*w_syncer)(struct xfs_mount *, void *);
} bhv_vfs_sync_work_t;
#define SYNC_ATTR 0x0001 /* sync attributes */
#define SYNC_DELWRI 0x0002 /* look at delayed writes */
#define SYNC_WAIT 0x0004 /* wait for i/o to complete */
#define SYNC_BDFLUSH 0x0008 /* BDFLUSH is calling -- don't block */
#define SYNC_IOWAIT 0x0010 /* wait for all I/O to complete */
int xfs_syncd_init(struct xfs_mount *mp);
void xfs_syncd_stop(struct xfs_mount *mp);
int xfs_sync_inodes(struct xfs_mount *mp, int flags);
int xfs_sync_fsdata(struct xfs_mount *mp, int flags);
int xfs_quiesce_data(struct xfs_mount *mp);
void xfs_quiesce_attr(struct xfs_mount *mp);
void xfs_flush_inode(struct xfs_inode *ip);
void xfs_flush_device(struct xfs_inode *ip);
int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode);
int xfs_reclaim_inodes(struct xfs_mount *mp, int noblock, int mode);
void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
void xfs_inode_clear_reclaim_tag(struct xfs_inode *ip);
void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,
struct xfs_inode *ip);
#endif

View File

@ -55,17 +55,6 @@ xfs_stats_clear_proc_handler(
#endif /* CONFIG_PROC_FS */
static ctl_table xfs_table[] = {
{
.ctl_name = XFS_RESTRICT_CHOWN,
.procname = "restrict_chown",
.data = &xfs_params.restrict_chown.val,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &xfs_params.restrict_chown.min,
.extra2 = &xfs_params.restrict_chown.max
},
{
.ctl_name = XFS_SGID_INHERIT,
.procname = "irix_sgid_inherit",

View File

@ -31,7 +31,6 @@ typedef struct xfs_sysctl_val {
} xfs_sysctl_val_t;
typedef struct xfs_param {
xfs_sysctl_val_t restrict_chown;/* Root/non-root can give away files.*/
xfs_sysctl_val_t sgid_inherit; /* Inherit S_ISGID if process' GID is
* not a member of parent dir GID. */
xfs_sysctl_val_t symlink_mode; /* Link creat mode affected by umask */
@ -68,7 +67,7 @@ typedef struct xfs_param {
enum {
/* XFS_REFCACHE_SIZE = 1 */
/* XFS_REFCACHE_PURGE = 2 */
XFS_RESTRICT_CHOWN = 3,
/* XFS_RESTRICT_CHOWN = 3 */
XFS_SGID_INHERIT = 4,
XFS_SYMLINK_MODE = 5,
XFS_PANIC_MASK = 6,

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2000-2006 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_VFS_H__
#define __XFS_VFS_H__
#include <linux/vfs.h>
#include "xfs_fs.h"
struct inode;
struct fid;
struct cred;
struct seq_file;
struct super_block;
struct xfs_inode;
struct xfs_mount;
struct xfs_mount_args;
typedef struct kstatfs bhv_statvfs_t;
typedef struct bhv_vfs_sync_work {
struct list_head w_list;
struct xfs_mount *w_mount;
void *w_data; /* syncer routine argument */
void (*w_syncer)(struct xfs_mount *, void *);
} bhv_vfs_sync_work_t;
#define SYNC_ATTR 0x0001 /* sync attributes */
#define SYNC_CLOSE 0x0002 /* close file system down */
#define SYNC_DELWRI 0x0004 /* look at delayed writes */
#define SYNC_WAIT 0x0008 /* wait for i/o to complete */
#define SYNC_BDFLUSH 0x0010 /* BDFLUSH is calling -- don't block */
#define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */
#define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */
#define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */
#define SYNC_IOWAIT 0x0100 /* wait for all I/O to complete */
/*
* When remounting a filesystem read-only or freezing the filesystem,
* we have two phases to execute. This first phase is syncing the data
* before we quiesce the fielsystem, and the second is flushing all the
* inodes out after we've waited for all the transactions created by
* the first phase to complete. The second phase uses SYNC_INODE_QUIESCE
* to ensure that the inodes are written to their location on disk
* rather than just existing in transactions in the log. This means
* after a quiesce there is no log replay required to write the inodes
* to disk (this is the main difference between a sync and a quiesce).
*/
#define SYNC_DATA_QUIESCE (SYNC_DELWRI|SYNC_FSDATA|SYNC_WAIT|SYNC_IOWAIT)
#define SYNC_INODE_QUIESCE (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT)
#define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */
#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */
#define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */
#define SHUTDOWN_CORRUPT_INCORE 0x0008 /* corrupt in-memory data structures */
#define SHUTDOWN_REMOTE_REQ 0x0010 /* shutdown came from remote cell */
#define SHUTDOWN_DEVICE_REQ 0x0020 /* failed all paths to the device */
#define xfs_test_for_freeze(mp) ((mp)->m_super->s_frozen)
#define xfs_wait_for_freeze(mp,l) vfs_check_frozen((mp)->m_super, (l))
#endif /* __XFS_VFS_H__ */

View File

@ -1,145 +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
*/
#include "xfs.h"
#include "xfs_vnodeops.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
/*
* And this gunk is needed for xfs_mount.h"
*/
#include "xfs_log.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_dmapi.h"
#include "xfs_inum.h"
#include "xfs_ag.h"
#include "xfs_mount.h"
/*
* Dedicated vnode inactive/reclaim sync wait queues.
* Prime number of hash buckets since address is used as the key.
*/
#define NVSYNC 37
#define vptosync(v) (&vsync[((unsigned long)v) % NVSYNC])
static wait_queue_head_t vsync[NVSYNC];
void __init
vn_init(void)
{
int i;
for (i = 0; i < NVSYNC; i++)
init_waitqueue_head(&vsync[i]);
}
void
vn_iowait(
xfs_inode_t *ip)
{
wait_queue_head_t *wq = vptosync(ip);
wait_event(*wq, (atomic_read(&ip->i_iocount) == 0));
}
void
vn_iowake(
xfs_inode_t *ip)
{
if (atomic_dec_and_test(&ip->i_iocount))
wake_up(vptosync(ip));
}
/*
* Volume managers supporting multiple paths can send back ENODEV when the
* final path disappears. In this case continuing to fill the page cache
* with dirty data which cannot be written out is evil, so prevent that.
*/
void
vn_ioerror(
xfs_inode_t *ip,
int error,
char *f,
int l)
{
if (unlikely(error == -ENODEV))
xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ, f, l);
}
#ifdef XFS_INODE_TRACE
/*
* Reference count of Linux inode if present, -1 if the xfs_inode
* has no associated Linux inode.
*/
static inline int xfs_icount(struct xfs_inode *ip)
{
struct inode *vp = VFS_I(ip);
if (vp)
return vn_count(vp);
return -1;
}
#define KTRACE_ENTER(ip, vk, s, line, ra) \
ktrace_enter( (ip)->i_trace, \
/* 0 */ (void *)(__psint_t)(vk), \
/* 1 */ (void *)(s), \
/* 2 */ (void *)(__psint_t) line, \
/* 3 */ (void *)(__psint_t)xfs_icount(ip), \
/* 4 */ (void *)(ra), \
/* 5 */ NULL, \
/* 6 */ (void *)(__psint_t)current_cpu(), \
/* 7 */ (void *)(__psint_t)current_pid(), \
/* 8 */ (void *)__return_address, \
/* 9 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL)
/*
* Vnode tracing code.
*/
void
_xfs_itrace_entry(xfs_inode_t *ip, const char *func, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_ENTRY, func, 0, ra);
}
void
_xfs_itrace_exit(xfs_inode_t *ip, const char *func, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_EXIT, func, 0, ra);
}
void
xfs_itrace_hold(xfs_inode_t *ip, char *file, int line, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_HOLD, file, line, ra);
}
void
_xfs_itrace_ref(xfs_inode_t *ip, char *file, int line, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_REF, file, line, ra);
}
void
xfs_itrace_rele(xfs_inode_t *ip, char *file, int line, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_RELE, file, line, ra);
}
#endif /* XFS_INODE_TRACE */

View File

@ -18,7 +18,10 @@
#ifndef __XFS_VNODE_H__
#define __XFS_VNODE_H__
#include "xfs_fs.h"
struct file;
struct xfs_inode;
struct xfs_iomap;
struct attrlist_cursor_kern;
@ -51,40 +54,6 @@ struct attrlist_cursor_kern;
Prevent VM access to the pages until
the operation completes. */
extern void vn_init(void);
/*
* Yeah, these don't take vnode anymore at all, all this should be
* cleaned up at some point.
*/
extern void vn_iowait(struct xfs_inode *ip);
extern void vn_iowake(struct xfs_inode *ip);
extern void vn_ioerror(struct xfs_inode *ip, int error, char *f, int l);
static inline int vn_count(struct inode *vp)
{
return atomic_read(&vp->i_count);
}
#define IHOLD(ip) \
do { \
ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
atomic_inc(&(VFS_I(ip)->i_count)); \
xfs_itrace_hold((ip), __FILE__, __LINE__, (inst_t *)__return_address); \
} while (0)
#define IRELE(ip) \
do { \
xfs_itrace_rele((ip), __FILE__, __LINE__, (inst_t *)__return_address); \
iput(VFS_I(ip)); \
} while (0)
static inline struct inode *vn_grab(struct inode *vp)
{
return igrab(vp);
}
/*
* Dealing with bad inodes
*/
@ -121,39 +90,4 @@ static inline void vn_atime_to_time_t(struct inode *vp, time_t *tt)
PAGECACHE_TAG_DIRTY)
/*
* Tracking vnode activity.
*/
#if defined(XFS_INODE_TRACE)
#define INODE_TRACE_SIZE 16 /* number of trace entries */
#define INODE_KTRACE_ENTRY 1
#define INODE_KTRACE_EXIT 2
#define INODE_KTRACE_HOLD 3
#define INODE_KTRACE_REF 4
#define INODE_KTRACE_RELE 5
extern void _xfs_itrace_entry(struct xfs_inode *, const char *, inst_t *);
extern void _xfs_itrace_exit(struct xfs_inode *, const char *, inst_t *);
extern void xfs_itrace_hold(struct xfs_inode *, char *, int, inst_t *);
extern void _xfs_itrace_ref(struct xfs_inode *, char *, int, inst_t *);
extern void xfs_itrace_rele(struct xfs_inode *, char *, int, inst_t *);
#define xfs_itrace_entry(ip) \
_xfs_itrace_entry(ip, __func__, (inst_t *)__return_address)
#define xfs_itrace_exit(ip) \
_xfs_itrace_exit(ip, __func__, (inst_t *)__return_address)
#define xfs_itrace_exit_tag(ip, tag) \
_xfs_itrace_exit(ip, tag, (inst_t *)__return_address)
#define xfs_itrace_ref(ip) \
_xfs_itrace_ref(ip, __FILE__, __LINE__, (inst_t *)__return_address)
#else
#define xfs_itrace_entry(a)
#define xfs_itrace_exit(a)
#define xfs_itrace_exit_tag(a, b)
#define xfs_itrace_hold(a, b, c, d)
#define xfs_itrace_ref(a)
#define xfs_itrace_rele(a, b, c, d)
#endif
#endif /* __XFS_VNODE_H__ */

View File

@ -101,7 +101,7 @@ xfs_qm_dqinit(
if (brandnewdquot) {
dqp->dq_flnext = dqp->dq_flprev = dqp;
mutex_init(&dqp->q_qlock);
sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq");
init_waitqueue_head(&dqp->q_pinwait);
/*
* Because we want to use a counting completion, complete
@ -131,7 +131,7 @@ xfs_qm_dqinit(
dqp->q_res_bcount = 0;
dqp->q_res_icount = 0;
dqp->q_res_rtbcount = 0;
dqp->q_pincount = 0;
atomic_set(&dqp->q_pincount, 0);
dqp->q_hash = NULL;
ASSERT(dqp->dq_flnext == dqp->dq_flprev);
@ -1221,16 +1221,14 @@ xfs_qm_dqflush(
xfs_dqtrace_entry(dqp, "DQFLUSH");
/*
* If not dirty, nada.
* If not dirty, or it's pinned and we are not supposed to
* block, nada.
*/
if (!XFS_DQ_IS_DIRTY(dqp)) {
if (!XFS_DQ_IS_DIRTY(dqp) ||
(!(flags & XFS_QMOPT_SYNC) && atomic_read(&dqp->q_pincount) > 0)) {
xfs_dqfunlock(dqp);
return (0);
return 0;
}
/*
* Cant flush a pinned dquot. Wait for it.
*/
xfs_qm_dqunpin_wait(dqp);
/*
@ -1274,10 +1272,8 @@ xfs_qm_dqflush(
dqp->dq_flags &= ~(XFS_DQ_DIRTY);
mp = dqp->q_mount;
/* lsn is 64 bits */
spin_lock(&mp->m_ail_lock);
dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn;
spin_unlock(&mp->m_ail_lock);
xfs_trans_ail_copy_lsn(mp->m_ail, &dqp->q_logitem.qli_flush_lsn,
&dqp->q_logitem.qli_item.li_lsn);
/*
* Attach an iodone routine so that we can remove this dquot from the
@ -1323,8 +1319,10 @@ xfs_qm_dqflush_done(
xfs_dq_logitem_t *qip)
{
xfs_dquot_t *dqp;
struct xfs_ail *ailp;
dqp = qip->qli_dquot;
ailp = qip->qli_item.li_ailp;
/*
* We only want to pull the item from the AIL if its
@ -1337,15 +1335,12 @@ xfs_qm_dqflush_done(
if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
qip->qli_item.li_lsn == qip->qli_flush_lsn) {
spin_lock(&dqp->q_mount->m_ail_lock);
/*
* xfs_trans_delete_ail() drops the AIL lock.
*/
/* xfs_trans_ail_delete() drops the AIL lock. */
spin_lock(&ailp->xa_lock);
if (qip->qli_item.li_lsn == qip->qli_flush_lsn)
xfs_trans_delete_ail(dqp->q_mount,
(xfs_log_item_t*)qip);
xfs_trans_ail_delete(ailp, (xfs_log_item_t*)qip);
else
spin_unlock(&dqp->q_mount->m_ail_lock);
spin_unlock(&ailp->xa_lock);
}
/*
@ -1375,7 +1370,7 @@ xfs_dqunlock(
mutex_unlock(&(dqp->q_qlock));
if (dqp->q_logitem.qli_dquot == dqp) {
/* Once was dqp->q_mount, but might just have been cleared */
xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_mountp,
xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_ailp,
(xfs_log_item_t*)&(dqp->q_logitem));
}
}
@ -1489,7 +1484,7 @@ xfs_qm_dqpurge(
"xfs_qm_dqpurge: dquot %p flush failed", dqp);
xfs_dqflock(dqp);
}
ASSERT(dqp->q_pincount == 0);
ASSERT(atomic_read(&dqp->q_pincount) == 0);
ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
!(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));

View File

@ -83,8 +83,8 @@ typedef struct xfs_dquot {
xfs_qcnt_t q_res_rtbcount;/* total realtime blks used+reserved */
mutex_t q_qlock; /* quota lock */
struct completion q_flush; /* flush completion queue */
uint q_pincount; /* pin count for this dquot */
sv_t q_pinwait; /* sync var for pinning */
atomic_t q_pincount; /* dquot pin count */
wait_queue_head_t q_pinwait; /* dquot pinning wait queue */
#ifdef XFS_DQUOT_TRACE
struct ktrace *q_trace; /* trace header structure */
#endif

View File

@ -88,25 +88,22 @@ xfs_qm_dquot_logitem_format(
/*
* Increment the pin count of the given dquot.
* This value is protected by pinlock spinlock in the xQM structure.
*/
STATIC void
xfs_qm_dquot_logitem_pin(
xfs_dq_logitem_t *logitem)
{
xfs_dquot_t *dqp;
xfs_dquot_t *dqp = logitem->qli_dquot;
dqp = logitem->qli_dquot;
ASSERT(XFS_DQ_IS_LOCKED(dqp));
spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock));
dqp->q_pincount++;
spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock));
atomic_inc(&dqp->q_pincount);
}
/*
* Decrement the pin count of the given dquot, and wake up
* anyone in xfs_dqwait_unpin() if the count goes to 0. The
* dquot must have been previously pinned with a call to xfs_dqpin().
* dquot must have been previously pinned with a call to
* xfs_qm_dquot_logitem_pin().
*/
/* ARGSUSED */
STATIC void
@ -114,16 +111,11 @@ xfs_qm_dquot_logitem_unpin(
xfs_dq_logitem_t *logitem,
int stale)
{
xfs_dquot_t *dqp;
xfs_dquot_t *dqp = logitem->qli_dquot;
dqp = logitem->qli_dquot;
ASSERT(dqp->q_pincount > 0);
spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock));
dqp->q_pincount--;
if (dqp->q_pincount == 0) {
sv_broadcast(&dqp->q_pinwait);
}
spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock));
ASSERT(atomic_read(&dqp->q_pincount) > 0);
if (atomic_dec_and_test(&dqp->q_pincount))
wake_up(&dqp->q_pinwait);
}
/* ARGSUSED */
@ -193,21 +185,14 @@ xfs_qm_dqunpin_wait(
xfs_dquot_t *dqp)
{
ASSERT(XFS_DQ_IS_LOCKED(dqp));
if (dqp->q_pincount == 0) {
if (atomic_read(&dqp->q_pincount) == 0)
return;
}
/*
* Give the log a push so we don't wait here too long.
*/
xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE);
spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock));
if (dqp->q_pincount == 0) {
spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock));
return;
}
sv_wait(&(dqp->q_pinwait), PINOD,
&(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s);
wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0));
}
/*
@ -310,7 +295,7 @@ xfs_qm_dquot_logitem_trylock(
uint retval;
dqp = qip->qli_dquot;
if (dqp->q_pincount > 0)
if (atomic_read(&dqp->q_pincount) > 0)
return (XFS_ITEM_PINNED);
if (! xfs_qm_dqlock_nowait(dqp))
@ -568,14 +553,16 @@ xfs_qm_qoffend_logitem_committed(
xfs_lsn_t lsn)
{
xfs_qoff_logitem_t *qfs;
struct xfs_ail *ailp;
qfs = qfe->qql_start_lip;
spin_lock(&qfs->qql_item.li_mountp->m_ail_lock);
ailp = qfs->qql_item.li_ailp;
spin_lock(&ailp->xa_lock);
/*
* Delete the qoff-start logitem from the AIL.
* xfs_trans_delete_ail() drops the AIL lock.
* xfs_trans_ail_delete() drops the AIL lock.
*/
xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs);
xfs_trans_ail_delete(ailp, (xfs_log_item_t *)qfs);
kmem_free(qfs);
kmem_free(qfe);
return (xfs_lsn_t)-1;

View File

@ -20,7 +20,6 @@
#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_clnt.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@ -396,13 +395,10 @@ xfs_qm_mount_quotas(
/*
* Called from the vfsops layer.
*/
int
void
xfs_qm_unmount_quotas(
xfs_mount_t *mp)
{
xfs_inode_t *uqp, *gqp;
int error = 0;
/*
* Release the dquots that root inode, et al might be holding,
* before we flush quotas and blow away the quotainfo structure.
@ -415,43 +411,18 @@ xfs_qm_unmount_quotas(
xfs_qm_dqdetach(mp->m_rsumip);
/*
* Flush out the quota inodes.
* Release the quota inodes.
*/
uqp = gqp = NULL;
if (mp->m_quotainfo) {
if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) {
xfs_ilock(uqp, XFS_ILOCK_EXCL);
xfs_iflock(uqp);
error = xfs_iflush(uqp, XFS_IFLUSH_SYNC);
xfs_iunlock(uqp, XFS_ILOCK_EXCL);
if (unlikely(error == EFSCORRUPTED)) {
XFS_ERROR_REPORT("xfs_qm_unmount_quotas(1)",
XFS_ERRLEVEL_LOW, mp);
goto out;
}
if (mp->m_quotainfo->qi_uquotaip) {
IRELE(mp->m_quotainfo->qi_uquotaip);
mp->m_quotainfo->qi_uquotaip = NULL;
}
if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) {
xfs_ilock(gqp, XFS_ILOCK_EXCL);
xfs_iflock(gqp);
error = xfs_iflush(gqp, XFS_IFLUSH_SYNC);
xfs_iunlock(gqp, XFS_ILOCK_EXCL);
if (unlikely(error == EFSCORRUPTED)) {
XFS_ERROR_REPORT("xfs_qm_unmount_quotas(2)",
XFS_ERRLEVEL_LOW, mp);
goto out;
}
if (mp->m_quotainfo->qi_gquotaip) {
IRELE(mp->m_quotainfo->qi_gquotaip);
mp->m_quotainfo->qi_gquotaip = NULL;
}
}
if (uqp) {
IRELE(uqp);
mp->m_quotainfo->qi_uquotaip = NULL;
}
if (gqp) {
IRELE(gqp);
mp->m_quotainfo->qi_gquotaip = NULL;
}
out:
return XFS_ERROR(error);
}
/*
@ -987,14 +958,10 @@ xfs_qm_dqdetach(
}
/*
* This is called by VFS_SYNC and flags arg determines the caller,
* and its motives, as done in xfs_sync.
*
* vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH 0x31
* syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25
* umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA
* This is called to sync quotas. We can be told to use non-blocking
* semantics by either the SYNC_BDFLUSH flag or the absence of the
* SYNC_WAIT flag.
*/
int
xfs_qm_sync(
xfs_mount_t *mp,
@ -1137,7 +1104,6 @@ xfs_qm_init_quotainfo(
return error;
}
spin_lock_init(&qinf->qi_pinlock);
xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0);
qinf->qi_dqreclaims = 0;
@ -1234,7 +1200,6 @@ xfs_qm_destroy_quotainfo(
*/
xfs_qm_rele_quotafs_ref(mp);
spinlock_destroy(&qi->qi_pinlock);
xfs_qm_list_destroy(&qi->qi_dqlist);
if (qi->qi_uquotaip) {

View File

@ -106,7 +106,6 @@ typedef struct xfs_qm {
typedef struct xfs_quotainfo {
xfs_inode_t *qi_uquotaip; /* user quota inode */
xfs_inode_t *qi_gquotaip; /* group quota inode */
spinlock_t qi_pinlock; /* dquot pinning lock */
xfs_dqlist_t qi_dqlist; /* all dquots in filesys */
int qi_dqreclaims; /* a change here indicates
a removal in the dqlist */
@ -168,7 +167,7 @@ extern void xfs_qm_destroy_quotainfo(xfs_mount_t *);
extern void xfs_qm_mount_quotas(xfs_mount_t *);
extern int xfs_qm_quotacheck(xfs_mount_t *);
extern void xfs_qm_unmount_quotadestroy(xfs_mount_t *);
extern int xfs_qm_unmount_quotas(xfs_mount_t *);
extern void xfs_qm_unmount_quotas(xfs_mount_t *);
extern int xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
extern int xfs_qm_sync(xfs_mount_t *, int);

View File

@ -20,7 +20,6 @@
#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_clnt.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@ -51,7 +50,7 @@
STATIC void
xfs_fill_statvfs_from_dquot(
bhv_statvfs_t *statp,
struct kstatfs *statp,
xfs_disk_dquot_t *dp)
{
__uint64_t limit;
@ -88,7 +87,7 @@ xfs_fill_statvfs_from_dquot(
STATIC void
xfs_qm_statvfs(
xfs_inode_t *ip,
bhv_statvfs_t *statp)
struct kstatfs *statp)
{
xfs_mount_t *mp = ip->i_mount;
xfs_dquot_t *dqp;

View File

@ -127,7 +127,7 @@ xfs_qm_quotactl(
break;
case Q_XQUOTASYNC:
return (xfs_sync_inodes(mp, SYNC_DELWRI, NULL));
return xfs_sync_inodes(mp, SYNC_DELWRI);
default:
break;
@ -1021,6 +1021,86 @@ xfs_qm_export_flags(
}
/*
* Release all the dquots on the inodes in an AG.
*/
STATIC void
xfs_qm_dqrele_inodes_ag(
xfs_mount_t *mp,
int ag,
uint flags)
{
xfs_inode_t *ip = NULL;
xfs_perag_t *pag = &mp->m_perag[ag];
int first_index = 0;
int nr_found;
do {
/*
* 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.
*/
read_lock(&pag->pag_ici_lock);
nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
(void**)&ip, first_index, 1);
if (!nr_found) {
read_unlock(&pag->pag_ici_lock);
break;
}
/*
* 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)) {
read_unlock(&pag->pag_ici_lock);
break;
}
/* skip quota inodes */
if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
ASSERT(ip->i_udquot == NULL);
ASSERT(ip->i_gdquot == NULL);
read_unlock(&pag->pag_ici_lock);
continue;
}
/*
* If we can't get a reference on the inode, it must be
* in reclaim. Leave it for the reclaim code to flush.
*/
if (!igrab(VFS_I(ip))) {
read_unlock(&pag->pag_ici_lock);
continue;
}
read_unlock(&pag->pag_ici_lock);
/* avoid new inodes though we shouldn't find any here */
if (xfs_iflags_test(ip, XFS_INEW)) {
IRELE(ip);
continue;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
xfs_qm_dqrele(ip->i_udquot);
ip->i_udquot = NULL;
}
if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) &&
ip->i_gdquot) {
xfs_qm_dqrele(ip->i_gdquot);
ip->i_gdquot = NULL;
}
xfs_iput(ip, XFS_ILOCK_EXCL);
} while (nr_found);
}
/*
* Go thru all the inodes in the file system, releasing their dquots.
* Note that the mount structure gets modified to indicate that quotas are off
@ -1032,91 +1112,14 @@ xfs_qm_dqrele_all_inodes(
struct xfs_mount *mp,
uint flags)
{
xfs_inode_t *ip, *topino;
uint ireclaims;
struct inode *vp;
boolean_t vnode_refd;
int i;
ASSERT(mp->m_quotainfo);
XFS_MOUNT_ILOCK(mp);
again:
ip = mp->m_inodes;
if (ip == NULL) {
XFS_MOUNT_IUNLOCK(mp);
return;
for (i = 0; i < mp->m_sb.sb_agcount; i++) {
if (!mp->m_perag[i].pag_ici_init)
continue;
xfs_qm_dqrele_inodes_ag(mp, i, flags);
}
do {
/* Skip markers inserted by xfs_sync */
if (ip->i_mount == NULL) {
ip = ip->i_mnext;
continue;
}
/* Root inode, rbmip and rsumip have associated blocks */
if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) {
ASSERT(ip->i_udquot == NULL);
ASSERT(ip->i_gdquot == NULL);
ip = ip->i_mnext;
continue;
}
vp = VFS_I(ip);
if (!vp) {
ASSERT(ip->i_udquot == NULL);
ASSERT(ip->i_gdquot == NULL);
ip = ip->i_mnext;
continue;
}
vnode_refd = B_FALSE;
if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
ireclaims = mp->m_ireclaims;
topino = mp->m_inodes;
vp = vn_grab(vp);
if (!vp)
goto again;
XFS_MOUNT_IUNLOCK(mp);
/* XXX restart limit ? */
xfs_ilock(ip, XFS_ILOCK_EXCL);
vnode_refd = B_TRUE;
} else {
ireclaims = mp->m_ireclaims;
topino = mp->m_inodes;
XFS_MOUNT_IUNLOCK(mp);
}
/*
* We don't keep the mountlock across the dqrele() call,
* since it can take a while..
*/
if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
xfs_qm_dqrele(ip->i_udquot);
ip->i_udquot = NULL;
}
if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) {
xfs_qm_dqrele(ip->i_gdquot);
ip->i_gdquot = NULL;
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
/*
* Wait until we've dropped the ilock and mountlock to
* do the vn_rele. Or be condemned to an eternity in the
* inactive code in hell.
*/
if (vnode_refd)
IRELE(ip);
XFS_MOUNT_ILOCK(mp);
/*
* If an inode was inserted or removed, we gotta
* start over again.
*/
if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) {
/* XXX use a sentinel */
goto again;
}
ip = ip->i_mnext;
} while (ip != mp->m_inodes);
XFS_MOUNT_IUNLOCK(mp);
}
/*------------------------------------------------------------------------*/

View File

@ -18,6 +18,13 @@
#include <xfs.h>
#include "debug.h"
/* xfs_mount.h drags a lot of crap in, sorry.. */
#include "xfs_sb.h"
#include "xfs_inum.h"
#include "xfs_ag.h"
#include "xfs_dmapi.h"
#include "xfs_mount.h"
static char message[1024]; /* keep it off the stack */
static DEFINE_SPINLOCK(xfs_err_lock);
@ -55,22 +62,42 @@ cmn_err(register int level, char *fmt, ...)
}
void
icmn_err(register int level, char *fmt, va_list ap)
xfs_fs_vcmn_err(
int level,
struct xfs_mount *mp,
char *fmt,
va_list ap)
{
ulong flags;
int len;
unsigned long flags;
int len = 0;
level &= XFS_ERR_MASK;
if(level > XFS_MAX_ERR_LEVEL)
if (level > XFS_MAX_ERR_LEVEL)
level = XFS_MAX_ERR_LEVEL;
spin_lock_irqsave(&xfs_err_lock,flags);
len = vsnprintf(message, sizeof(message), fmt, ap);
if (mp) {
len = sprintf(message, "Filesystem \"%s\": ", mp->m_fsname);
/*
* Skip the printk if we can't print anything useful
* due to an over-long device name.
*/
if (len >= sizeof(message))
goto out;
}
len = vsnprintf(message + len, sizeof(message) - len, fmt, ap);
if (len >= sizeof(message))
len = sizeof(message) - 1;
if (message[len-1] == '\n')
message[len-1] = 0;
printk("%s%s\n", err_level[level], message);
out:
spin_unlock_irqrestore(&xfs_err_lock,flags);
BUG_ON(level == CE_PANIC);
}
@ -84,5 +111,5 @@ assfail(char *expr, char *file, int line)
void
xfs_hex_dump(void *p, int length)
{
print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_OFFSET, 16, 1, p, length, 1);
print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_ADDRESS, 16, 1, p, length, 1);
}

View File

@ -27,8 +27,6 @@
#define CE_ALERT 1 /* alert */
#define CE_PANIC 0 /* panic */
extern void icmn_err(int, char *, va_list)
__attribute__ ((format (printf, 2, 0)));
extern void cmn_err(int, char *, ...)
__attribute__ ((format (printf, 2, 3)));
extern void assfail(char *expr, char *f, int l);

View File

@ -113,21 +113,16 @@ ktrace_alloc(int nentries, unsigned int __nocast sleep)
void
ktrace_free(ktrace_t *ktp)
{
int entries_size;
if (ktp == (ktrace_t *)NULL)
return;
/*
* Special treatment for the Vnode trace buffer.
*/
if (ktp->kt_nentries == ktrace_zentries) {
if (ktp->kt_nentries == ktrace_zentries)
kmem_zone_free(ktrace_ent_zone, ktp->kt_entries);
} else {
entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t));
else
kmem_free(ktp->kt_entries);
}
kmem_zone_free(ktrace_hdr_zone, ktp);
}

View File

@ -30,7 +30,7 @@
#define XFS_ATTR_TRACE 1
#define XFS_BLI_TRACE 1
#define XFS_BMAP_TRACE 1
#define XFS_BMBT_TRACE 1
#define XFS_BTREE_TRACE 1
#define XFS_DIR2_TRACE 1
#define XFS_DQUOT_TRACE 1
#define XFS_ILOCK_TRACE 1

View File

@ -758,7 +758,7 @@ xfs_acl_setmode(
if (gap && nomask)
iattr.ia_mode |= gap->ae_perm << 3;
return xfs_setattr(XFS_I(vp), &iattr, 0, sys_cred);
return xfs_setattr(XFS_I(vp), &iattr, 0);
}
/*

View File

@ -91,6 +91,8 @@ typedef struct xfs_agf {
#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp))
#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)XFS_BUF_PTR(bp))
extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
/*
* Size of the unlinked inode hash table in the agi.
@ -142,6 +144,9 @@ typedef struct xfs_agi {
#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp))
#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)XFS_BUF_PTR(bp))
extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_buf **bpp);
/*
* The third a.g. block contains the a.g. freelist, an array
* of block pointers to blocks owned by the allocation btree code.
@ -192,17 +197,23 @@ typedef struct xfs_perag
xfs_agino_t pagi_freecount; /* number of free inodes */
xfs_agino_t pagi_count; /* number of allocated inodes */
int pagb_count; /* pagb slots in use */
xfs_perag_busy_t *pagb_list; /* unstable blocks */
#ifdef __KERNEL__
spinlock_t pagb_lock; /* lock for pagb_list */
#endif
xfs_perag_busy_t *pagb_list; /* unstable blocks */
atomic_t pagf_fstrms; /* # of filestreams active in this AG */
int pag_ici_init; /* incore inode cache initialised */
rwlock_t pag_ici_lock; /* incore inode lock */
struct radix_tree_root pag_ici_root; /* incore inode cache root */
#endif
} xfs_perag_t;
/*
* tags for inode radix tree
*/
#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */
#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)
#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \
(MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + MIN(cl + 1, XFS_AG_MAXLEVELS(mp)))

View File

@ -89,6 +89,92 @@ STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *,
* Internal functions.
*/
/*
* Lookup the record equal to [bno, len] in the btree given by cur.
*/
STATIC int /* error */
xfs_alloc_lookup_eq(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
xfs_extlen_t len, /* length of extent */
int *stat) /* success/failure */
{
cur->bc_rec.a.ar_startblock = bno;
cur->bc_rec.a.ar_blockcount = len;
return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
}
/*
* Lookup the first record greater than or equal to [bno, len]
* in the btree given by cur.
*/
STATIC int /* error */
xfs_alloc_lookup_ge(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
xfs_extlen_t len, /* length of extent */
int *stat) /* success/failure */
{
cur->bc_rec.a.ar_startblock = bno;
cur->bc_rec.a.ar_blockcount = len;
return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat);
}
/*
* Lookup the first record less than or equal to [bno, len]
* in the btree given by cur.
*/
STATIC int /* error */
xfs_alloc_lookup_le(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
xfs_extlen_t len, /* length of extent */
int *stat) /* success/failure */
{
cur->bc_rec.a.ar_startblock = bno;
cur->bc_rec.a.ar_blockcount = len;
return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
}
/*
* Update the record referred to by cur to the value given
* by [bno, len].
* This either works (return 0) or gets an EFSCORRUPTED error.
*/
STATIC int /* error */
xfs_alloc_update(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
xfs_extlen_t len) /* length of extent */
{
union xfs_btree_rec rec;
rec.alloc.ar_startblock = cpu_to_be32(bno);
rec.alloc.ar_blockcount = cpu_to_be32(len);
return xfs_btree_update(cur, &rec);
}
/*
* Get the data from the pointed-to record.
*/
STATIC int /* error */
xfs_alloc_get_rec(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t *bno, /* output: starting block of extent */
xfs_extlen_t *len, /* output: length of extent */
int *stat) /* output: success/failure */
{
union xfs_btree_rec *rec;
int error;
error = xfs_btree_get_rec(cur, &rec, stat);
if (!error && *stat == 1) {
*bno = be32_to_cpu(rec->alloc.ar_startblock);
*len = be32_to_cpu(rec->alloc.ar_blockcount);
}
return error;
}
/*
* Compute aligned version of the found extent.
* Takes alignment and min length into account.
@ -294,21 +380,20 @@ xfs_alloc_fixup_trees(
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
}
#ifdef DEBUG
{
xfs_alloc_block_t *bnoblock;
xfs_alloc_block_t *cntblock;
if (bno_cur->bc_nlevels == 1 &&
cnt_cur->bc_nlevels == 1) {
bnoblock = XFS_BUF_TO_ALLOC_BLOCK(bno_cur->bc_bufs[0]);
cntblock = XFS_BUF_TO_ALLOC_BLOCK(cnt_cur->bc_bufs[0]);
XFS_WANT_CORRUPTED_RETURN(
be16_to_cpu(bnoblock->bb_numrecs) ==
be16_to_cpu(cntblock->bb_numrecs));
}
#ifdef DEBUG
if (bno_cur->bc_nlevels == 1 && cnt_cur->bc_nlevels == 1) {
struct xfs_btree_block *bnoblock;
struct xfs_btree_block *cntblock;
bnoblock = XFS_BUF_TO_BLOCK(bno_cur->bc_bufs[0]);
cntblock = XFS_BUF_TO_BLOCK(cnt_cur->bc_bufs[0]);
XFS_WANT_CORRUPTED_RETURN(
bnoblock->bb_numrecs == cntblock->bb_numrecs);
}
#endif
/*
* Deal with all four cases: the allocated record is contained
* within the freespace record, so we can have new freespace
@ -333,7 +418,7 @@ xfs_alloc_fixup_trees(
/*
* Delete the entry from the by-size btree.
*/
if ((error = xfs_alloc_delete(cnt_cur, &i)))
if ((error = xfs_btree_delete(cnt_cur, &i)))
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
/*
@ -343,7 +428,7 @@ xfs_alloc_fixup_trees(
if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i)))
return error;
XFS_WANT_CORRUPTED_RETURN(i == 0);
if ((error = xfs_alloc_insert(cnt_cur, &i)))
if ((error = xfs_btree_insert(cnt_cur, &i)))
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
}
@ -351,7 +436,7 @@ xfs_alloc_fixup_trees(
if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i)))
return error;
XFS_WANT_CORRUPTED_RETURN(i == 0);
if ((error = xfs_alloc_insert(cnt_cur, &i)))
if ((error = xfs_btree_insert(cnt_cur, &i)))
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
}
@ -362,7 +447,7 @@ xfs_alloc_fixup_trees(
/*
* No remaining freespace, just delete the by-block tree entry.
*/
if ((error = xfs_alloc_delete(bno_cur, &i)))
if ((error = xfs_btree_delete(bno_cur, &i)))
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
} else {
@ -379,7 +464,7 @@ xfs_alloc_fixup_trees(
if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i)))
return error;
XFS_WANT_CORRUPTED_RETURN(i == 0);
if ((error = xfs_alloc_insert(bno_cur, &i)))
if ((error = xfs_btree_insert(bno_cur, &i)))
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
}
@ -640,8 +725,8 @@ xfs_alloc_ag_vextent_exact(
/*
* Allocate/initialize a cursor for the by-number freespace btree.
*/
bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_BNO, NULL, 0);
bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_BNO);
/*
* Lookup bno and minlen in the btree (minlen is irrelevant, really).
* Look for the closest free block <= bno, it must contain bno
@ -696,8 +781,8 @@ xfs_alloc_ag_vextent_exact(
* We are allocating agbno for rlen [agbno .. end]
* Allocate/initialize a cursor for the by-size btree.
*/
cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_CNT, NULL, 0);
cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_CNT);
ASSERT(args->agbno + args->len <=
be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
@ -759,8 +844,8 @@ xfs_alloc_ag_vextent_near(
/*
* Get a cursor for the by-size btree.
*/
cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_CNT, NULL, 0);
cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_CNT);
ltlen = 0;
bno_cur_lt = bno_cur_gt = NULL;
/*
@ -818,7 +903,7 @@ xfs_alloc_ag_vextent_near(
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if (ltlen >= args->minlen)
break;
if ((error = xfs_alloc_increment(cnt_cur, 0, &i)))
if ((error = xfs_btree_increment(cnt_cur, 0, &i)))
goto error0;
} while (i);
ASSERT(ltlen >= args->minlen);
@ -828,7 +913,7 @@ xfs_alloc_ag_vextent_near(
i = cnt_cur->bc_ptrs[0];
for (j = 1, blen = 0, bdiff = 0;
!error && j && (blen < args->maxlen || bdiff > 0);
error = xfs_alloc_increment(cnt_cur, 0, &j)) {
error = xfs_btree_increment(cnt_cur, 0, &j)) {
/*
* For each entry, decide if it's better than
* the previous best entry.
@ -886,8 +971,8 @@ xfs_alloc_ag_vextent_near(
/*
* Set up a cursor for the by-bno tree.
*/
bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp,
args->agbp, args->agno, XFS_BTNUM_BNO, NULL, 0);
bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp,
args->agbp, args->agno, XFS_BTNUM_BNO);
/*
* Fix up the btree entries.
*/
@ -914,8 +999,8 @@ xfs_alloc_ag_vextent_near(
/*
* Allocate and initialize the cursor for the leftward search.
*/
bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_BNO, NULL, 0);
bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_BNO);
/*
* Lookup <= bno to find the leftward search's starting point.
*/
@ -938,7 +1023,7 @@ xfs_alloc_ag_vextent_near(
* Increment the cursor, so we will point at the entry just right
* of the leftward entry if any, or to the leftmost entry.
*/
if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i)))
if ((error = xfs_btree_increment(bno_cur_gt, 0, &i)))
goto error0;
if (!i) {
/*
@ -961,7 +1046,7 @@ xfs_alloc_ag_vextent_near(
args->minlen, &ltbnoa, &ltlena);
if (ltlena >= args->minlen)
break;
if ((error = xfs_alloc_decrement(bno_cur_lt, 0, &i)))
if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i)))
goto error0;
if (!i) {
xfs_btree_del_cursor(bno_cur_lt,
@ -977,7 +1062,7 @@ xfs_alloc_ag_vextent_near(
args->minlen, &gtbnoa, &gtlena);
if (gtlena >= args->minlen)
break;
if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i)))
if ((error = xfs_btree_increment(bno_cur_gt, 0, &i)))
goto error0;
if (!i) {
xfs_btree_del_cursor(bno_cur_gt,
@ -1066,7 +1151,7 @@ xfs_alloc_ag_vextent_near(
/*
* Fell off the right end.
*/
if ((error = xfs_alloc_increment(
if ((error = xfs_btree_increment(
bno_cur_gt, 0, &i)))
goto error0;
if (!i) {
@ -1162,7 +1247,7 @@ xfs_alloc_ag_vextent_near(
/*
* Fell off the left end.
*/
if ((error = xfs_alloc_decrement(
if ((error = xfs_btree_decrement(
bno_cur_lt, 0, &i)))
goto error0;
if (!i) {
@ -1267,8 +1352,8 @@ xfs_alloc_ag_vextent_size(
/*
* Allocate and initialize a cursor for the by-size btree.
*/
cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_CNT, NULL, 0);
cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_CNT);
bno_cur = NULL;
/*
* Look for an entry >= maxlen+alignment-1 blocks.
@ -1321,7 +1406,7 @@ xfs_alloc_ag_vextent_size(
bestflen = flen;
bestfbno = fbno;
for (;;) {
if ((error = xfs_alloc_decrement(cnt_cur, 0, &i)))
if ((error = xfs_btree_decrement(cnt_cur, 0, &i)))
goto error0;
if (i == 0)
break;
@ -1372,8 +1457,8 @@ xfs_alloc_ag_vextent_size(
/*
* Allocate and initialize a cursor for the by-block tree.
*/
bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_BNO, NULL, 0);
bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_BNO);
if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
rbno, rlen, XFSA_FIXUP_CNT_OK)))
goto error0;
@ -1416,7 +1501,7 @@ xfs_alloc_ag_vextent_small(
xfs_extlen_t flen;
int i;
if ((error = xfs_alloc_decrement(ccur, 0, &i)))
if ((error = xfs_btree_decrement(ccur, 0, &i)))
goto error0;
if (i) {
if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i)))
@ -1515,8 +1600,7 @@ xfs_free_ag_extent(
/*
* Allocate and initialize a cursor for the by-block btree.
*/
bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, NULL,
0);
bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO);
cnt_cur = NULL;
/*
* Look for a neighboring block on the left (lower block numbers)
@ -1549,7 +1633,7 @@ xfs_free_ag_extent(
* Look for a neighboring block on the right (higher block numbers)
* that is contiguous with this space.
*/
if ((error = xfs_alloc_increment(bno_cur, 0, &haveright)))
if ((error = xfs_btree_increment(bno_cur, 0, &haveright)))
goto error0;
if (haveright) {
/*
@ -1575,8 +1659,7 @@ xfs_free_ag_extent(
/*
* Now allocate and initialize a cursor for the by-size tree.
*/
cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, NULL,
0);
cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT);
/*
* Have both left and right contiguous neighbors.
* Merge all three into a single free block.
@ -1588,7 +1671,7 @@ xfs_free_ag_extent(
if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if ((error = xfs_alloc_delete(cnt_cur, &i)))
if ((error = xfs_btree_delete(cnt_cur, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
/*
@ -1597,19 +1680,19 @@ xfs_free_ag_extent(
if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if ((error = xfs_alloc_delete(cnt_cur, &i)))
if ((error = xfs_btree_delete(cnt_cur, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
/*
* Delete the old by-block entry for the right block.
*/
if ((error = xfs_alloc_delete(bno_cur, &i)))
if ((error = xfs_btree_delete(bno_cur, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
/*
* Move the by-block cursor back to the left neighbor.
*/
if ((error = xfs_alloc_decrement(bno_cur, 0, &i)))
if ((error = xfs_btree_decrement(bno_cur, 0, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
#ifdef DEBUG
@ -1648,14 +1731,14 @@ xfs_free_ag_extent(
if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if ((error = xfs_alloc_delete(cnt_cur, &i)))
if ((error = xfs_btree_delete(cnt_cur, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
/*
* Back up the by-block cursor to the left neighbor, and
* update its length.
*/
if ((error = xfs_alloc_decrement(bno_cur, 0, &i)))
if ((error = xfs_btree_decrement(bno_cur, 0, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
nbno = ltbno;
@ -1674,7 +1757,7 @@ xfs_free_ag_extent(
if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if ((error = xfs_alloc_delete(cnt_cur, &i)))
if ((error = xfs_btree_delete(cnt_cur, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
/*
@ -1693,7 +1776,7 @@ xfs_free_ag_extent(
else {
nbno = bno;
nlen = len;
if ((error = xfs_alloc_insert(bno_cur, &i)))
if ((error = xfs_btree_insert(bno_cur, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
}
@ -1705,7 +1788,7 @@ xfs_free_ag_extent(
if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 0, error0);
if ((error = xfs_alloc_insert(cnt_cur, &i)))
if ((error = xfs_btree_insert(cnt_cur, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
@ -2150,51 +2233,83 @@ xfs_alloc_put_freelist(
* Read in the allocation group header (free/alloc section).
*/
int /* error */
xfs_alloc_read_agf(
xfs_mount_t *mp, /* mount point structure */
xfs_trans_t *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */
int flags, /* XFS_ALLOC_FLAG_... */
xfs_buf_t **bpp) /* buffer for the ag freelist header */
xfs_read_agf(
struct xfs_mount *mp, /* mount point structure */
struct xfs_trans *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */
int flags, /* XFS_BUF_ */
struct xfs_buf **bpp) /* buffer for the ag freelist header */
{
xfs_agf_t *agf; /* ag freelist header */
struct xfs_agf *agf; /* ag freelist header */
int agf_ok; /* set if agf is consistent */
xfs_buf_t *bp; /* return value */
xfs_perag_t *pag; /* per allocation group data */
int error;
ASSERT(agno != NULLAGNUMBER);
error = xfs_trans_read_buf(
mp, tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1),
(flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0U,
&bp);
XFS_FSS_TO_BB(mp, 1), flags, bpp);
if (error)
return error;
ASSERT(!bp || !XFS_BUF_GETERROR(bp));
if (!bp) {
*bpp = NULL;
if (!*bpp)
return 0;
}
ASSERT(!XFS_BUF_GETERROR(*bpp));
agf = XFS_BUF_TO_AGF(*bpp);
/*
* Validate the magic number of the agf block.
*/
agf = XFS_BUF_TO_AGF(bp);
agf_ok =
be32_to_cpu(agf->agf_magicnum) == XFS_AGF_MAGIC &&
XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&
be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&
be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp);
be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp) &&
be32_to_cpu(agf->agf_seqno) == agno;
if (xfs_sb_version_haslazysbcount(&mp->m_sb))
agf_ok = agf_ok && be32_to_cpu(agf->agf_btreeblks) <=
be32_to_cpu(agf->agf_length);
if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
XFS_RANDOM_ALLOC_READ_AGF))) {
XFS_CORRUPTION_ERROR("xfs_alloc_read_agf",
XFS_ERRLEVEL_LOW, mp, agf);
xfs_trans_brelse(tp, bp);
xfs_trans_brelse(tp, *bpp);
return XFS_ERROR(EFSCORRUPTED);
}
XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGF, XFS_AGF_REF);
return 0;
}
/*
* Read in the allocation group header (free/alloc section).
*/
int /* error */
xfs_alloc_read_agf(
struct xfs_mount *mp, /* mount point structure */
struct xfs_trans *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */
int flags, /* XFS_ALLOC_FLAG_... */
struct xfs_buf **bpp) /* buffer for the ag freelist header */
{
struct xfs_agf *agf; /* ag freelist header */
struct xfs_perag *pag; /* per allocation group data */
int error;
ASSERT(agno != NULLAGNUMBER);
error = xfs_read_agf(mp, tp, agno,
(flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0,
bpp);
if (error)
return error;
if (!*bpp)
return 0;
ASSERT(!XFS_BUF_GETERROR(*bpp));
agf = XFS_BUF_TO_AGF(*bpp);
pag = &mp->m_perag[agno];
if (!pag->pagf_init) {
pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks);
@ -2213,6 +2328,7 @@ xfs_alloc_read_agf(
#ifdef DEBUG
else if (!XFS_FORCED_SHUTDOWN(mp)) {
ASSERT(pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks));
ASSERT(pag->pagf_btreeblks == be32_to_cpu(agf->agf_btreeblks));
ASSERT(pag->pagf_flcount == be32_to_cpu(agf->agf_flcount));
ASSERT(pag->pagf_longest == be32_to_cpu(agf->agf_longest));
ASSERT(pag->pagf_levels[XFS_BTNUM_BNOi] ==
@ -2221,8 +2337,6 @@ xfs_alloc_read_agf(
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]));
}
#endif
XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGF, XFS_AGF_REF);
*bpp = bp;
return 0;
}

View File

@ -121,6 +121,19 @@ extern ktrace_t *xfs_alloc_trace_buf;
#define XFS_ALLOC_KTRACE_BUSYSEARCH 6
#endif
void
xfs_alloc_mark_busy(xfs_trans_t *tp,
xfs_agnumber_t agno,
xfs_agblock_t bno,
xfs_extlen_t len);
void
xfs_alloc_clear_busy(xfs_trans_t *tp,
xfs_agnumber_t ag,
int idx);
#endif /* __KERNEL__ */
/*
* Compute and fill in value of m_ag_maxlevels.
*/
@ -196,18 +209,4 @@ xfs_free_extent(
xfs_fsblock_t bno, /* starting block number of extent */
xfs_extlen_t len); /* length of extent */
void
xfs_alloc_mark_busy(xfs_trans_t *tp,
xfs_agnumber_t agno,
xfs_agblock_t bno,
xfs_extlen_t len);
void
xfs_alloc_clear_busy(xfs_trans_t *tp,
xfs_agnumber_t ag,
int idx);
#endif /* __KERNEL__ */
#endif /* __XFS_ALLOC_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,6 @@
struct xfs_buf;
struct xfs_btree_cur;
struct xfs_btree_sblock;
struct xfs_mount;
/*
@ -50,16 +49,6 @@ typedef struct xfs_alloc_rec_incore {
/* btree pointer type */
typedef __be32 xfs_alloc_ptr_t;
/* btree block header type */
typedef struct xfs_btree_sblock xfs_alloc_block_t;
#define XFS_BUF_TO_ALLOC_BLOCK(bp) ((xfs_alloc_block_t *)XFS_BUF_PTR(bp))
/*
* Real block structures have a size equal to the disk block size.
*/
#define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) ((cur)->bc_mp->m_alloc_mxr[lev != 0])
#define XFS_ALLOC_BLOCK_MINRECS(lev,cur) ((cur)->bc_mp->m_alloc_mnr[lev != 0])
/*
* Minimum and maximum blocksize and sectorsize.
@ -82,74 +71,40 @@ typedef struct xfs_btree_sblock xfs_alloc_block_t;
#define XFS_BNO_BLOCK(mp) ((xfs_agblock_t)(XFS_AGFL_BLOCK(mp) + 1))
#define XFS_CNT_BLOCK(mp) ((xfs_agblock_t)(XFS_BNO_BLOCK(mp) + 1))
/*
* Btree block header size depends on a superblock flag.
*
* (not quite yet, but soon)
*/
#define XFS_ALLOC_BLOCK_LEN(mp) XFS_BTREE_SBLOCK_LEN
/*
* Record, key, and pointer address macros for btree blocks.
*
* (note that some of these may appear unused, but they are used in userspace)
*/
#define XFS_ALLOC_REC_ADDR(bb,i,cur) \
XFS_BTREE_REC_ADDR(xfs_alloc, bb, i)
#define XFS_ALLOC_REC_ADDR(mp, block, index) \
((xfs_alloc_rec_t *) \
((char *)(block) + \
XFS_ALLOC_BLOCK_LEN(mp) + \
(((index) - 1) * sizeof(xfs_alloc_rec_t))))
#define XFS_ALLOC_KEY_ADDR(bb,i,cur) \
XFS_BTREE_KEY_ADDR(xfs_alloc, bb, i)
#define XFS_ALLOC_KEY_ADDR(mp, block, index) \
((xfs_alloc_key_t *) \
((char *)(block) + \
XFS_ALLOC_BLOCK_LEN(mp) + \
((index) - 1) * sizeof(xfs_alloc_key_t)))
#define XFS_ALLOC_PTR_ADDR(bb,i,cur) \
XFS_BTREE_PTR_ADDR(xfs_alloc, bb, i, XFS_ALLOC_BLOCK_MAXRECS(1, cur))
#define XFS_ALLOC_PTR_ADDR(mp, block, index, maxrecs) \
((xfs_alloc_ptr_t *) \
((char *)(block) + \
XFS_ALLOC_BLOCK_LEN(mp) + \
(maxrecs) * sizeof(xfs_alloc_key_t) + \
((index) - 1) * sizeof(xfs_alloc_ptr_t)))
/*
* Decrement cursor by one record at the level.
* For nonzero levels the leaf-ward information is untouched.
*/
extern int xfs_alloc_decrement(struct xfs_btree_cur *cur, int level, int *stat);
/*
* Delete the record pointed to by cur.
* The cursor refers to the place where the record was (could be inserted)
* when the operation returns.
*/
extern int xfs_alloc_delete(struct xfs_btree_cur *cur, int *stat);
/*
* Get the data from the pointed-to record.
*/
extern int xfs_alloc_get_rec(struct xfs_btree_cur *cur, xfs_agblock_t *bno,
xfs_extlen_t *len, int *stat);
/*
* Increment cursor by one record at the level.
* For nonzero levels the leaf-ward information is untouched.
*/
extern int xfs_alloc_increment(struct xfs_btree_cur *cur, int level, int *stat);
/*
* Insert the current record at the point referenced by cur.
* The cursor may be inconsistent on return if splits have been done.
*/
extern int xfs_alloc_insert(struct xfs_btree_cur *cur, int *stat);
/*
* Lookup the record equal to [bno, len] in the btree given by cur.
*/
extern int xfs_alloc_lookup_eq(struct xfs_btree_cur *cur, xfs_agblock_t bno,
xfs_extlen_t len, int *stat);
/*
* Lookup the first record greater than or equal to [bno, len]
* in the btree given by cur.
*/
extern int xfs_alloc_lookup_ge(struct xfs_btree_cur *cur, xfs_agblock_t bno,
xfs_extlen_t len, int *stat);
/*
* Lookup the first record less than or equal to [bno, len]
* in the btree given by cur.
*/
extern int xfs_alloc_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno,
xfs_extlen_t len, int *stat);
/*
* Update the record referred to by cur, to the value given by [bno, len].
* This either works (return 0) or gets an EFSCORRUPTED error.
*/
extern int xfs_alloc_update(struct xfs_btree_cur *cur, xfs_agblock_t bno,
xfs_extlen_t len);
extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
struct xfs_trans *, struct xfs_buf *,
xfs_agnumber_t, xfs_btnum_t);
extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int);
#endif /* __XFS_ALLOC_BTREE_H__ */

View File

@ -41,21 +41,36 @@
#endif
#ifdef XFS_NATIVE_HOST
#define cpu_to_be16(val) ((__be16)(val))
#define cpu_to_be32(val) ((__be32)(val))
#define cpu_to_be64(val) ((__be64)(val))
#define be16_to_cpu(val) ((__uint16_t)(val))
#define be32_to_cpu(val) ((__uint32_t)(val))
#define be64_to_cpu(val) ((__uint64_t)(val))
#define cpu_to_be16(val) ((__force __be16)(__u16)(val))
#define cpu_to_be32(val) ((__force __be32)(__u32)(val))
#define cpu_to_be64(val) ((__force __be64)(__u64)(val))
#define be16_to_cpu(val) ((__force __u16)(__be16)(val))
#define be32_to_cpu(val) ((__force __u32)(__be32)(val))
#define be64_to_cpu(val) ((__force __u64)(__be64)(val))
#else
#define cpu_to_be16(val) (__swab16((__uint16_t)(val)))
#define cpu_to_be32(val) (__swab32((__uint32_t)(val)))
#define cpu_to_be64(val) (__swab64((__uint64_t)(val)))
#define be16_to_cpu(val) (__swab16((__be16)(val)))
#define be32_to_cpu(val) (__swab32((__be32)(val)))
#define be64_to_cpu(val) (__swab64((__be64)(val)))
#define cpu_to_be16(val) ((__force __be16)__swab16((__u16)(val)))
#define cpu_to_be32(val) ((__force __be32)__swab32((__u32)(val)))
#define cpu_to_be64(val) ((__force __be64)__swab64((__u64)(val)))
#define be16_to_cpu(val) (__swab16((__force __u16)(__be16)(val)))
#define be32_to_cpu(val) (__swab32((__force __u32)(__be32)(val)))
#define be64_to_cpu(val) (__swab64((__force __u64)(__be64)(val)))
#endif
static inline void be16_add_cpu(__be16 *a, __s16 b)
{
*a = cpu_to_be16(be16_to_cpu(*a) + b);
}
static inline void be32_add_cpu(__be32 *a, __s32 b)
{
*a = cpu_to_be32(be32_to_cpu(*a) + b);
}
static inline void be64_add_cpu(__be64 *a, __s64 b)
{
*a = cpu_to_be64(be64_to_cpu(*a) + b);
}
#endif /* __KERNEL__ */
/* do we need conversion? */

View File

@ -61,8 +61,7 @@ static inline int xfs_highbit64(__uint64_t v)
/* Get low bit set out of 32-bit argument, -1 if none set */
static inline int xfs_lowbit32(__uint32_t v)
{
unsigned long t = v;
return (v) ? find_first_bit(&t, 32) : -1;
return ffs(v) - 1;
}
/* Get low bit set out of 64-bit argument, -1 if none set */

View File

@ -393,8 +393,8 @@ xfs_bmap_count_leaves(
STATIC void
xfs_bmap_disk_count_leaves(
xfs_extnum_t idx,
xfs_bmbt_block_t *block,
struct xfs_mount *mp,
struct xfs_btree_block *block,
int numrecs,
int *count);
@ -402,6 +402,53 @@ xfs_bmap_disk_count_leaves(
* Bmap internal routines.
*/
STATIC int /* error */
xfs_bmbt_lookup_eq(
struct xfs_btree_cur *cur,
xfs_fileoff_t off,
xfs_fsblock_t bno,
xfs_filblks_t len,
int *stat) /* success/failure */
{
cur->bc_rec.b.br_startoff = off;
cur->bc_rec.b.br_startblock = bno;
cur->bc_rec.b.br_blockcount = len;
return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
}
STATIC int /* error */
xfs_bmbt_lookup_ge(
struct xfs_btree_cur *cur,
xfs_fileoff_t off,
xfs_fsblock_t bno,
xfs_filblks_t len,
int *stat) /* success/failure */
{
cur->bc_rec.b.br_startoff = off;
cur->bc_rec.b.br_startblock = bno;
cur->bc_rec.b.br_blockcount = len;
return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat);
}
/*
* Update the record referred to by cur to the value given
* by [off, bno, len, state].
* This either works (return 0) or gets an EFSCORRUPTED error.
*/
STATIC int
xfs_bmbt_update(
struct xfs_btree_cur *cur,
xfs_fileoff_t off,
xfs_fsblock_t bno,
xfs_filblks_t len,
xfs_exntst_t state)
{
union xfs_btree_rec rec;
xfs_bmbt_disk_set_allf(&rec.bmbt, off, bno, len, state);
return xfs_btree_update(cur, &rec);
}
/*
* Called from xfs_bmap_add_attrfork to handle btree format files.
*/
@ -422,15 +469,14 @@ xfs_bmap_add_attrfork_btree(
if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip))
*flags |= XFS_ILOG_DBROOT;
else {
cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
XFS_DATA_FORK);
cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK);
cur->bc_private.b.flist = flist;
cur->bc_private.b.firstblock = *firstblock;
if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat)))
goto error0;
/* must be at least one entry */
XFS_WANT_CORRUPTED_GOTO(stat == 1, error0);
if ((error = xfs_bmbt_newroot(cur, flags, &stat)))
if ((error = xfs_btree_new_iroot(cur, flags, &stat)))
goto error0;
if (stat == 0) {
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
@ -818,10 +864,10 @@ xfs_bmap_add_extent_delay_real(
RIGHT.br_blockcount, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i)))
if ((error = xfs_btree_delete(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
if ((error = xfs_btree_decrement(cur, 0, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
@ -931,7 +977,7 @@ xfs_bmap_add_extent_delay_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
@ -1007,7 +1053,7 @@ xfs_bmap_add_extent_delay_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
@ -1097,7 +1143,7 @@ xfs_bmap_add_extent_delay_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
@ -1152,7 +1198,7 @@ xfs_bmap_add_extent_delay_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
@ -1379,16 +1425,16 @@ xfs_bmap_add_extent_unwritten_real(
RIGHT.br_blockcount, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i)))
if ((error = xfs_btree_delete(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
if ((error = xfs_btree_decrement(cur, 0, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i)))
if ((error = xfs_btree_delete(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
if ((error = xfs_btree_decrement(cur, 0, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
@ -1428,10 +1474,10 @@ xfs_bmap_add_extent_unwritten_real(
&i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i)))
if ((error = xfs_btree_delete(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
if ((error = xfs_btree_decrement(cur, 0, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
@ -1471,10 +1517,10 @@ xfs_bmap_add_extent_unwritten_real(
RIGHT.br_blockcount, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i)))
if ((error = xfs_btree_delete(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
if ((error = xfs_btree_decrement(cur, 0, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, new->br_startoff,
@ -1557,7 +1603,7 @@ xfs_bmap_add_extent_unwritten_real(
PREV.br_blockcount - new->br_blockcount,
oldext)))
goto done;
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
if ((error = xfs_btree_decrement(cur, 0, &i)))
goto done;
if (xfs_bmbt_update(cur, LEFT.br_startoff,
LEFT.br_startblock,
@ -1605,7 +1651,7 @@ xfs_bmap_add_extent_unwritten_real(
oldext)))
goto done;
cur->bc_rec.b = *new;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
@ -1647,7 +1693,7 @@ xfs_bmap_add_extent_unwritten_real(
PREV.br_blockcount - new->br_blockcount,
oldext)))
goto done;
if ((error = xfs_bmbt_increment(cur, 0, &i)))
if ((error = xfs_btree_increment(cur, 0, &i)))
goto done;
if ((error = xfs_bmbt_update(cur, new->br_startoff,
new->br_startblock,
@ -1695,7 +1741,7 @@ xfs_bmap_add_extent_unwritten_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
@ -1743,7 +1789,7 @@ xfs_bmap_add_extent_unwritten_real(
cur->bc_rec.b = PREV;
cur->bc_rec.b.br_blockcount =
new->br_startoff - PREV.br_startoff;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
/*
@ -1758,7 +1804,7 @@ xfs_bmap_add_extent_unwritten_real(
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
/* new middle extent - newext */
cur->bc_rec.b.br_state = new->br_state;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
@ -2106,10 +2152,10 @@ xfs_bmap_add_extent_hole_real(
right.br_blockcount, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i)))
if ((error = xfs_btree_delete(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
if ((error = xfs_btree_decrement(cur, 0, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, left.br_startoff,
@ -2218,7 +2264,7 @@ xfs_bmap_add_extent_hole_real(
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = new->br_state;
if ((error = xfs_bmbt_insert(cur, &i)))
if ((error = xfs_btree_insert(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
}
@ -2996,24 +3042,24 @@ xfs_bmap_btree_to_extents(
int whichfork) /* data or attr fork */
{
/* REFERENCED */
xfs_bmbt_block_t *cblock;/* child btree block */
struct xfs_btree_block *cblock;/* child btree block */
xfs_fsblock_t cbno; /* child block number */
xfs_buf_t *cbp; /* child block's buffer */
int error; /* error return value */
xfs_ifork_t *ifp; /* inode fork data */
xfs_mount_t *mp; /* mount point structure */
__be64 *pp; /* ptr to block address */
xfs_bmbt_block_t *rblock;/* root btree block */
struct xfs_btree_block *rblock;/* root btree block */
mp = ip->i_mount;
ifp = XFS_IFORK_PTR(ip, whichfork);
ASSERT(ifp->if_flags & XFS_IFEXTENTS);
ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
rblock = ifp->if_broot;
ASSERT(be16_to_cpu(rblock->bb_level) == 1);
ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1);
ASSERT(XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes) == 1);
mp = ip->i_mount;
pp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, ifp->if_broot_bytes);
ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1);
pp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, ifp->if_broot_bytes);
cbno = be64_to_cpu(*pp);
*logflagsp = 0;
#ifdef DEBUG
@ -3023,8 +3069,8 @@ xfs_bmap_btree_to_extents(
if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp,
XFS_BMAP_BTREE_REF)))
return error;
cblock = XFS_BUF_TO_BMBT_BLOCK(cbp);
if ((error = xfs_btree_check_lblock(cur, cblock, 0, cbp)))
cblock = XFS_BUF_TO_BLOCK(cbp);
if ((error = xfs_btree_check_block(cur, cblock, 0, cbp)))
return error;
xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp);
ip->i_d.di_nblocks--;
@ -3170,7 +3216,7 @@ xfs_bmap_del_extent(
flags |= XFS_ILOG_FEXT(whichfork);
break;
}
if ((error = xfs_bmbt_delete(cur, &i)))
if ((error = xfs_btree_delete(cur, &i)))
goto done;
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
break;
@ -3254,10 +3300,10 @@ xfs_bmap_del_extent(
got.br_startblock, temp,
got.br_state)))
goto done;
if ((error = xfs_bmbt_increment(cur, 0, &i)))
if ((error = xfs_btree_increment(cur, 0, &i)))
goto done;
cur->bc_rec.b = new;
error = xfs_bmbt_insert(cur, &i);
error = xfs_btree_insert(cur, &i);
if (error && error != ENOSPC)
goto done;
/*
@ -3404,11 +3450,11 @@ xfs_bmap_extents_to_btree(
int *logflagsp, /* inode logging flags */
int whichfork) /* data or attr fork */
{
xfs_bmbt_block_t *ablock; /* allocated (child) bt block */
struct xfs_btree_block *ablock; /* allocated (child) bt block */
xfs_buf_t *abp; /* buffer for ablock */
xfs_alloc_arg_t args; /* allocation arguments */
xfs_bmbt_rec_t *arp; /* child record pointer */
xfs_bmbt_block_t *block; /* btree root block */
struct xfs_btree_block *block; /* btree root block */
xfs_btree_cur_t *cur; /* bmap btree cursor */
xfs_bmbt_rec_host_t *ep; /* extent record pointer */
int error; /* error return value */
@ -3428,6 +3474,7 @@ xfs_bmap_extents_to_btree(
*/
xfs_iroot_realloc(ip, 1, whichfork);
ifp->if_flags |= XFS_IFBROOT;
/*
* Fill in the root.
*/
@ -3435,14 +3482,14 @@ xfs_bmap_extents_to_btree(
block->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
block->bb_level = cpu_to_be16(1);
block->bb_numrecs = cpu_to_be16(1);
block->bb_leftsib = cpu_to_be64(NULLDFSBNO);
block->bb_rightsib = cpu_to_be64(NULLDFSBNO);
block->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
block->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
/*
* Need a cursor. Can't allocate until bb_level is filled in.
*/
mp = ip->i_mount;
cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
whichfork);
cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
cur->bc_private.b.firstblock = *firstblock;
cur->bc_private.b.flist = flist;
cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0;
@ -3489,12 +3536,12 @@ xfs_bmap_extents_to_btree(
/*
* Fill in the child block.
*/
ablock = XFS_BUF_TO_BMBT_BLOCK(abp);
ablock = XFS_BUF_TO_BLOCK(abp);
ablock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
ablock->bb_level = 0;
ablock->bb_leftsib = cpu_to_be64(NULLDFSBNO);
ablock->bb_rightsib = cpu_to_be64(NULLDFSBNO);
arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
ablock->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO);
ablock->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO);
arp = XFS_BMBT_REC_ADDR(mp, ablock, 1);
nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
for (cnt = i = 0; i < nextents; i++) {
ep = xfs_iext_get_ext(ifp, i);
@ -3505,21 +3552,24 @@ xfs_bmap_extents_to_btree(
}
}
ASSERT(cnt == XFS_IFORK_NEXTENTS(ip, whichfork));
ablock->bb_numrecs = cpu_to_be16(cnt);
xfs_btree_set_numrecs(ablock, cnt);
/*
* Fill in the root key and pointer.
*/
kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
kp = XFS_BMBT_KEY_ADDR(mp, block, 1);
arp = XFS_BMBT_REC_ADDR(mp, ablock, 1);
kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp));
pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
pp = XFS_BMBT_PTR_ADDR(mp, block, 1, xfs_bmbt_get_maxrecs(cur,
be16_to_cpu(block->bb_level)));
*pp = cpu_to_be64(args.fsbno);
/*
* Do all this logging at the end so that
* the root is at the right level.
*/
xfs_bmbt_log_block(cur, abp, XFS_BB_ALL_BITS);
xfs_bmbt_log_recs(cur, abp, 1, be16_to_cpu(ablock->bb_numrecs));
xfs_btree_log_block(cur, abp, XFS_BB_ALL_BITS);
xfs_btree_log_recs(cur, abp, 1, be16_to_cpu(ablock->bb_numrecs));
ASSERT(*curp == NULL);
*curp = cur;
*logflagsp = XFS_ILOG_CORE | XFS_ILOG_FBROOT(whichfork);
@ -4176,7 +4226,7 @@ xfs_bmap_compute_maxlevels(
maxleafents = MAXAEXTNUM;
sz = XFS_BMDR_SPACE_CALC(MINABTPTRS);
}
maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0);
maxrootrecs = xfs_bmdr_maxrecs(mp, sz, 0);
minleafrecs = mp->m_bmap_dmnr[0];
minnoderecs = mp->m_bmap_dmnr[1];
maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
@ -4242,9 +4292,15 @@ xfs_bmap_finish(
* We have a new transaction, so we should return committed=1,
* even though we're returning an error.
*/
if (error) {
if (error)
return error;
}
/*
* transaction commit worked ok so we can drop the extra ticket
* reference that we gained in xfs_trans_dup()
*/
xfs_log_ticket_put(ntp->t_ticket);
if ((error = xfs_trans_reserve(ntp, 0, logres, 0, XFS_TRANS_PERM_LOG_RES,
logcount)))
return error;
@ -4474,6 +4530,22 @@ xfs_bmap_one_block(
return rval;
}
STATIC int
xfs_bmap_sanity_check(
struct xfs_mount *mp,
struct xfs_buf *bp,
int level)
{
struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC ||
be16_to_cpu(block->bb_level) != level ||
be16_to_cpu(block->bb_numrecs) == 0 ||
be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0])
return 0;
return 1;
}
/*
* Read in the extents to if_extents.
* All inode fields are set up by caller, we just traverse the btree
@ -4486,7 +4558,7 @@ xfs_bmap_read_extents(
xfs_inode_t *ip, /* incore inode */
int whichfork) /* data or attr fork */
{
xfs_bmbt_block_t *block; /* current btree block */
struct xfs_btree_block *block; /* current btree block */
xfs_fsblock_t bno; /* block # of "block" */
xfs_buf_t *bp; /* buffer for "block" */
int error; /* error return value */
@ -4510,7 +4582,7 @@ xfs_bmap_read_extents(
*/
level = be16_to_cpu(block->bb_level);
ASSERT(level > 0);
pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
bno = be64_to_cpu(*pp);
ASSERT(bno != NULLDFSBNO);
ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
@ -4523,13 +4595,13 @@ xfs_bmap_read_extents(
if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
XFS_BMAP_BTREE_REF)))
return error;
block = XFS_BUF_TO_BMBT_BLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
XFS_WANT_CORRUPTED_GOTO(
XFS_BMAP_SANITY_CHECK(mp, block, level),
xfs_bmap_sanity_check(mp, bp, level),
error0);
if (level == 0)
break;
pp = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]);
pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
bno = be64_to_cpu(*pp);
XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, bno), error0);
xfs_trans_brelse(tp, bp);
@ -4549,7 +4621,7 @@ xfs_bmap_read_extents(
xfs_extnum_t start;
num_recs = be16_to_cpu(block->bb_numrecs);
num_recs = xfs_btree_get_numrecs(block);
if (unlikely(i + num_recs > room)) {
ASSERT(i + num_recs <= room);
xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
@ -4561,18 +4633,18 @@ xfs_bmap_read_extents(
goto error0;
}
XFS_WANT_CORRUPTED_GOTO(
XFS_BMAP_SANITY_CHECK(mp, block, 0),
xfs_bmap_sanity_check(mp, bp, 0),
error0);
/*
* Read-ahead the next leaf block, if any.
*/
nextbno = be64_to_cpu(block->bb_rightsib);
nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
if (nextbno != NULLFSBLOCK)
xfs_btree_reada_bufl(mp, nextbno, 1);
/*
* Copy records into the extent records.
*/
frp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, 1);
frp = XFS_BMBT_REC_ADDR(mp, block, 1);
start = i;
for (j = 0; j < num_recs; j++, i++, frp++) {
xfs_bmbt_rec_host_t *trp = xfs_iext_get_ext(ifp, i);
@ -4603,7 +4675,7 @@ xfs_bmap_read_extents(
if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
XFS_BMAP_BTREE_REF)))
return error;
block = XFS_BUF_TO_BMBT_BLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
}
ASSERT(i == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)));
ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork));
@ -5029,8 +5101,7 @@ xfs_bmapi(
if (abno == NULLFSBLOCK)
break;
if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
cur = xfs_btree_init_cursor(mp,
tp, NULL, 0, XFS_BTNUM_BMAP,
cur = xfs_bmbt_init_cursor(mp, tp,
ip, whichfork);
cur->bc_private.b.firstblock =
*firstblock;
@ -5147,9 +5218,8 @@ xfs_bmapi(
*/
ASSERT(mval->br_blockcount <= len);
if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
cur = xfs_btree_init_cursor(mp,
tp, NULL, 0, XFS_BTNUM_BMAP,
ip, whichfork);
cur = xfs_bmbt_init_cursor(mp,
tp, ip, whichfork);
cur->bc_private.b.firstblock =
*firstblock;
cur->bc_private.b.flist = flist;
@ -5440,8 +5510,7 @@ xfs_bunmapi(
logflags = 0;
if (ifp->if_flags & XFS_IFBROOT) {
ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
whichfork);
cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
cur->bc_private.b.firstblock = *firstblock;
cur->bc_private.b.flist = flist;
cur->bc_private.b.flags = 0;
@ -5742,14 +5811,17 @@ error0:
STATIC int
xfs_getbmapx_fix_eof_hole(
xfs_inode_t *ip, /* xfs incore inode pointer */
struct getbmap *out, /* output structure */
struct getbmapx *out, /* output structure */
int prealloced, /* this is a file with
* preallocated data space */
* preallocated data space */
__int64_t end, /* last block requested */
xfs_fsblock_t startblock)
{
__int64_t fixlen;
xfs_mount_t *mp; /* file system mount point */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_extnum_t lastx; /* last extent pointer */
xfs_fileoff_t fileblock;
if (startblock == HOLESTARTBLOCK) {
mp = ip->i_mount;
@ -5763,21 +5835,33 @@ xfs_getbmapx_fix_eof_hole(
out->bmv_length = fixlen;
}
} else {
out->bmv_block = XFS_FSB_TO_DB(ip, startblock);
if (startblock == DELAYSTARTBLOCK)
out->bmv_block = -2;
else
out->bmv_block = XFS_FSB_TO_DB(ip, startblock);
fileblock = XFS_BB_TO_FSB(ip->i_mount, out->bmv_offset);
ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
if (xfs_iext_bno_to_ext(ifp, fileblock, &lastx) &&
(lastx == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))-1))
out->bmv_oflags |= BMV_OF_LAST;
}
return 1;
}
/*
* Fcntl interface to xfs_bmapi.
* Get inode's extents as described in bmv, and format for output.
* Calls formatter to fill the user's buffer until all extents
* are mapped, until the passed-in bmv->bmv_count slots have
* been filled, or until the formatter short-circuits the loop,
* if it is tracking filled-in extents on its own.
*/
int /* error code */
xfs_getbmap(
xfs_inode_t *ip,
struct getbmap *bmv, /* user bmap structure */
void __user *ap, /* pointer to user's array */
int interface) /* interface flags */
struct getbmapx *bmv, /* user bmap structure */
xfs_bmap_format_t formatter, /* format to user */
void *arg) /* formatter arg */
{
__int64_t bmvend; /* last block requested */
int error; /* return value */
@ -5790,19 +5874,17 @@ xfs_getbmap(
int nexleft; /* # of user extents left */
int subnex; /* # of bmapi's can do */
int nmap; /* number of map entries */
struct getbmap out; /* output structure */
struct getbmapx out; /* output structure */
int whichfork; /* data or attr fork */
int prealloced; /* this is a file with
* preallocated data space */
int sh_unwritten; /* true, if unwritten */
/* extents listed separately */
int iflags; /* interface flags */
int bmapi_flags; /* flags for xfs_bmapi */
__int32_t oflags; /* getbmapx bmv_oflags field */
mp = ip->i_mount;
iflags = bmv->bmv_iflags;
whichfork = interface & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK;
sh_unwritten = (interface & BMV_IF_PREALLOC) != 0;
whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK;
/* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not
* generate a DMAPI read event. Otherwise, if the DM_EVENT_READ
@ -5817,7 +5899,7 @@ xfs_getbmap(
* could misinterpret holes in a DMAPI file as true holes,
* when in fact they may represent offline user data.
*/
if ((interface & BMV_IF_NO_DMAPI_READ) == 0 &&
if ((iflags & BMV_IF_NO_DMAPI_READ) == 0 &&
DM_EVENT_ENABLED(ip, DM_EVENT_READ) &&
whichfork == XFS_DATA_FORK) {
error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL);
@ -5873,8 +5955,9 @@ xfs_getbmap(
xfs_ilock(ip, XFS_IOLOCK_SHARED);
if (whichfork == XFS_DATA_FORK &&
(ip->i_delayed_blks || ip->i_size > ip->i_d.di_size)) {
if (((iflags & BMV_IF_DELALLOC) == 0) &&
(whichfork == XFS_DATA_FORK) &&
(ip->i_delayed_blks || ip->i_size > ip->i_d.di_size)) {
/* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */
error = xfs_flush_pages(ip, (xfs_off_t)0,
-1, 0, FI_REMAPF);
@ -5884,7 +5967,8 @@ xfs_getbmap(
}
}
ASSERT(whichfork == XFS_ATTR_FORK || ip->i_delayed_blks == 0);
ASSERT(whichfork == XFS_ATTR_FORK || (iflags & BMV_IF_DELALLOC) ||
ip->i_delayed_blks == 0);
lock = xfs_ilock_map_shared(ip);
@ -5896,7 +5980,7 @@ xfs_getbmap(
nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1;
bmapi_flags = XFS_BMAPI_AFLAG(whichfork) |
((sh_unwritten) ? 0 : XFS_BMAPI_IGSTATE);
((iflags & BMV_IF_PREALLOC) ? 0 : XFS_BMAPI_IGSTATE);
/*
* Allocate enough space to handle "subnex" maps at a time.
@ -5906,9 +5990,12 @@ xfs_getbmap(
bmv->bmv_entries = 0;
if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0) {
error = 0;
goto unlock_and_return;
if ((XFS_IFORK_NEXTENTS(ip, whichfork) == 0)) {
if (((iflags & BMV_IF_DELALLOC) == 0) ||
whichfork == XFS_ATTR_FORK) {
error = 0;
goto unlock_and_return;
}
}
nexleft = nex;
@ -5924,52 +6011,40 @@ xfs_getbmap(
ASSERT(nmap <= subnex);
for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) {
nexleft--;
oflags = (map[i].br_state == XFS_EXT_UNWRITTEN) ?
BMV_OF_PREALLOC : 0;
out.bmv_oflags = 0;
if (map[i].br_state == XFS_EXT_UNWRITTEN)
out.bmv_oflags |= BMV_OF_PREALLOC;
else if (map[i].br_startblock == DELAYSTARTBLOCK)
out.bmv_oflags |= BMV_OF_DELALLOC;
out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff);
out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
out.bmv_unused1 = out.bmv_unused2 = 0;
ASSERT(((iflags & BMV_IF_DELALLOC) != 0) ||
(map[i].br_startblock != DELAYSTARTBLOCK));
if (map[i].br_startblock == HOLESTARTBLOCK &&
whichfork == XFS_ATTR_FORK) {
/* came to the end of attribute fork */
out.bmv_oflags |= BMV_OF_LAST;
goto unlock_and_return;
} else {
int full = 0; /* user array is full */
if (!xfs_getbmapx_fix_eof_hole(ip, &out,
prealloced, bmvend,
map[i].br_startblock)) {
goto unlock_and_return;
}
/* return either getbmap/getbmapx structure. */
if (interface & BMV_IF_EXTENDED) {
struct getbmapx outx;
GETBMAP_CONVERT(out,outx);
outx.bmv_oflags = oflags;
outx.bmv_unused1 = outx.bmv_unused2 = 0;
if (copy_to_user(ap, &outx,
sizeof(outx))) {
error = XFS_ERROR(EFAULT);
goto unlock_and_return;
}
} else {
if (copy_to_user(ap, &out,
sizeof(out))) {
error = XFS_ERROR(EFAULT);
goto unlock_and_return;
}
}
/* format results & advance arg */
error = formatter(&arg, &out, &full);
if (error || full)
goto unlock_and_return;
nexleft--;
bmv->bmv_offset =
out.bmv_offset + out.bmv_length;
bmv->bmv_length = MAX((__int64_t)0,
(__int64_t)(bmvend - bmv->bmv_offset));
bmv->bmv_entries++;
ap = (interface & BMV_IF_EXTENDED) ?
(void __user *)
((struct getbmapx __user *)ap + 1) :
(void __user *)
((struct getbmap __user *)ap + 1);
}
}
} while (nmap && nexleft && bmv->bmv_length);
@ -6131,7 +6206,7 @@ xfs_bmap_get_bp(
void
xfs_check_block(
xfs_bmbt_block_t *block,
struct xfs_btree_block *block,
xfs_mount_t *mp,
int root,
short sz)
@ -6143,36 +6218,29 @@ xfs_check_block(
ASSERT(be16_to_cpu(block->bb_level) > 0);
prevp = NULL;
for( i = 1; i <= be16_to_cpu(block->bb_numrecs); i++) {
for( i = 1; i <= xfs_btree_get_numrecs(block); i++) {
dmxr = mp->m_bmap_dmxr[0];
if (root) {
keyp = XFS_BMAP_BROOT_KEY_ADDR(block, i, sz);
} else {
keyp = XFS_BTREE_KEY_ADDR(xfs_bmbt, block, i);
}
keyp = XFS_BMBT_KEY_ADDR(mp, block, i);
if (prevp) {
xfs_btree_check_key(XFS_BTNUM_BMAP, prevp, keyp);
ASSERT(be64_to_cpu(prevp->br_startoff) <
be64_to_cpu(keyp->br_startoff));
}
prevp = keyp;
/*
* Compare the block numbers to see if there are dups.
*/
if (root)
pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, i, sz);
else
pp = XFS_BMBT_PTR_ADDR(mp, block, i, dmxr);
if (root) {
pp = XFS_BMAP_BROOT_PTR_ADDR(block, i, sz);
} else {
pp = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, i, dmxr);
}
for (j = i+1; j <= be16_to_cpu(block->bb_numrecs); j++) {
if (root) {
thispa = XFS_BMAP_BROOT_PTR_ADDR(block, j, sz);
} else {
thispa = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, j,
dmxr);
}
if (root)
thispa = XFS_BMAP_BROOT_PTR_ADDR(mp, block, j, sz);
else
thispa = XFS_BMBT_PTR_ADDR(mp, block, j, dmxr);
if (*thispa == *pp) {
cmn_err(CE_WARN, "%s: thispa(%d) == pp(%d) %Ld",
__func__, j, i,
@ -6195,7 +6263,7 @@ xfs_bmap_check_leaf_extents(
xfs_inode_t *ip, /* incore inode pointer */
int whichfork) /* data or attr fork */
{
xfs_bmbt_block_t *block; /* current btree block */
struct xfs_btree_block *block; /* current btree block */
xfs_fsblock_t bno; /* block # of "block" */
xfs_buf_t *bp; /* buffer for "block" */
int error; /* error return value */
@ -6223,7 +6291,7 @@ xfs_bmap_check_leaf_extents(
level = be16_to_cpu(block->bb_level);
ASSERT(level > 0);
xfs_check_block(block, mp, 1, ifp->if_broot_bytes);
pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
bno = be64_to_cpu(*pp);
ASSERT(bno != NULLDFSBNO);
@ -6245,9 +6313,9 @@ xfs_bmap_check_leaf_extents(
if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
XFS_BMAP_BTREE_REF)))
goto error_norelse;
block = XFS_BUF_TO_BMBT_BLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
XFS_WANT_CORRUPTED_GOTO(
XFS_BMAP_SANITY_CHECK(mp, block, level),
xfs_bmap_sanity_check(mp, bp, level),
error0);
if (level == 0)
break;
@ -6258,7 +6326,7 @@ xfs_bmap_check_leaf_extents(
*/
xfs_check_block(block, mp, 0, 0);
pp = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]);
pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
bno = be64_to_cpu(*pp);
XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, bno), error0);
if (bp_release) {
@ -6280,13 +6348,13 @@ xfs_bmap_check_leaf_extents(
xfs_extnum_t num_recs;
num_recs = be16_to_cpu(block->bb_numrecs);
num_recs = xfs_btree_get_numrecs(block);
/*
* Read-ahead the next leaf block, if any.
*/
nextbno = be64_to_cpu(block->bb_rightsib);
nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
/*
* Check all the extents to make sure they are OK.
@ -6294,13 +6362,17 @@ xfs_bmap_check_leaf_extents(
* conform with the first entry in this one.
*/
ep = XFS_BTREE_REC_ADDR(xfs_bmbt, block, 1);
ep = XFS_BMBT_REC_ADDR(mp, block, 1);
if (i) {
xfs_btree_check_rec(XFS_BTNUM_BMAP, &last, ep);
ASSERT(xfs_bmbt_disk_get_startoff(&last) +
xfs_bmbt_disk_get_blockcount(&last) <=
xfs_bmbt_disk_get_startoff(ep));
}
for (j = 1; j < num_recs; j++) {
nextp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, j + 1);
xfs_btree_check_rec(XFS_BTNUM_BMAP, ep, nextp);
nextp = XFS_BMBT_REC_ADDR(mp, block, j + 1);
ASSERT(xfs_bmbt_disk_get_startoff(ep) +
xfs_bmbt_disk_get_blockcount(ep) <=
xfs_bmbt_disk_get_startoff(nextp));
ep = nextp;
}
@ -6326,7 +6398,7 @@ xfs_bmap_check_leaf_extents(
if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp,
XFS_BMAP_BTREE_REF)))
goto error_norelse;
block = XFS_BUF_TO_BMBT_BLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
}
if (bp_release) {
bp_release = 0;
@ -6356,7 +6428,7 @@ xfs_bmap_count_blocks(
int whichfork, /* data or attr fork */
int *count) /* out: count of blocks */
{
xfs_bmbt_block_t *block; /* current btree block */
struct xfs_btree_block *block; /* current btree block */
xfs_fsblock_t bno; /* block # of "block" */
xfs_ifork_t *ifp; /* fork structure */
int level; /* btree level, for checking */
@ -6379,7 +6451,7 @@ xfs_bmap_count_blocks(
block = ifp->if_broot;
level = be16_to_cpu(block->bb_level);
ASSERT(level > 0);
pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
bno = be64_to_cpu(*pp);
ASSERT(bno != NULLDFSBNO);
ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
@ -6413,29 +6485,29 @@ xfs_bmap_count_tree(
__be64 *pp;
xfs_fsblock_t bno = blockno;
xfs_fsblock_t nextbno;
xfs_bmbt_block_t *block, *nextblock;
struct xfs_btree_block *block, *nextblock;
int numrecs;
if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF)))
return error;
*count += 1;
block = XFS_BUF_TO_BMBT_BLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
if (--level) {
/* Not at node above leafs, count this level of nodes */
nextbno = be64_to_cpu(block->bb_rightsib);
nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
while (nextbno != NULLFSBLOCK) {
if ((error = xfs_btree_read_bufl(mp, tp, nextbno,
0, &nbp, XFS_BMAP_BTREE_REF)))
return error;
*count += 1;
nextblock = XFS_BUF_TO_BMBT_BLOCK(nbp);
nextbno = be64_to_cpu(nextblock->bb_rightsib);
nextblock = XFS_BUF_TO_BLOCK(nbp);
nextbno = be64_to_cpu(nextblock->bb_u.l.bb_rightsib);
xfs_trans_brelse(tp, nbp);
}
/* Dive to the next level */
pp = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]);
pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
bno = be64_to_cpu(*pp);
if (unlikely((error =
xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) {
@ -6448,9 +6520,9 @@ xfs_bmap_count_tree(
} else {
/* count all level 1 nodes and their leaves */
for (;;) {
nextbno = be64_to_cpu(block->bb_rightsib);
nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
numrecs = be16_to_cpu(block->bb_numrecs);
xfs_bmap_disk_count_leaves(0, block, numrecs, count);
xfs_bmap_disk_count_leaves(mp, block, numrecs, count);
xfs_trans_brelse(tp, bp);
if (nextbno == NULLFSBLOCK)
break;
@ -6459,7 +6531,7 @@ xfs_bmap_count_tree(
XFS_BMAP_BTREE_REF)))
return error;
*count += 1;
block = XFS_BUF_TO_BMBT_BLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
}
}
return 0;
@ -6489,8 +6561,8 @@ xfs_bmap_count_leaves(
*/
STATIC void
xfs_bmap_disk_count_leaves(
xfs_extnum_t idx,
xfs_bmbt_block_t *block,
struct xfs_mount *mp,
struct xfs_btree_block *block,
int numrecs,
int *count)
{
@ -6498,7 +6570,7 @@ xfs_bmap_disk_count_leaves(
xfs_bmbt_rec_t *frp;
for (b = 1; b <= numrecs; b++) {
frp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, idx + b);
frp = XFS_BMBT_REC_ADDR(mp, block, b);
*count += xfs_bmbt_disk_get_blockcount(frp);
}
}

View File

@ -137,9 +137,7 @@ typedef struct xfs_bmalloca {
char conv; /* overwriting unwritten extents */
} xfs_bmalloca_t;
#ifdef __KERNEL__
#if defined(XFS_BMAP_TRACE)
#if defined(__KERNEL__) && defined(XFS_BMAP_TRACE)
/*
* Trace operations for bmap extent tracing
*/
@ -163,9 +161,12 @@ xfs_bmap_trace_exlist(
int whichfork); /* data or attr fork */
#define XFS_BMAP_TRACE_EXLIST(ip,c,w) \
xfs_bmap_trace_exlist(__func__,ip,c,w)
#else
#else /* __KERNEL__ && XFS_BMAP_TRACE */
#define XFS_BMAP_TRACE_EXLIST(ip,c,w)
#endif
#endif /* __KERNEL__ && XFS_BMAP_TRACE */
/*
* Convert inode from non-attributed to attributed.
@ -205,20 +206,6 @@ xfs_bmap_compute_maxlevels(
struct xfs_mount *mp, /* file system mount structure */
int whichfork); /* data or attr fork */
/*
* Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
* caller. Frees all the extents that need freeing, which must be done
* last due to locking considerations.
*
* Return 1 if the given transaction was committed and a new one allocated,
* and 0 otherwise.
*/
int /* error */
xfs_bmap_finish(
struct xfs_trans **tp, /* transaction pointer addr */
xfs_bmap_free_t *flist, /* i/o: list extents to free */
int *committed); /* xact committed or not */
/*
* Returns the file-relative block number of the first unused block in the file.
* This is the lowest-address hole if the file has holes, else the first block
@ -344,14 +331,43 @@ xfs_bunmapi(
int *done); /* set if not done yet */
/*
* Fcntl interface to xfs_bmapi.
* Check an extent list, which has just been read, for
* any bit in the extent flag field.
*/
int
xfs_check_nostate_extents(
struct xfs_ifork *ifp,
xfs_extnum_t idx,
xfs_extnum_t num);
#ifdef __KERNEL__
/*
* Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
* caller. Frees all the extents that need freeing, which must be done
* last due to locking considerations.
*
* Return 1 if the given transaction was committed and a new one allocated,
* and 0 otherwise.
*/
int /* error */
xfs_bmap_finish(
struct xfs_trans **tp, /* transaction pointer addr */
xfs_bmap_free_t *flist, /* i/o: list extents to free */
int *committed); /* xact committed or not */
/* bmap to userspace formatter - copy to user & advance pointer */
typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *);
/*
* Get inode's extents as described in bmv, and format for output.
*/
int /* error code */
xfs_getbmap(
xfs_inode_t *ip,
struct getbmap *bmv, /* user bmap structure */
void __user *ap, /* pointer to user's array */
int iflags); /* interface flags */
struct getbmapx *bmv, /* user bmap structure */
xfs_bmap_format_t formatter, /* format to user */
void *arg); /* formatter arg */
/*
* Check if the endoff is outside the last extent. If so the caller will grow
@ -374,16 +390,6 @@ xfs_bmap_count_blocks(
int whichfork,
int *count);
/*
* Check an extent list, which has just been read, for
* any bit in the extent flag field.
*/
int
xfs_check_nostate_extents(
struct xfs_ifork *ifp,
xfs_extnum_t idx,
xfs_extnum_t num);
/*
* Search the extent records for the entry containing block bno.
* If bno lies in a hole, point to the next entry. If bno lies

File diff suppressed because it is too large Load Diff

View File

@ -21,9 +21,10 @@
#define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */
struct xfs_btree_cur;
struct xfs_btree_lblock;
struct xfs_btree_block;
struct xfs_mount;
struct xfs_inode;
struct xfs_trans;
/*
* Bmap root header, on-disk form only.
@ -145,71 +146,60 @@ typedef struct xfs_bmbt_key {
/* btree pointer type */
typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
/* btree block header type */
typedef struct xfs_btree_lblock xfs_bmbt_block_t;
/*
* Btree block header size depends on a superblock flag.
*
* (not quite yet, but soon)
*/
#define XFS_BMBT_BLOCK_LEN(mp) XFS_BTREE_LBLOCK_LEN
#define XFS_BUF_TO_BMBT_BLOCK(bp) ((xfs_bmbt_block_t *)XFS_BUF_PTR(bp))
#define XFS_BMBT_REC_ADDR(mp, block, index) \
((xfs_bmbt_rec_t *) \
((char *)(block) + \
XFS_BMBT_BLOCK_LEN(mp) + \
((index) - 1) * sizeof(xfs_bmbt_rec_t)))
#define XFS_BMAP_RBLOCK_DSIZE(lev,cur) ((cur)->bc_private.b.forksize)
#define XFS_BMAP_RBLOCK_ISIZE(lev,cur) \
((int)XFS_IFORK_PTR((cur)->bc_private.b.ip, \
(cur)->bc_private.b.whichfork)->if_broot_bytes)
#define XFS_BMBT_KEY_ADDR(mp, block, index) \
((xfs_bmbt_key_t *) \
((char *)(block) + \
XFS_BMBT_BLOCK_LEN(mp) + \
((index) - 1) * sizeof(xfs_bmbt_key_t)))
#define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) \
(((lev) == (cur)->bc_nlevels - 1 ? \
XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \
xfs_bmdr, (lev) == 0) : \
((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])))
#define XFS_BMAP_BLOCK_IMAXRECS(lev,cur) \
(((lev) == (cur)->bc_nlevels - 1 ? \
XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur),\
xfs_bmbt, (lev) == 0) : \
((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])))
#define XFS_BMBT_PTR_ADDR(mp, block, index, maxrecs) \
((xfs_bmbt_ptr_t *) \
((char *)(block) + \
XFS_BMBT_BLOCK_LEN(mp) + \
(maxrecs) * sizeof(xfs_bmbt_key_t) + \
((index) - 1) * sizeof(xfs_bmbt_ptr_t)))
#define XFS_BMAP_BLOCK_DMINRECS(lev,cur) \
(((lev) == (cur)->bc_nlevels - 1 ? \
XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur),\
xfs_bmdr, (lev) == 0) : \
((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])))
#define XFS_BMAP_BLOCK_IMINRECS(lev,cur) \
(((lev) == (cur)->bc_nlevels - 1 ? \
XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur),\
xfs_bmbt, (lev) == 0) : \
((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])))
#define XFS_BMDR_REC_ADDR(block, index) \
((xfs_bmdr_rec_t *) \
((char *)(block) + \
sizeof(struct xfs_bmdr_block) + \
((index) - 1) * sizeof(xfs_bmdr_rec_t)))
#define XFS_BMAP_REC_DADDR(bb,i,cur) (XFS_BTREE_REC_ADDR(xfs_bmbt, bb, i))
#define XFS_BMDR_KEY_ADDR(block, index) \
((xfs_bmdr_key_t *) \
((char *)(block) + \
sizeof(struct xfs_bmdr_block) + \
((index) - 1) * sizeof(xfs_bmdr_key_t)))
#define XFS_BMAP_REC_IADDR(bb,i,cur) (XFS_BTREE_REC_ADDR(xfs_bmbt, bb, i))
#define XFS_BMAP_KEY_DADDR(bb,i,cur) \
(XFS_BTREE_KEY_ADDR(xfs_bmbt, bb, i))
#define XFS_BMAP_KEY_IADDR(bb,i,cur) \
(XFS_BTREE_KEY_ADDR(xfs_bmbt, bb, i))
#define XFS_BMAP_PTR_DADDR(bb,i,cur) \
(XFS_BTREE_PTR_ADDR(xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \
be16_to_cpu((bb)->bb_level), cur)))
#define XFS_BMAP_PTR_IADDR(bb,i,cur) \
(XFS_BTREE_PTR_ADDR(xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \
be16_to_cpu((bb)->bb_level), cur)))
#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \
((xfs_bmdr_ptr_t *) \
((char *)(block) + \
sizeof(struct xfs_bmdr_block) + \
(maxrecs) * sizeof(xfs_bmdr_key_t) + \
((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
/*
* These are to be used when we know the size of the block and
* we don't have a cursor.
*/
#define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) \
(XFS_BTREE_REC_ADDR(xfs_bmbt,bb,i))
#define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) \
(XFS_BTREE_KEY_ADDR(xfs_bmbt,bb,i))
#define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) \
(XFS_BTREE_PTR_ADDR(xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)))
#define XFS_BMAP_BROOT_NUMRECS(bb) be16_to_cpu((bb)->bb_numrecs)
#define XFS_BMAP_BROOT_MAXRECS(sz) XFS_BTREE_BLOCK_MAXRECS(sz,xfs_bmbt,0)
#define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \
XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0))
#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) \
(int)(sizeof(xfs_bmbt_block_t) + \
(int)(XFS_BTREE_LBLOCK_LEN + \
((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
#define XFS_BMAP_BROOT_SPACE(bb) \
@ -223,42 +213,12 @@ typedef struct xfs_btree_lblock xfs_bmbt_block_t;
*/
#define XFS_BM_MAXLEVELS(mp,w) ((mp)->m_bm_maxlevels[(w)])
#define XFS_BMAP_SANITY_CHECK(mp,bb,level) \
(be32_to_cpu((bb)->bb_magic) == XFS_BMAP_MAGIC && \
be16_to_cpu((bb)->bb_level) == level && \
be16_to_cpu((bb)->bb_numrecs) > 0 && \
be16_to_cpu((bb)->bb_numrecs) <= (mp)->m_bmap_dmxr[(level) != 0])
#ifdef __KERNEL__
#if defined(XFS_BMBT_TRACE)
/*
* Trace buffer entry types.
*/
#define XFS_BMBT_KTRACE_ARGBI 1
#define XFS_BMBT_KTRACE_ARGBII 2
#define XFS_BMBT_KTRACE_ARGFFFI 3
#define XFS_BMBT_KTRACE_ARGI 4
#define XFS_BMBT_KTRACE_ARGIFK 5
#define XFS_BMBT_KTRACE_ARGIFR 6
#define XFS_BMBT_KTRACE_ARGIK 7
#define XFS_BMBT_KTRACE_CUR 8
#define XFS_BMBT_TRACE_SIZE 4096 /* size of global trace buffer */
#define XFS_BMBT_KTRACE_SIZE 32 /* size of per-inode trace buffer */
extern ktrace_t *xfs_bmbt_trace_buf;
#endif
/*
* Prototypes for xfs_bmap.c to call.
*/
extern void xfs_bmdr_to_bmbt(xfs_bmdr_block_t *, int, xfs_bmbt_block_t *, int);
extern int xfs_bmbt_decrement(struct xfs_btree_cur *, int, int *);
extern int xfs_bmbt_delete(struct xfs_btree_cur *, int *);
extern void xfs_bmdr_to_bmbt(struct xfs_mount *, xfs_bmdr_block_t *, int,
struct xfs_btree_block *, int);
extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s);
extern xfs_bmbt_block_t *xfs_bmbt_get_block(struct xfs_btree_cur *cur,
int, struct xfs_buf **bpp);
extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_host_t *r);
extern xfs_fsblock_t xfs_bmbt_get_startblock(xfs_bmbt_rec_host_t *r);
extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_host_t *r);
@ -268,22 +228,6 @@ extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r);
extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r);
extern int xfs_bmbt_increment(struct xfs_btree_cur *, int, int *);
extern int xfs_bmbt_insert(struct xfs_btree_cur *, int *);
extern void xfs_bmbt_log_block(struct xfs_btree_cur *, struct xfs_buf *, int);
extern void xfs_bmbt_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int,
int);
extern int xfs_bmbt_lookup_eq(struct xfs_btree_cur *, xfs_fileoff_t,
xfs_fsblock_t, xfs_filblks_t, int *);
extern int xfs_bmbt_lookup_ge(struct xfs_btree_cur *, xfs_fileoff_t,
xfs_fsblock_t, xfs_filblks_t, int *);
/*
* Give the bmap btree a new root block. Copy the old broot contents
* down into a real block and make the broot point to it.
*/
extern int xfs_bmbt_newroot(struct xfs_btree_cur *cur, int *lflags, int *stat);
extern void xfs_bmbt_set_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s);
extern void xfs_bmbt_set_allf(xfs_bmbt_rec_host_t *r, xfs_fileoff_t o,
xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v);
@ -296,10 +240,15 @@ extern void xfs_bmbt_disk_set_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o,
xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v);
extern void xfs_bmbt_to_bmdr(xfs_bmbt_block_t *, int, xfs_bmdr_block_t *, int);
extern int xfs_bmbt_update(struct xfs_btree_cur *, xfs_fileoff_t,
xfs_fsblock_t, xfs_filblks_t, xfs_exntst_t);
extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int,
xfs_bmdr_block_t *, int);
extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level);
extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf);
extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);
extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
struct xfs_trans *, struct xfs_inode *, int);
#endif /* __KERNEL__ */
#endif /* __XFS_BMAP_BTREE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -39,39 +39,19 @@ extern kmem_zone_t *xfs_btree_cur_zone;
#define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi)
/*
* Short form header: space allocation btrees.
* Generic btree header.
*
* This is a comination of the actual format used on disk for short and long
* format btrees. The first three fields are shared by both format, but
* the pointers are different and should be used with care.
*
* To get the size of the actual short or long form headers please use
* the size macros below. Never use sizeof(xfs_btree_block).
*/
typedef struct xfs_btree_sblock {
struct xfs_btree_block {
__be32 bb_magic; /* magic number for block type */
__be16 bb_level; /* 0 is a leaf */
__be16 bb_numrecs; /* current # of data records */
__be32 bb_leftsib; /* left sibling block or NULLAGBLOCK */
__be32 bb_rightsib; /* right sibling block or NULLAGBLOCK */
} xfs_btree_sblock_t;
/*
* Long form header: bmap btrees.
*/
typedef struct xfs_btree_lblock {
__be32 bb_magic; /* magic number for block type */
__be16 bb_level; /* 0 is a leaf */
__be16 bb_numrecs; /* current # of data records */
__be64 bb_leftsib; /* left sibling block or NULLDFSBNO */
__be64 bb_rightsib; /* right sibling block or NULLDFSBNO */
} xfs_btree_lblock_t;
/*
* Combined header and structure, used by common code.
*/
typedef struct xfs_btree_hdr
{
__be32 bb_magic; /* magic number for block type */
__be16 bb_level; /* 0 is a leaf */
__be16 bb_numrecs; /* current # of data records */
} xfs_btree_hdr_t;
typedef struct xfs_btree_block {
xfs_btree_hdr_t bb_h; /* header */
union {
struct {
__be32 bb_leftsib;
@ -82,7 +62,36 @@ typedef struct xfs_btree_block {
__be64 bb_rightsib;
} l; /* long form pointers */
} bb_u; /* rest */
} xfs_btree_block_t;
};
#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */
#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */
/*
* Generic key, ptr and record wrapper structures.
*
* These are disk format structures, and are converted where necessary
* by the btree specific code that needs to interpret them.
*/
union xfs_btree_ptr {
__be32 s; /* short form ptr */
__be64 l; /* long form ptr */
};
union xfs_btree_key {
xfs_bmbt_key_t bmbt;
xfs_bmdr_key_t bmbr; /* bmbt root block */
xfs_alloc_key_t alloc;
xfs_inobt_key_t inobt;
};
union xfs_btree_rec {
xfs_bmbt_rec_t bmbt;
xfs_bmdr_rec_t bmbr; /* bmbt root block */
xfs_alloc_rec_t alloc;
xfs_inobt_rec_t inobt;
};
/*
* For logging record fields.
@ -95,47 +104,132 @@ typedef struct xfs_btree_block {
#define XFS_BB_NUM_BITS 5
#define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1)
/*
* Boolean to select which form of xfs_btree_block_t.bb_u to use.
*/
#define XFS_BTREE_LONG_PTRS(btnum) ((btnum) == XFS_BTNUM_BMAP)
/*
* Magic numbers for btree blocks.
*/
extern const __uint32_t xfs_magics[];
/*
* Maximum and minimum records in a btree block.
* Given block size, type prefix, and leaf flag (0 or 1).
* The divisor below is equivalent to lf ? (e1) : (e2) but that produces
* compiler warnings.
* Generic stats interface
*/
#define XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) \
((int)(((bsz) - (uint)sizeof(t ## _block_t)) / \
(((lf) * (uint)sizeof(t ## _rec_t)) + \
((1 - (lf)) * \
((uint)sizeof(t ## _key_t) + (uint)sizeof(t ## _ptr_t))))))
#define XFS_BTREE_BLOCK_MINRECS(bsz,t,lf) \
(XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) / 2)
#define __XFS_BTREE_STATS_INC(type, stat) \
XFS_STATS_INC(xs_ ## type ## _2_ ## stat)
#define XFS_BTREE_STATS_INC(cur, stat) \
do { \
switch (cur->bc_btnum) { \
case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(abtb, stat); break; \
case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \
case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \
case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \
} while (0)
/*
* Record, key, and pointer address calculation macros.
* Given block size, type prefix, block pointer, and index of requested entry
* (first entry numbered 1).
*/
#define XFS_BTREE_REC_ADDR(t,bb,i) \
((t ## _rec_t *)((char *)(bb) + sizeof(t ## _block_t) + \
((i) - 1) * sizeof(t ## _rec_t)))
#define XFS_BTREE_KEY_ADDR(t,bb,i) \
((t ## _key_t *)((char *)(bb) + sizeof(t ## _block_t) + \
((i) - 1) * sizeof(t ## _key_t)))
#define XFS_BTREE_PTR_ADDR(t,bb,i,mxr) \
((t ## _ptr_t *)((char *)(bb) + sizeof(t ## _block_t) + \
(mxr) * sizeof(t ## _key_t) + ((i) - 1) * sizeof(t ## _ptr_t)))
#define __XFS_BTREE_STATS_ADD(type, stat, val) \
XFS_STATS_ADD(xs_ ## type ## _2_ ## stat, val)
#define XFS_BTREE_STATS_ADD(cur, stat, val) \
do { \
switch (cur->bc_btnum) { \
case XFS_BTNUM_BNO: __XFS_BTREE_STATS_ADD(abtb, stat, val); break; \
case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \
case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \
case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \
} while (0)
#define XFS_BTREE_MAXLEVELS 8 /* max of all btrees */
struct xfs_btree_ops {
/* size of the key and record structures */
size_t key_len;
size_t rec_len;
/* cursor operations */
struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *);
void (*update_cursor)(struct xfs_btree_cur *src,
struct xfs_btree_cur *dst);
/* 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);
/* block allocation / freeing */
int (*alloc_block)(struct xfs_btree_cur *cur,
union xfs_btree_ptr *start_bno,
union xfs_btree_ptr *new_bno,
int length, int *stat);
int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp);
/* update last record information */
void (*update_lastrec)(struct xfs_btree_cur *cur,
struct xfs_btree_block *block,
union xfs_btree_rec *rec,
int ptr, int reason);
/* records in block/level */
int (*get_minrecs)(struct xfs_btree_cur *cur, int level);
int (*get_maxrecs)(struct xfs_btree_cur *cur, int level);
/* records on disk. Matter for the root in inode case. */
int (*get_dmaxrecs)(struct xfs_btree_cur *cur, int level);
/* init values of btree structures */
void (*init_key_from_rec)(union xfs_btree_key *key,
union xfs_btree_rec *rec);
void (*init_rec_from_key)(union xfs_btree_key *key,
union xfs_btree_rec *rec);
void (*init_rec_from_cur)(struct xfs_btree_cur *cur,
union xfs_btree_rec *rec);
void (*init_ptr_from_cur)(struct xfs_btree_cur *cur,
union xfs_btree_ptr *ptr);
/* difference between key value and cursor value */
__int64_t (*key_diff)(struct xfs_btree_cur *cur,
union xfs_btree_key *key);
#ifdef DEBUG
/* check that k1 is lower than k2 */
int (*keys_inorder)(struct xfs_btree_cur *cur,
union xfs_btree_key *k1,
union xfs_btree_key *k2);
/* check that r1 is lower than r2 */
int (*recs_inorder)(struct xfs_btree_cur *cur,
union xfs_btree_rec *r1,
union xfs_btree_rec *r2);
#endif
/* btree tracing */
#ifdef XFS_BTREE_TRACE
void (*trace_enter)(struct xfs_btree_cur *, const char *,
char *, int, int, __psunsigned_t,
__psunsigned_t, __psunsigned_t,
__psunsigned_t, __psunsigned_t,
__psunsigned_t, __psunsigned_t,
__psunsigned_t, __psunsigned_t,
__psunsigned_t, __psunsigned_t);
void (*trace_cursor)(struct xfs_btree_cur *, __uint32_t *,
__uint64_t *, __uint64_t *);
void (*trace_key)(struct xfs_btree_cur *,
union xfs_btree_key *, __uint64_t *,
__uint64_t *);
void (*trace_record)(struct xfs_btree_cur *,
union xfs_btree_rec *, __uint64_t *,
__uint64_t *, __uint64_t *);
#endif
};
/*
* Reasons for the update_lastrec method to be called.
*/
#define LASTREC_UPDATE 0
#define LASTREC_INSREC 1
#define LASTREC_DELREC 2
/*
* Btree cursor structure.
* This collects all information needed by the btree code in one place.
@ -144,6 +238,8 @@ typedef struct xfs_btree_cur
{
struct xfs_trans *bc_tp; /* transaction we're in, if any */
struct xfs_mount *bc_mp; /* file system mount struct */
const struct xfs_btree_ops *bc_ops;
uint bc_flags; /* btree features - below */
union {
xfs_alloc_rec_incore_t a;
xfs_bmbt_irec_t b;
@ -175,94 +271,40 @@ typedef struct xfs_btree_cur
} bc_private; /* per-btree type data */
} xfs_btree_cur_t;
/* cursor flags */
#define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */
#define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */
#define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */
#define XFS_BTREE_NOERROR 0
#define XFS_BTREE_ERROR 1
/*
* Convert from buffer to btree block header.
*/
#define XFS_BUF_TO_BLOCK(bp) ((xfs_btree_block_t *)XFS_BUF_PTR(bp))
#define XFS_BUF_TO_LBLOCK(bp) ((xfs_btree_lblock_t *)XFS_BUF_PTR(bp))
#define XFS_BUF_TO_SBLOCK(bp) ((xfs_btree_sblock_t *)XFS_BUF_PTR(bp))
#define XFS_BUF_TO_BLOCK(bp) ((struct xfs_btree_block *)XFS_BUF_PTR(bp))
#ifdef __KERNEL__
#ifdef DEBUG
/*
* Debug routine: check that block header is ok.
* Check that block header is ok.
*/
void
int
xfs_btree_check_block(
xfs_btree_cur_t *cur, /* btree cursor */
xfs_btree_block_t *block, /* generic btree block pointer */
struct xfs_btree_cur *cur, /* btree cursor */
struct xfs_btree_block *block, /* generic btree block pointer */
int level, /* level of the btree block */
struct xfs_buf *bp); /* buffer containing block, if any */
/*
* Debug routine: check that keys are in the right order.
*/
void
xfs_btree_check_key(
xfs_btnum_t btnum, /* btree identifier */
void *ak1, /* pointer to left (lower) key */
void *ak2); /* pointer to right (higher) key */
/*
* Debug routine: check that records are in the right order.
*/
void
xfs_btree_check_rec(
xfs_btnum_t btnum, /* btree identifier */
void *ar1, /* pointer to left (lower) record */
void *ar2); /* pointer to right (higher) record */
#else
#define xfs_btree_check_block(a,b,c,d)
#define xfs_btree_check_key(a,b,c)
#define xfs_btree_check_rec(a,b,c)
#endif /* DEBUG */
/*
* Checking routine: check that long form block header is ok.
*/
int /* error (0 or EFSCORRUPTED) */
xfs_btree_check_lblock(
xfs_btree_cur_t *cur, /* btree cursor */
xfs_btree_lblock_t *block, /* btree long form block pointer */
int level, /* level of the btree block */
struct xfs_buf *bp); /* buffer containing block, if any */
/*
* Checking routine: check that (long) pointer is ok.
* Check that (long) pointer is ok.
*/
int /* error (0 or EFSCORRUPTED) */
xfs_btree_check_lptr(
xfs_btree_cur_t *cur, /* btree cursor */
struct xfs_btree_cur *cur, /* btree cursor */
xfs_dfsbno_t ptr, /* btree block disk address */
int level); /* btree block level */
#define xfs_btree_check_lptr_disk(cur, ptr, level) \
xfs_btree_check_lptr(cur, be64_to_cpu(ptr), level)
/*
* Checking routine: check that short form block header is ok.
*/
int /* error (0 or EFSCORRUPTED) */
xfs_btree_check_sblock(
xfs_btree_cur_t *cur, /* btree cursor */
xfs_btree_sblock_t *block, /* btree short form block pointer */
int level, /* level of the btree block */
struct xfs_buf *bp); /* buffer containing block */
/*
* Checking routine: check that (short) pointer is ok.
*/
int /* error (0 or EFSCORRUPTED) */
xfs_btree_check_sptr(
xfs_btree_cur_t *cur, /* btree cursor */
xfs_agblock_t ptr, /* btree block disk address */
int level); /* btree block level */
/*
* Delete the btree cursor.
*/
@ -280,15 +322,6 @@ xfs_btree_dup_cursor(
xfs_btree_cur_t *cur, /* input cursor */
xfs_btree_cur_t **ncur);/* output cursor */
/*
* Change the cursor to point to the first record in the current block
* at the given level. Other levels are unaffected.
*/
int /* success=1, failure=0 */
xfs_btree_firstrec(
xfs_btree_cur_t *cur, /* btree cursor */
int level); /* level to change */
/*
* Get a buffer for the block, return it with no data read.
* Long-form addressing.
@ -312,20 +345,6 @@ xfs_btree_get_bufs(
xfs_agblock_t agbno, /* allocation group block number */
uint lock); /* lock flags for get_buf */
/*
* Allocate a new btree cursor.
* The cursor is either for allocation (A) or bmap (B).
*/
xfs_btree_cur_t * /* new btree cursor */
xfs_btree_init_cursor(
struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */
struct xfs_buf *agbp, /* (A only) buffer for agf structure */
xfs_agnumber_t agno, /* (A only) allocation group number */
xfs_btnum_t btnum, /* btree identifier */
struct xfs_inode *ip, /* (B only) inode owning the btree */
int whichfork); /* (B only) data/attr fork */
/*
* Check for the cursor referring to the last block at the given level.
*/
@ -334,15 +353,6 @@ xfs_btree_islastblock(
xfs_btree_cur_t *cur, /* btree cursor */
int level); /* level to check */
/*
* Change the cursor to point to the last record in the current block
* at the given level. Other levels are unaffected.
*/
int /* success=1, failure=0 */
xfs_btree_lastrec(
xfs_btree_cur_t *cur, /* btree cursor */
int level); /* level to change */
/*
* Compute first and last byte offsets for the fields given.
* Interprets the offsets table, which contains struct field offsets.
@ -403,29 +413,6 @@ xfs_btree_reada_bufs(
xfs_agblock_t agbno, /* allocation group block number */
xfs_extlen_t count); /* count of filesystem blocks */
/*
* Read-ahead btree blocks, at the given level.
* Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA.
*/
int /* readahead block count */
xfs_btree_readahead_core(
xfs_btree_cur_t *cur, /* btree cursor */
int lev, /* level in btree */
int lr); /* left/right bits */
static inline int /* readahead block count */
xfs_btree_readahead(
xfs_btree_cur_t *cur, /* btree cursor */
int lev, /* level in btree */
int lr) /* left/right bits */
{
if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev])
return 0;
return xfs_btree_readahead_core(cur, lev, lr);
}
/*
* Set the buffer for level "lev" in the cursor to bp, releasing
* any previous buffer.
@ -436,7 +423,44 @@ xfs_btree_setbuf(
int lev, /* level in btree */
struct xfs_buf *bp); /* new buffer to set */
#endif /* __KERNEL__ */
/*
* Common btree core entry points.
*/
int xfs_btree_increment(struct xfs_btree_cur *, int, int *);
int xfs_btree_decrement(struct xfs_btree_cur *, int, int *);
int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *);
int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *);
int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *);
int xfs_btree_kill_iroot(struct xfs_btree_cur *);
int xfs_btree_insert(struct xfs_btree_cur *, int *);
int xfs_btree_delete(struct xfs_btree_cur *, int *);
int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *);
/*
* Internal btree helpers also used by xfs_bmap.c.
*/
void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int);
void xfs_btree_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int, int);
/*
* Helpers.
*/
static inline int xfs_btree_get_numrecs(struct xfs_btree_block *block)
{
return be16_to_cpu(block->bb_numrecs);
}
static inline void xfs_btree_set_numrecs(struct xfs_btree_block *block,
__uint16_t numrecs)
{
block->bb_numrecs = cpu_to_be16(numrecs);
}
static inline int xfs_btree_get_level(struct xfs_btree_block *block)
{
return be16_to_cpu(block->bb_level);
}
/*

249
fs/xfs/xfs_btree_trace.c Normal file
View File

@ -0,0 +1,249 @@
/*
* Copyright (c) 2008 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
*/
#include "xfs.h"
#include "xfs_types.h"
#include "xfs_inum.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
#include "xfs_btree_trace.h"
STATIC void
xfs_btree_trace_ptr(
struct xfs_btree_cur *cur,
union xfs_btree_ptr ptr,
__psunsigned_t *high,
__psunsigned_t *low)
{
if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
__u64 val = be64_to_cpu(ptr.l);
*high = val >> 32;
*low = (int)val;
} else {
*high = 0;
*low = be32_to_cpu(ptr.s);
}
}
/*
* Add a trace buffer entry for arguments, for a buffer & 1 integer arg.
*/
void
xfs_btree_trace_argbi(
const char *func,
struct xfs_btree_cur *cur,
struct xfs_buf *b,
int i,
int line)
{
cur->bc_ops->trace_enter(cur, func, XBT_ARGS, XFS_BTREE_KTRACE_ARGBI,
line, (__psunsigned_t)b, i, 0, 0, 0, 0, 0,
0, 0, 0, 0);
}
/*
* Add a trace buffer entry for arguments, for a buffer & 2 integer args.
*/
void
xfs_btree_trace_argbii(
const char *func,
struct xfs_btree_cur *cur,
struct xfs_buf *b,
int i0,
int i1,
int line)
{
cur->bc_ops->trace_enter(cur, func, XBT_ARGS, XFS_BTREE_KTRACE_ARGBII,
line, (__psunsigned_t)b, i0, i1, 0, 0, 0, 0,
0, 0, 0, 0);
}
/*
* Add a trace buffer entry for arguments, for 3 block-length args
* and an integer arg.
*/
void
xfs_btree_trace_argfffi(
const char *func,
struct xfs_btree_cur *cur,
xfs_dfiloff_t o,
xfs_dfsbno_t b,
xfs_dfilblks_t i,
int j,
int line)
{
cur->bc_ops->trace_enter(cur, func, XBT_ARGS, XFS_BTREE_KTRACE_ARGFFFI,
line,
o >> 32, (int)o,
b >> 32, (int)b,
i >> 32, (int)i,
(int)j, 0, 0, 0, 0);
}
/*
* Add a trace buffer entry for arguments, for one integer arg.
*/
void
xfs_btree_trace_argi(
const char *func,
struct xfs_btree_cur *cur,
int i,
int line)
{
cur->bc_ops->trace_enter(cur, func, XBT_ARGS, XFS_BTREE_KTRACE_ARGI,
line, i, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
/*
* Add a trace buffer entry for arguments, for int, fsblock, key.
*/
void
xfs_btree_trace_argipk(
const char *func,
struct xfs_btree_cur *cur,
int i,
union xfs_btree_ptr ptr,
union xfs_btree_key *key,
int line)
{
__psunsigned_t high, low;
__uint64_t l0, l1;
xfs_btree_trace_ptr(cur, ptr, &high, &low);
cur->bc_ops->trace_key(cur, key, &l0, &l1);
cur->bc_ops->trace_enter(cur, func, XBT_ARGS, XFS_BTREE_KTRACE_ARGIPK,
line, i, high, low,
l0 >> 32, (int)l0,
l1 >> 32, (int)l1,
0, 0, 0, 0);
}
/*
* Add a trace buffer entry for arguments, for int, fsblock, rec.
*/
void
xfs_btree_trace_argipr(
const char *func,
struct xfs_btree_cur *cur,
int i,
union xfs_btree_ptr ptr,
union xfs_btree_rec *rec,
int line)
{
__psunsigned_t high, low;
__uint64_t l0, l1, l2;
xfs_btree_trace_ptr(cur, ptr, &high, &low);
cur->bc_ops->trace_record(cur, rec, &l0, &l1, &l2);
cur->bc_ops->trace_enter(cur, func, XBT_ARGS, XFS_BTREE_KTRACE_ARGIPR,
line, i,
high, low,
l0 >> 32, (int)l0,
l1 >> 32, (int)l1,
l2 >> 32, (int)l2,
0, 0);
}
/*
* Add a trace buffer entry for arguments, for int, key.
*/
void
xfs_btree_trace_argik(
const char *func,
struct xfs_btree_cur *cur,
int i,
union xfs_btree_key *key,
int line)
{
__uint64_t l0, l1;
cur->bc_ops->trace_key(cur, key, &l0, &l1);
cur->bc_ops->trace_enter(cur, func, XBT_ARGS, XFS_BTREE_KTRACE_ARGIK,
line, i,
l0 >> 32, (int)l0,
l1 >> 32, (int)l1,
0, 0, 0, 0, 0, 0);
}
/*
* Add a trace buffer entry for arguments, for record.
*/
void
xfs_btree_trace_argr(
const char *func,
struct xfs_btree_cur *cur,
union xfs_btree_rec *rec,
int line)
{
__uint64_t l0, l1, l2;
cur->bc_ops->trace_record(cur, rec, &l0, &l1, &l2);
cur->bc_ops->trace_enter(cur, func, XBT_ARGS, XFS_BTREE_KTRACE_ARGR,
line,
l0 >> 32, (int)l0,
l1 >> 32, (int)l1,
l2 >> 32, (int)l2,
0, 0, 0, 0, 0);
}
/*
* Add a trace buffer entry for the cursor/operation.
*/
void
xfs_btree_trace_cursor(
const char *func,
struct xfs_btree_cur *cur,
int type,
int line)
{
__uint32_t s0;
__uint64_t l0, l1;
char *s;
switch (type) {
case XBT_ARGS:
s = "args";
break;
case XBT_ENTRY:
s = "entry";
break;
case XBT_ERROR:
s = "error";
break;
case XBT_EXIT:
s = "exit";
break;
default:
s = "unknown";
break;
}
cur->bc_ops->trace_cursor(cur, &s0, &l0, &l1);
cur->bc_ops->trace_enter(cur, func, s, XFS_BTREE_KTRACE_CUR, line,
s0,
l0 >> 32, (int)l0,
l1 >> 32, (int)l1,
(__psunsigned_t)cur->bc_bufs[0],
(__psunsigned_t)cur->bc_bufs[1],
(__psunsigned_t)cur->bc_bufs[2],
(__psunsigned_t)cur->bc_bufs[3],
(cur->bc_ptrs[0] << 16) | cur->bc_ptrs[1],
(cur->bc_ptrs[2] << 16) | cur->bc_ptrs[3]);
}

116
fs/xfs/xfs_btree_trace.h Normal file
View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2008 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_BTREE_TRACE_H__
#define __XFS_BTREE_TRACE_H__
struct xfs_btree_cur;
struct xfs_buf;
/*
* Trace hooks.
* i,j = integer (32 bit)
* b = btree block buffer (xfs_buf_t)
* p = btree ptr
* r = btree record
* k = btree key
*/
#ifdef XFS_BTREE_TRACE
/*
* Trace buffer entry types.
*/
#define XFS_BTREE_KTRACE_ARGBI 1
#define XFS_BTREE_KTRACE_ARGBII 2
#define XFS_BTREE_KTRACE_ARGFFFI 3
#define XFS_BTREE_KTRACE_ARGI 4
#define XFS_BTREE_KTRACE_ARGIPK 5
#define XFS_BTREE_KTRACE_ARGIPR 6
#define XFS_BTREE_KTRACE_ARGIK 7
#define XFS_BTREE_KTRACE_ARGR 8
#define XFS_BTREE_KTRACE_CUR 9
/*
* Sub-types for cursor traces.
*/
#define XBT_ARGS 0
#define XBT_ENTRY 1
#define XBT_ERROR 2
#define XBT_EXIT 3
void xfs_btree_trace_argbi(const char *, struct xfs_btree_cur *,
struct xfs_buf *, int, int);
void xfs_btree_trace_argbii(const char *, struct xfs_btree_cur *,
struct xfs_buf *, int, int, int);
void xfs_btree_trace_argfffi(const char *, struct xfs_btree_cur *,
xfs_dfiloff_t, xfs_dfsbno_t, xfs_dfilblks_t, int, int);
void xfs_btree_trace_argi(const char *, struct xfs_btree_cur *, int, int);
void xfs_btree_trace_argipk(const char *, struct xfs_btree_cur *, int,
union xfs_btree_ptr, union xfs_btree_key *, int);
void xfs_btree_trace_argipr(const char *, struct xfs_btree_cur *, int,
union xfs_btree_ptr, union xfs_btree_rec *, int);
void xfs_btree_trace_argik(const char *, struct xfs_btree_cur *, int,
union xfs_btree_key *, int);
void xfs_btree_trace_argr(const char *, struct xfs_btree_cur *,
union xfs_btree_rec *, int);
void xfs_btree_trace_cursor(const char *, struct xfs_btree_cur *, int, int);
#define XFS_ALLOCBT_TRACE_SIZE 4096 /* size of global trace buffer */
extern ktrace_t *xfs_allocbt_trace_buf;
#define XFS_INOBT_TRACE_SIZE 4096 /* size of global trace buffer */
extern ktrace_t *xfs_inobt_trace_buf;
#define XFS_BMBT_TRACE_SIZE 4096 /* size of global trace buffer */
#define XFS_BMBT_KTRACE_SIZE 32 /* size of per-inode trace buffer */
extern ktrace_t *xfs_bmbt_trace_buf;
#define XFS_BTREE_TRACE_ARGBI(c, b, i) \
xfs_btree_trace_argbi(__func__, c, b, i, __LINE__)
#define XFS_BTREE_TRACE_ARGBII(c, b, i, j) \
xfs_btree_trace_argbii(__func__, c, b, i, j, __LINE__)
#define XFS_BTREE_TRACE_ARGFFFI(c, o, b, i, j) \
xfs_btree_trace_argfffi(__func__, c, o, b, i, j, __LINE__)
#define XFS_BTREE_TRACE_ARGI(c, i) \
xfs_btree_trace_argi(__func__, c, i, __LINE__)
#define XFS_BTREE_TRACE_ARGIPK(c, i, p, k) \
xfs_btree_trace_argipk(__func__, c, i, p, k, __LINE__)
#define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) \
xfs_btree_trace_argipr(__func__, c, i, p, r, __LINE__)
#define XFS_BTREE_TRACE_ARGIK(c, i, k) \
xfs_btree_trace_argik(__func__, c, i, k, __LINE__)
#define XFS_BTREE_TRACE_ARGR(c, r) \
xfs_btree_trace_argr(__func__, c, r, __LINE__)
#define XFS_BTREE_TRACE_CURSOR(c, t) \
xfs_btree_trace_cursor(__func__, c, t, __LINE__)
#else
#define XFS_BTREE_TRACE_ARGBI(c, b, i)
#define XFS_BTREE_TRACE_ARGBII(c, b, i, j)
#define XFS_BTREE_TRACE_ARGFFFI(c, o, b, i, j)
#define XFS_BTREE_TRACE_ARGI(c, i)
#define XFS_BTREE_TRACE_ARGIPK(c, i, p, s)
#define XFS_BTREE_TRACE_ARGIPR(c, i, p, r)
#define XFS_BTREE_TRACE_ARGIK(c, i, k)
#define XFS_BTREE_TRACE_ARGR(c, r)
#define XFS_BTREE_TRACE_CURSOR(c, t)
#endif /* XFS_BTREE_TRACE */
#endif /* __XFS_BTREE_TRACE_H__ */

View File

@ -375,7 +375,7 @@ xfs_buf_item_unpin(
xfs_buf_log_item_t *bip,
int stale)
{
xfs_mount_t *mp;
struct xfs_ail *ailp;
xfs_buf_t *bp;
int freed;
@ -387,7 +387,7 @@ xfs_buf_item_unpin(
xfs_buftrace("XFS_UNPIN", bp);
freed = atomic_dec_and_test(&bip->bli_refcount);
mp = bip->bli_item.li_mountp;
ailp = bip->bli_item.li_ailp;
xfs_bunpin(bp);
if (freed && stale) {
ASSERT(bip->bli_flags & XFS_BLI_STALE);
@ -399,17 +399,17 @@ xfs_buf_item_unpin(
xfs_buftrace("XFS_UNPIN STALE", bp);
/*
* If we get called here because of an IO error, we may
* or may not have the item on the AIL. xfs_trans_delete_ail()
* or may not have the item on the AIL. xfs_trans_ail_delete()
* will take care of that situation.
* xfs_trans_delete_ail() drops the AIL lock.
* xfs_trans_ail_delete() drops the AIL lock.
*/
if (bip->bli_flags & XFS_BLI_STALE_INODE) {
xfs_buf_do_callbacks(bp, (xfs_log_item_t *)bip);
XFS_BUF_SET_FSPRIVATE(bp, NULL);
XFS_BUF_CLR_IODONE_FUNC(bp);
} else {
spin_lock(&mp->m_ail_lock);
xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip);
spin_lock(&ailp->xa_lock);
xfs_trans_ail_delete(ailp, (xfs_log_item_t *)bip);
xfs_buf_item_relse(bp);
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL);
}
@ -707,8 +707,8 @@ xfs_buf_item_init(
* the first. If we do already have one, there is
* nothing to do here so return.
*/
if (XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *) != mp)
XFS_BUF_SET_FSPRIVATE3(bp, mp);
if (bp->b_mount != mp)
bp->b_mount = mp;
XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb);
if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) {
lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
@ -731,6 +731,7 @@ xfs_buf_item_init(
bip->bli_item.li_type = XFS_LI_BUF;
bip->bli_item.li_ops = &xfs_buf_item_ops;
bip->bli_item.li_mountp = mp;
bip->bli_item.li_ailp = mp->m_ail;
bip->bli_buf = bp;
xfs_buf_hold(bp);
bip->bli_format.blf_type = XFS_LI_BUF;
@ -997,21 +998,7 @@ xfs_buf_iodone_callbacks(
xfs_buf_do_callbacks(bp, lip);
XFS_BUF_SET_FSPRIVATE(bp, NULL);
XFS_BUF_CLR_IODONE_FUNC(bp);
/*
* XFS_SHUT flag gets set when we go thru the
* entire buffer cache and deliberately start
* throwing away delayed write buffers.
* Since there's no biowait done on those,
* we should just brelse them.
*/
if (XFS_BUF_ISSHUT(bp)) {
XFS_BUF_UNSHUT(bp);
xfs_buf_relse(bp);
} else {
xfs_biodone(bp);
}
xfs_biodone(bp);
return;
}
@ -1122,27 +1109,23 @@ xfs_buf_iodone(
xfs_buf_t *bp,
xfs_buf_log_item_t *bip)
{
struct xfs_mount *mp;
struct xfs_ail *ailp = bip->bli_item.li_ailp;
ASSERT(bip->bli_buf == bp);
xfs_buf_rele(bp);
mp = bip->bli_item.li_mountp;
/*
* If we are forcibly shutting down, this may well be
* off the AIL already. That's because we simulate the
* log-committed callbacks to unpin these buffers. Or we may never
* have put this item on AIL because of the transaction was
* aborted forcibly. xfs_trans_delete_ail() takes care of these.
* aborted forcibly. xfs_trans_ail_delete() takes care of these.
*
* Either way, AIL is useless if we're forcing a shutdown.
*/
spin_lock(&mp->m_ail_lock);
/*
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip);
spin_lock(&ailp->xa_lock);
xfs_trans_ail_delete(ailp, (xfs_log_item_t *)bip);
xfs_buf_item_free(bip);
}

View File

@ -1,105 +0,0 @@
/*
* Copyright (c) 2000-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_CLNT_H__
#define __XFS_CLNT_H__
/*
* XFS arguments structure, constructed from the arguments we
* are passed via the mount system call.
*
* NOTE: The mount system call is handled differently between
* Linux and IRIX. In IRIX we worked work with a binary data
* structure coming in across the syscall interface from user
* space (the mount userspace knows about each filesystem type
* and the set of valid options for it, and converts the users
* argument string into a binary structure _before_ making the
* system call), and the ABI issues that this implies.
*
* In Linux, we are passed a comma separated set of options;
* ie. a NULL terminated string of characters. Userspace mount
* code does not have any knowledge of mount options expected by
* each filesystem type and so each filesystem parses its mount
* options in kernel space.
*
* For the Linux port, we kept this structure pretty much intact
* and use it internally (because the existing code groks it).
*/
struct xfs_mount_args {
int flags; /* flags -> see XFSMNT_... macros below */
int flags2; /* flags -> see XFSMNT2_... macros below */
int logbufs; /* Number of log buffers, -1 to default */
int logbufsize; /* Size of log buffers, -1 to default */
char fsname[MAXNAMELEN+1]; /* data device name */
char rtname[MAXNAMELEN+1]; /* realtime device filename */
char logname[MAXNAMELEN+1]; /* journal device filename */
char mtpt[MAXNAMELEN+1]; /* filesystem mount point */
int sunit; /* stripe unit (BBs) */
int swidth; /* stripe width (BBs), multiple of sunit */
uchar_t iosizelog; /* log2 of the preferred I/O size */
int ihashsize; /* inode hash table size (buckets) */
};
/*
* XFS mount option flags -- args->flags1
*/
#define XFSMNT_ATTR2 0x00000001 /* allow ATTR2 EA format */
#define XFSMNT_WSYNC 0x00000002 /* safe mode nfs mount
* compatible */
#define XFSMNT_INO64 0x00000004 /* move inode numbers up
* past 2^32 */
#define XFSMNT_UQUOTA 0x00000008 /* user quota accounting */
#define XFSMNT_PQUOTA 0x00000010 /* IRIX prj quota accounting */
#define XFSMNT_UQUOTAENF 0x00000020 /* user quota limit
* enforcement */
#define XFSMNT_PQUOTAENF 0x00000040 /* IRIX project quota limit
* enforcement */
#define XFSMNT_QUIET 0x00000080 /* don't report mount errors */
#define XFSMNT_NOALIGN 0x00000200 /* don't allocate at
* stripe boundaries*/
#define XFSMNT_RETERR 0x00000400 /* return error to user */
#define XFSMNT_NORECOVERY 0x00000800 /* no recovery, implies
* read-only mount */
#define XFSMNT_SHARED 0x00001000 /* shared XFS mount */
#define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */
#define XFSMNT_OSYNCISOSYNC 0x00004000 /* o_sync is REALLY o_sync */
/* (osyncisdsync is default) */
#define XFSMNT_NOATTR2 0x00008000 /* turn off ATTR2 EA format */
#define XFSMNT_32BITINODES 0x00200000 /* restrict inodes to 32
* bits of address space */
#define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */
#define XFSMNT_GQUOTAENF 0x00800000 /* group quota limit
* enforcement */
#define XFSMNT_NOUUID 0x01000000 /* Ignore fs uuid */
#define XFSMNT_DMAPI 0x02000000 /* enable dmapi/xdsm */
#define XFSMNT_BARRIER 0x04000000 /* use write barriers */
#define XFSMNT_IKEEP 0x08000000 /* inode cluster delete */
#define XFSMNT_SWALLOC 0x10000000 /* turn on stripe width
* allocation */
#define XFSMNT_DIRSYNC 0x40000000 /* sync creat,link,unlink,rename
* symlink,mkdir,rmdir,mknod */
#define XFSMNT_FLAGS2 0x80000000 /* more flags set in flags2 */
/*
* XFS mount option flags -- args->flags2
*/
#define XFSMNT2_COMPAT_IOSIZE 0x00000001 /* don't report large preferred
* I/O size in stat(2) */
#define XFSMNT2_FILESTREAMS 0x00000002 /* enable the filestreams
* allocator */
#endif /* __XFS_CLNT_H__ */

View File

@ -72,27 +72,7 @@ typedef struct xfs_da_intnode {
typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
typedef struct xfs_da_node_entry xfs_da_node_entry_t;
#define XFS_DA_MAXHASH ((xfs_dahash_t)-1) /* largest valid hash value */
#define XFS_LBSIZE(mp) (mp)->m_sb.sb_blocksize
#define XFS_LBLOG(mp) (mp)->m_sb.sb_blocklog
#define XFS_DA_MAKE_BNOENTRY(mp,bno,entry) \
(((bno) << (mp)->m_dircook_elog) | (entry))
#define XFS_DA_MAKE_COOKIE(mp,bno,entry,hash) \
(((xfs_off_t)XFS_DA_MAKE_BNOENTRY(mp, bno, entry) << 32) | (hash))
#define XFS_DA_COOKIE_HASH(mp,cookie) ((xfs_dahash_t)cookie)
#define XFS_DA_COOKIE_BNO(mp,cookie) \
((((xfs_off_t)(cookie) >> 31) == -1LL ? \
(xfs_dablk_t)0 : \
(xfs_dablk_t)((xfs_off_t)(cookie) >> \
((mp)->m_dircook_elog + 32))))
#define XFS_DA_COOKIE_ENTRY(mp,cookie) \
((((xfs_off_t)(cookie) >> 31) == -1LL ? \
(xfs_dablk_t)0 : \
(xfs_dablk_t)(((xfs_off_t)(cookie) >> 32) & \
((1 << (mp)->m_dircook_elog) - 1))))
/*========================================================================
* Btree searching and modification structure definitions.
@ -226,9 +206,8 @@ struct xfs_nameops {
};
#ifdef __KERNEL__
/*========================================================================
* Function prototypes for the kernel.
* Function prototypes.
*========================================================================*/
/*
@ -289,6 +268,5 @@ xfs_daddr_t xfs_da_blkno(xfs_dabuf_t *dabuf);
extern struct kmem_zone *xfs_da_state_zone;
extern struct kmem_zone *xfs_dabuf_zone;
#endif /* __KERNEL__ */
#endif /* __XFS_DA_BTREE_H__ */

View File

@ -49,9 +49,8 @@
*/
int
xfs_swapext(
xfs_swapext_t __user *sxu)
xfs_swapext_t *sxp)
{
xfs_swapext_t *sxp;
xfs_inode_t *ip, *tip;
struct file *file, *target_file;
int error = 0;
@ -62,11 +61,6 @@ xfs_swapext(
goto out;
}
if (copy_from_user(sxp, sxu, sizeof(xfs_swapext_t))) {
error = XFS_ERROR(EFAULT);
goto out_free_sxp;
}
/* Pull information for the target fd */
file = fget((int)sxp->sx_fdtarget);
if (!file) {

View File

@ -46,7 +46,7 @@ typedef struct xfs_swapext
/*
* Syscall interface for xfs_swapext
*/
int xfs_swapext(struct xfs_swapext __user *sx);
int xfs_swapext(struct xfs_swapext *sx);
int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
struct xfs_swapext *sxp);

View File

@ -18,32 +18,29 @@
#ifndef __XFS_DINODE_H__
#define __XFS_DINODE_H__
struct xfs_buf;
struct xfs_mount;
#define XFS_DINODE_MAGIC 0x494e /* 'IN' */
#define XFS_DINODE_GOOD_VERSION(v) (((v) == 1 || (v) == 2))
#define XFS_DINODE_VERSION_1 1
#define XFS_DINODE_VERSION_2 2
#define XFS_DINODE_GOOD_VERSION(v) \
(((v) == XFS_DINODE_VERSION_1 || (v) == XFS_DINODE_VERSION_2))
#define XFS_DINODE_MAGIC 0x494e /* 'IN' */
/*
* Disk inode structure.
* This is just the header; the inode is expanded to fill a variable size
* with the last field expanding. It is split into the core and "other"
* because we only need the core part in the in-core inode.
*/
typedef struct xfs_timestamp {
__be32 t_sec; /* timestamp seconds */
__be32 t_nsec; /* timestamp nanoseconds */
} xfs_timestamp_t;
/*
* Note: Coordinate changes to this structure with the XFS_DI_* #defines
* below, the offsets table in xfs_ialloc_log_di() and struct xfs_icdinode
* in xfs_inode.h.
* On-disk inode structure.
*
* This is just the header or "dinode core", the inode is expanded to fill a
* variable size the leftover area split into a data and an attribute fork.
* The format of the data and attribute fork depends on the format of the
* inode as indicated by di_format and di_aformat. To access the data and
* attribute use the XFS_DFORK_PTR, XFS_DFORK_DPTR, and XFS_DFORK_PTR macros
* below.
*
* There is a very similar struct icdinode in xfs_inode which matches the
* layout of the first 96 bytes of this structure, but is kept in native
* format instead of big endian.
*/
typedef struct xfs_dinode_core {
typedef struct xfs_dinode {
__be16 di_magic; /* inode magic # = XFS_DINODE_MAGIC */
__be16 di_mode; /* mode and type of file */
__u8 di_version; /* inode version */
@ -69,35 +66,13 @@ typedef struct xfs_dinode_core {
__be16 di_dmstate; /* DMIG state info */
__be16 di_flags; /* random flags, XFS_DIFLAG_... */
__be32 di_gen; /* generation number */
} xfs_dinode_core_t;
/* di_next_unlinked is the only non-core field in the old dinode */
__be32 di_next_unlinked;/* agi unlinked list ptr */
} __attribute__((packed)) xfs_dinode_t;
#define DI_MAX_FLUSH 0xffff
typedef struct xfs_dinode
{
xfs_dinode_core_t di_core;
/*
* In adding anything between the core and the union, be
* sure to update the macros like XFS_LITINO below and
* XFS_BMAP_RBLOCK_DSIZE in xfs_bmap_btree.h.
*/
__be32 di_next_unlinked;/* agi unlinked list ptr */
union {
xfs_bmdr_block_t di_bmbt; /* btree root block */
xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */
xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */
char di_c[1]; /* local contents */
__be32 di_dev; /* device for S_IFCHR/S_IFBLK */
uuid_t di_muuid; /* mount point value */
char di_symlink[1]; /* local symbolic link */
} di_u;
union {
xfs_bmdr_block_t di_abmbt; /* btree root block */
xfs_bmbt_rec_32_t di_abmx[1]; /* extent list */
xfs_attr_shortform_t di_attrsf; /* shortform attribute list */
} di_a;
} xfs_dinode_t;
/*
* The 32 bit link count in the inode theoretically maxes out at UINT_MAX.
* Since the pathconf interface is signed, we use 2^31 - 1 instead.
@ -106,51 +81,15 @@ typedef struct xfs_dinode
#define XFS_MAXLINK ((1U << 31) - 1U)
#define XFS_MAXLINK_1 65535U
/*
* Bit names for logging disk inodes only
*/
#define XFS_DI_MAGIC 0x0000001
#define XFS_DI_MODE 0x0000002
#define XFS_DI_VERSION 0x0000004
#define XFS_DI_FORMAT 0x0000008
#define XFS_DI_ONLINK 0x0000010
#define XFS_DI_UID 0x0000020
#define XFS_DI_GID 0x0000040
#define XFS_DI_NLINK 0x0000080
#define XFS_DI_PROJID 0x0000100
#define XFS_DI_PAD 0x0000200
#define XFS_DI_ATIME 0x0000400
#define XFS_DI_MTIME 0x0000800
#define XFS_DI_CTIME 0x0001000
#define XFS_DI_SIZE 0x0002000
#define XFS_DI_NBLOCKS 0x0004000
#define XFS_DI_EXTSIZE 0x0008000
#define XFS_DI_NEXTENTS 0x0010000
#define XFS_DI_NAEXTENTS 0x0020000
#define XFS_DI_FORKOFF 0x0040000
#define XFS_DI_AFORMAT 0x0080000
#define XFS_DI_DMEVMASK 0x0100000
#define XFS_DI_DMSTATE 0x0200000
#define XFS_DI_FLAGS 0x0400000
#define XFS_DI_GEN 0x0800000
#define XFS_DI_NEXT_UNLINKED 0x1000000
#define XFS_DI_U 0x2000000
#define XFS_DI_A 0x4000000
#define XFS_DI_NUM_BITS 27
#define XFS_DI_ALL_BITS ((1 << XFS_DI_NUM_BITS) - 1)
#define XFS_DI_CORE_BITS (XFS_DI_ALL_BITS & ~(XFS_DI_U|XFS_DI_A))
/*
* Values for di_format
*/
typedef enum xfs_dinode_fmt
{
XFS_DINODE_FMT_DEV, /* CHR, BLK: di_dev */
XFS_DINODE_FMT_LOCAL, /* DIR, REG: di_c */
/* LNK: di_symlink */
XFS_DINODE_FMT_EXTENTS, /* DIR, REG, LNK: di_bmx */
XFS_DINODE_FMT_BTREE, /* DIR, REG, LNK: di_bmbt */
XFS_DINODE_FMT_UUID /* MNT: di_uuid */
typedef enum xfs_dinode_fmt {
XFS_DINODE_FMT_DEV, /* xfs_dev_t */
XFS_DINODE_FMT_LOCAL, /* bulk data */
XFS_DINODE_FMT_EXTENTS, /* struct xfs_bmbt_rec */
XFS_DINODE_FMT_BTREE, /* struct xfs_bmdr_block */
XFS_DINODE_FMT_UUID /* uuid_t */
} xfs_dinode_fmt_t;
/*
@ -166,13 +105,13 @@ typedef enum xfs_dinode_fmt
*/
#define XFS_LITINO(mp) ((mp)->m_litino)
#define XFS_BROOT_SIZE_ADJ \
(sizeof(xfs_bmbt_block_t) - sizeof(xfs_bmdr_block_t))
(XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
/*
* Inode data & attribute fork sizes, per inode.
*/
#define XFS_DFORK_Q(dip) ((dip)->di_core.di_forkoff != 0)
#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_core.di_forkoff << 3))
#define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0)
#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3))
#define XFS_DFORK_DSIZE(dip,mp) \
(XFS_DFORK_Q(dip) ? \
@ -187,22 +126,41 @@ typedef enum xfs_dinode_fmt
XFS_DFORK_DSIZE(dip, mp) : \
XFS_DFORK_ASIZE(dip, mp))
#define XFS_DFORK_DPTR(dip) ((dip)->di_u.di_c)
/*
* Return pointers to the data or attribute forks.
*/
#define XFS_DFORK_DPTR(dip) \
((char *)(dip) + sizeof(struct xfs_dinode))
#define XFS_DFORK_APTR(dip) \
((dip)->di_u.di_c + XFS_DFORK_BOFF(dip))
(XFS_DFORK_DPTR(dip) + XFS_DFORK_BOFF(dip))
#define XFS_DFORK_PTR(dip,w) \
((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip))
#define XFS_DFORK_FORMAT(dip,w) \
((w) == XFS_DATA_FORK ? \
(dip)->di_core.di_format : \
(dip)->di_core.di_aformat)
(dip)->di_format : \
(dip)->di_aformat)
#define XFS_DFORK_NEXTENTS(dip,w) \
((w) == XFS_DATA_FORK ? \
be32_to_cpu((dip)->di_core.di_nextents) : \
be16_to_cpu((dip)->di_core.di_anextents))
be32_to_cpu((dip)->di_nextents) : \
be16_to_cpu((dip)->di_anextents))
#define XFS_BUF_TO_DINODE(bp) ((xfs_dinode_t *)XFS_BUF_PTR(bp))
/*
* For block and character special files the 32bit dev_t is stored at the
* beginning of the data fork.
*/
static inline xfs_dev_t xfs_dinode_get_rdev(struct xfs_dinode *dip)
{
return be32_to_cpu(*(__be32 *)XFS_DFORK_DPTR(dip));
}
static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
{
*(__be32 *)XFS_DFORK_DPTR(dip) = cpu_to_be32(rdev);
}
/*
* Values for di_flags
* There should be a one-to-one correspondence between these flags and the

View File

@ -33,13 +33,6 @@ struct xfs_inode;
struct xfs_mount;
struct xfs_trans;
/*
* Maximum size of a shortform directory.
*/
#define XFS_DIR2_SF_MAX_SIZE \
(XFS_DINODE_MAX_SIZE - (uint)sizeof(xfs_dinode_core_t) - \
(uint)sizeof(xfs_agino_t))
/*
* Inode number stored as 8 8-bit values.
*/

View File

@ -25,7 +25,6 @@
#include "xfs_inum.h"
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_clnt.h"
static struct xfs_dmops xfs_dmcore_stub = {
@ -38,9 +37,9 @@ static struct xfs_dmops xfs_dmcore_stub = {
};
int
xfs_dmops_get(struct xfs_mount *mp, struct xfs_mount_args *args)
xfs_dmops_get(struct xfs_mount *mp)
{
if (args->flags & XFSMNT_DMAPI) {
if (mp->m_flags & XFS_MOUNT_DMAPI) {
cmn_err(CE_WARN,
"XFS: dmapi support not available in this kernel.");
return EINVAL;

View File

@ -153,21 +153,6 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud)
}
#endif /* DEBUG */
static void
xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap)
{
if (mp != NULL) {
char *newfmt;
int len = 16 + mp->m_fsname_len + strlen(fmt);
newfmt = kmem_alloc(len, KM_SLEEP);
sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt);
icmn_err(level, newfmt, ap);
kmem_free(newfmt);
} else {
icmn_err(level, fmt, ap);
}
}
void
xfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)

View File

@ -159,11 +159,15 @@ extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud);
#define XFS_PTAG_FSBLOCK_ZERO 0x00000080
struct xfs_mount;
/* PRINTFLIKE4 */
extern void xfs_fs_vcmn_err(int level, struct xfs_mount *mp,
char *fmt, va_list ap)
__attribute__ ((format (printf, 3, 0)));
extern void xfs_cmn_err(int panic_tag, int level, struct xfs_mount *mp,
char *fmt, ...);
/* PRINTFLIKE3 */
extern void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...);
char *fmt, ...)
__attribute__ ((format (printf, 4, 5)));
extern void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...)
__attribute__ ((format (printf, 3, 4)));
extern void xfs_hex_dump(void *p, int length);

View File

@ -108,19 +108,16 @@ xfs_efi_item_pin(xfs_efi_log_item_t *efip)
STATIC void
xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale)
{
xfs_mount_t *mp;
struct xfs_ail *ailp = efip->efi_item.li_ailp;
mp = efip->efi_item.li_mountp;
spin_lock(&mp->m_ail_lock);
spin_lock(&ailp->xa_lock);
if (efip->efi_flags & XFS_EFI_CANCELED) {
/*
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip);
/* xfs_trans_ail_delete() drops the AIL lock. */
xfs_trans_ail_delete(ailp, (xfs_log_item_t *)efip);
xfs_efi_item_free(efip);
} else {
efip->efi_flags |= XFS_EFI_COMMITTED;
spin_unlock(&mp->m_ail_lock);
spin_unlock(&ailp->xa_lock);
}
}
@ -134,26 +131,23 @@ xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale)
STATIC void
xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp)
{
xfs_mount_t *mp;
struct xfs_ail *ailp = efip->efi_item.li_ailp;
xfs_log_item_desc_t *lidp;
mp = efip->efi_item.li_mountp;
spin_lock(&mp->m_ail_lock);
spin_lock(&ailp->xa_lock);
if (efip->efi_flags & XFS_EFI_CANCELED) {
/*
* free the xaction descriptor pointing to this item
*/
lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) efip);
xfs_trans_free_item(tp, lidp);
/*
* pull the item off the AIL.
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip);
/* xfs_trans_ail_delete() drops the AIL lock. */
xfs_trans_ail_delete(ailp, (xfs_log_item_t *)efip);
xfs_efi_item_free(efip);
} else {
efip->efi_flags |= XFS_EFI_COMMITTED;
spin_unlock(&mp->m_ail_lock);
spin_unlock(&ailp->xa_lock);
}
}
@ -268,6 +262,7 @@ xfs_efi_init(xfs_mount_t *mp,
efip->efi_item.li_type = XFS_LI_EFI;
efip->efi_item.li_ops = &xfs_efi_item_ops;
efip->efi_item.li_mountp = mp;
efip->efi_item.li_ailp = mp->m_ail;
efip->efi_format.efi_nextents = nextents;
efip->efi_format.efi_id = (__psint_t)(void*)efip;
@ -345,25 +340,22 @@ void
xfs_efi_release(xfs_efi_log_item_t *efip,
uint nextents)
{
xfs_mount_t *mp;
int extents_left;
struct xfs_ail *ailp = efip->efi_item.li_ailp;
int extents_left;
mp = efip->efi_item.li_mountp;
ASSERT(efip->efi_next_extent > 0);
ASSERT(efip->efi_flags & XFS_EFI_COMMITTED);
spin_lock(&mp->m_ail_lock);
spin_lock(&ailp->xa_lock);
ASSERT(efip->efi_next_extent >= nextents);
efip->efi_next_extent -= nextents;
extents_left = efip->efi_next_extent;
if (extents_left == 0) {
/*
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip);
/* xfs_trans_ail_delete() drops the AIL lock. */
xfs_trans_ail_delete(ailp, (xfs_log_item_t *)efip);
xfs_efi_item_free(efip);
} else {
spin_unlock(&mp->m_ail_lock);
spin_unlock(&ailp->xa_lock);
}
}
@ -565,6 +557,7 @@ xfs_efd_init(xfs_mount_t *mp,
efdp->efd_item.li_type = XFS_LI_EFD;
efdp->efd_item.li_ops = &xfs_efd_item_ops;
efdp->efd_item.li_mountp = mp;
efdp->efd_item.li_ailp = mp->m_ail;
efdp->efd_efip = efip;
efdp->efd_format.efd_nextents = nextents;
efdp->efd_format.efd_efi_id = efip->efi_format.efi_id;

View File

@ -113,22 +113,14 @@ struct getbmapx {
#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */
#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */
#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */
#define BMV_IF_VALID (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC)
#ifdef __KERNEL__
#define BMV_IF_EXTENDED 0x40000000 /* getpmapx if set */
#endif
#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */
#define BMV_IF_VALID \
(BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC|BMV_IF_DELALLOC)
/* bmv_oflags values - returned for for each non-header segment */
#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */
/* Convert getbmap <-> getbmapx - move fields from p1 to p2. */
#define GETBMAP_CONVERT(p1,p2) { \
p2.bmv_offset = p1.bmv_offset; \
p2.bmv_block = p1.bmv_block; \
p2.bmv_length = p1.bmv_length; \
p2.bmv_count = p1.bmv_count; \
p2.bmv_entries = p1.bmv_entries; }
#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */
#define BMV_OF_LAST 0x4 /* segment is the last in the file */
/*
* Structure for XFS_IOC_FSSETDM.
@ -426,10 +418,6 @@ typedef struct xfs_handle {
#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS
#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS
#define XFS_IOC_GETVERSION FS_IOC_GETVERSION
/* 32-bit compat counterparts */
#define XFS_IOC32_GETXFLAGS FS_IOC32_GETFLAGS
#define XFS_IOC32_SETXFLAGS FS_IOC32_SETFLAGS
#define XFS_IOC32_GETVERSION FS_IOC32_GETVERSION
/*
* ioctl commands that replace IRIX fcntl()'s

View File

@ -126,7 +126,7 @@ xfs_growfs_data_private(
xfs_extlen_t agsize;
xfs_extlen_t tmpsize;
xfs_alloc_rec_t *arec;
xfs_btree_sblock_t *block;
struct xfs_btree_block *block;
xfs_buf_t *bp;
int bucket;
int dpct;
@ -251,14 +251,14 @@ xfs_growfs_data_private(
bp = xfs_buf_get(mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)),
BTOBB(mp->m_sb.sb_blocksize), 0);
block = XFS_BUF_TO_SBLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
memset(block, 0, mp->m_sb.sb_blocksize);
block->bb_magic = cpu_to_be32(XFS_ABTB_MAGIC);
block->bb_level = 0;
block->bb_numrecs = cpu_to_be16(1);
block->bb_leftsib = cpu_to_be32(NULLAGBLOCK);
block->bb_rightsib = cpu_to_be32(NULLAGBLOCK);
arec = XFS_BTREE_REC_ADDR(xfs_alloc, block, 1);
block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
arec->ar_blockcount = cpu_to_be32(
agsize - be32_to_cpu(arec->ar_startblock));
@ -272,14 +272,14 @@ xfs_growfs_data_private(
bp = xfs_buf_get(mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)),
BTOBB(mp->m_sb.sb_blocksize), 0);
block = XFS_BUF_TO_SBLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
memset(block, 0, mp->m_sb.sb_blocksize);
block->bb_magic = cpu_to_be32(XFS_ABTC_MAGIC);
block->bb_level = 0;
block->bb_numrecs = cpu_to_be16(1);
block->bb_leftsib = cpu_to_be32(NULLAGBLOCK);
block->bb_rightsib = cpu_to_be32(NULLAGBLOCK);
arec = XFS_BTREE_REC_ADDR(xfs_alloc, block, 1);
block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
arec->ar_blockcount = cpu_to_be32(
agsize - be32_to_cpu(arec->ar_startblock));
@ -294,13 +294,13 @@ xfs_growfs_data_private(
bp = xfs_buf_get(mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)),
BTOBB(mp->m_sb.sb_blocksize), 0);
block = XFS_BUF_TO_SBLOCK(bp);
block = XFS_BUF_TO_BLOCK(bp);
memset(block, 0, mp->m_sb.sb_blocksize);
block->bb_magic = cpu_to_be32(XFS_IBT_MAGIC);
block->bb_level = 0;
block->bb_numrecs = 0;
block->bb_leftsib = cpu_to_be32(NULLAGBLOCK);
block->bb_rightsib = cpu_to_be32(NULLAGBLOCK);
block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
error = xfs_bwrite(mp, bp);
if (error) {
goto error0;
@ -435,6 +435,9 @@ xfs_growfs_data(
xfs_growfs_data_t *in)
{
int error;
if (!capable(CAP_SYS_ADMIN))
return XFS_ERROR(EPERM);
if (!mutex_trylock(&mp->m_growlock))
return XFS_ERROR(EWOULDBLOCK);
error = xfs_growfs_data_private(mp, in);
@ -448,6 +451,9 @@ xfs_growfs_log(
xfs_growfs_log_t *in)
{
int error;
if (!capable(CAP_SYS_ADMIN))
return XFS_ERROR(EPERM);
if (!mutex_trylock(&mp->m_growlock))
return XFS_ERROR(EWOULDBLOCK);
error = xfs_growfs_log_private(mp, in);

View File

@ -41,68 +41,6 @@
#include "xfs_error.h"
#include "xfs_bmap.h"
/*
* Log specified fields for the inode given by bp and off.
*/
STATIC void
xfs_ialloc_log_di(
xfs_trans_t *tp, /* transaction pointer */
xfs_buf_t *bp, /* inode buffer */
int off, /* index of inode in buffer */
int fields) /* bitmask of fields to log */
{
int first; /* first byte number */
int ioffset; /* off in bytes */
int last; /* last byte number */
xfs_mount_t *mp; /* mount point structure */
static const short offsets[] = { /* field offsets */
/* keep in sync with bits */
offsetof(xfs_dinode_core_t, di_magic),
offsetof(xfs_dinode_core_t, di_mode),
offsetof(xfs_dinode_core_t, di_version),
offsetof(xfs_dinode_core_t, di_format),
offsetof(xfs_dinode_core_t, di_onlink),
offsetof(xfs_dinode_core_t, di_uid),
offsetof(xfs_dinode_core_t, di_gid),
offsetof(xfs_dinode_core_t, di_nlink),
offsetof(xfs_dinode_core_t, di_projid),
offsetof(xfs_dinode_core_t, di_pad),
offsetof(xfs_dinode_core_t, di_atime),
offsetof(xfs_dinode_core_t, di_mtime),
offsetof(xfs_dinode_core_t, di_ctime),
offsetof(xfs_dinode_core_t, di_size),
offsetof(xfs_dinode_core_t, di_nblocks),
offsetof(xfs_dinode_core_t, di_extsize),
offsetof(xfs_dinode_core_t, di_nextents),
offsetof(xfs_dinode_core_t, di_anextents),
offsetof(xfs_dinode_core_t, di_forkoff),
offsetof(xfs_dinode_core_t, di_aformat),
offsetof(xfs_dinode_core_t, di_dmevmask),
offsetof(xfs_dinode_core_t, di_dmstate),
offsetof(xfs_dinode_core_t, di_flags),
offsetof(xfs_dinode_core_t, di_gen),
offsetof(xfs_dinode_t, di_next_unlinked),
offsetof(xfs_dinode_t, di_u),
offsetof(xfs_dinode_t, di_a),
sizeof(xfs_dinode_t)
};
ASSERT(offsetof(xfs_dinode_t, di_core) == 0);
ASSERT((fields & (XFS_DI_U|XFS_DI_A)) == 0);
mp = tp->t_mountp;
/*
* Get the inode-relative first and last bytes for these fields
*/
xfs_btree_offsets(fields, offsets, XFS_DI_NUM_BITS, &first, &last);
/*
* Convert to buffer offsets and log it.
*/
ioffset = off << mp->m_sb.sb_inodelog;
first += ioffset;
last += ioffset;
xfs_trans_log_buf(tp, bp, first, last);
}
/*
* Allocation group level functions.
@ -118,6 +56,102 @@ xfs_ialloc_cluster_alignment(
return 1;
}
/*
* Lookup the record equal to ino in the btree given by cur.
*/
STATIC int /* error */
xfs_inobt_lookup_eq(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agino_t ino, /* starting inode of chunk */
__int32_t fcnt, /* free inode count */
xfs_inofree_t free, /* free inode mask */
int *stat) /* success/failure */
{
cur->bc_rec.i.ir_startino = ino;
cur->bc_rec.i.ir_freecount = fcnt;
cur->bc_rec.i.ir_free = free;
return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
}
/*
* Lookup the first record greater than or equal to ino
* in the btree given by cur.
*/
int /* error */
xfs_inobt_lookup_ge(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agino_t ino, /* starting inode of chunk */
__int32_t fcnt, /* free inode count */
xfs_inofree_t free, /* free inode mask */
int *stat) /* success/failure */
{
cur->bc_rec.i.ir_startino = ino;
cur->bc_rec.i.ir_freecount = fcnt;
cur->bc_rec.i.ir_free = free;
return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat);
}
/*
* Lookup the first record less than or equal to ino
* in the btree given by cur.
*/
int /* error */
xfs_inobt_lookup_le(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agino_t ino, /* starting inode of chunk */
__int32_t fcnt, /* free inode count */
xfs_inofree_t free, /* free inode mask */
int *stat) /* success/failure */
{
cur->bc_rec.i.ir_startino = ino;
cur->bc_rec.i.ir_freecount = fcnt;
cur->bc_rec.i.ir_free = free;
return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
}
/*
* Update the record referred to by cur to the value given
* by [ino, fcnt, free].
* This either works (return 0) or gets an EFSCORRUPTED error.
*/
STATIC int /* error */
xfs_inobt_update(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agino_t ino, /* starting inode of chunk */
__int32_t fcnt, /* free inode count */
xfs_inofree_t free) /* free inode mask */
{
union xfs_btree_rec rec;
rec.inobt.ir_startino = cpu_to_be32(ino);
rec.inobt.ir_freecount = cpu_to_be32(fcnt);
rec.inobt.ir_free = cpu_to_be64(free);
return xfs_btree_update(cur, &rec);
}
/*
* Get the data from the pointed-to record.
*/
int /* error */
xfs_inobt_get_rec(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agino_t *ino, /* output: starting inode of chunk */
__int32_t *fcnt, /* output: number of free inodes */
xfs_inofree_t *free, /* output: free inode mask */
int *stat) /* output: success/failure */
{
union xfs_btree_rec *rec;
int error;
error = xfs_btree_get_rec(cur, &rec, stat);
if (!error && *stat == 1) {
*ino = be32_to_cpu(rec->inobt.ir_startino);
*fcnt = be32_to_cpu(rec->inobt.ir_freecount);
*free = be64_to_cpu(rec->inobt.ir_free);
}
return error;
}
/*
* Allocate new inodes in the allocation group specified by agbp.
* Return 0 for success, else error code.
@ -287,9 +321,9 @@ xfs_ialloc_ag_alloc(
* able to use the file system.
*/
if (xfs_sb_version_hasnlink(&args.mp->m_sb))
version = XFS_DINODE_VERSION_2;
version = 2;
else
version = XFS_DINODE_VERSION_1;
version = 1;
/*
* Seed the new inode cluster with a random generation number. This
@ -310,18 +344,25 @@ xfs_ialloc_ag_alloc(
XFS_BUF_LOCK);
ASSERT(fbuf);
ASSERT(!XFS_BUF_GETERROR(fbuf));
/*
* Set initial values for the inodes in this buffer.
* Initialize all inodes in this buffer and then log them.
*
* XXX: It would be much better if we had just one transaction to
* log a whole cluster of inodes instead of all the indivdual
* transactions causing a lot of log traffic.
*/
xfs_biozero(fbuf, 0, ninodes << args.mp->m_sb.sb_inodelog);
for (i = 0; i < ninodes; i++) {
int ioffset = i << args.mp->m_sb.sb_inodelog;
uint isize = sizeof(struct xfs_dinode);
free = XFS_MAKE_IPTR(args.mp, fbuf, i);
free->di_core.di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
free->di_core.di_version = version;
free->di_core.di_gen = cpu_to_be32(gen);
free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
free->di_version = version;
free->di_gen = cpu_to_be32(gen);
free->di_next_unlinked = cpu_to_be32(NULLAGINO);
xfs_ialloc_log_di(tp, fbuf, i,
XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED);
xfs_trans_log_buf(tp, fbuf, ioffset, ioffset + isize - 1);
}
xfs_trans_inode_alloc_buf(tp, fbuf);
}
@ -335,8 +376,7 @@ xfs_ialloc_ag_alloc(
/*
* Insert records describing the new inode chunk into the btree.
*/
cur = xfs_btree_init_cursor(args.mp, tp, agbp, agno,
XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
cur = xfs_inobt_init_cursor(args.mp, tp, agbp, agno);
for (thisino = newino;
thisino < newino + newlen;
thisino += XFS_INODES_PER_CHUNK) {
@ -346,7 +386,7 @@ xfs_ialloc_ag_alloc(
return error;
}
ASSERT(i == 0);
if ((error = xfs_inobt_insert(cur, &i))) {
if ((error = xfs_btree_insert(cur, &i))) {
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
return error;
}
@ -676,8 +716,7 @@ nextag:
*/
agno = tagno;
*IO_agbp = NULL;
cur = xfs_btree_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno),
XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno));
/*
* If pagino is 0 (this is the root inode allocation) use newino.
* This must work because we've just allocated some.
@ -697,7 +736,7 @@ nextag:
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
freecount += rec.ir_freecount;
if ((error = xfs_inobt_increment(cur, 0, &i)))
if ((error = xfs_btree_increment(cur, 0, &i)))
goto error0;
} while (i == 1);
@ -741,7 +780,7 @@ nextag:
/*
* Search left with tcur, back up 1 record.
*/
if ((error = xfs_inobt_decrement(tcur, 0, &i)))
if ((error = xfs_btree_decrement(tcur, 0, &i)))
goto error1;
doneleft = !i;
if (!doneleft) {
@ -755,7 +794,7 @@ nextag:
/*
* Search right with cur, go forward 1 record.
*/
if ((error = xfs_inobt_increment(cur, 0, &i)))
if ((error = xfs_btree_increment(cur, 0, &i)))
goto error1;
doneright = !i;
if (!doneright) {
@ -817,7 +856,7 @@ nextag:
* further left.
*/
if (useleft) {
if ((error = xfs_inobt_decrement(tcur, 0,
if ((error = xfs_btree_decrement(tcur, 0,
&i)))
goto error1;
doneleft = !i;
@ -837,7 +876,7 @@ nextag:
* further right.
*/
else {
if ((error = xfs_inobt_increment(cur, 0,
if ((error = xfs_btree_increment(cur, 0,
&i)))
goto error1;
doneright = !i;
@ -892,7 +931,7 @@ nextag:
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if (rec.ir_freecount > 0)
break;
if ((error = xfs_inobt_increment(cur, 0, &i)))
if ((error = xfs_btree_increment(cur, 0, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
}
@ -926,7 +965,7 @@ nextag:
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
freecount += rec.ir_freecount;
if ((error = xfs_inobt_increment(cur, 0, &i)))
if ((error = xfs_btree_increment(cur, 0, &i)))
goto error0;
} while (i == 1);
ASSERT(freecount == be32_to_cpu(agi->agi_freecount) ||
@ -1022,8 +1061,7 @@ xfs_difree(
/*
* Initialize the cursor.
*/
cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO,
(xfs_inode_t *)0, 0);
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
#ifdef DEBUG
if (cur->bc_nlevels == 1) {
int freecount = 0;
@ -1036,7 +1074,7 @@ xfs_difree(
goto error0;
if (i) {
freecount += rec.ir_freecount;
if ((error = xfs_inobt_increment(cur, 0, &i)))
if ((error = xfs_btree_increment(cur, 0, &i)))
goto error0;
}
} while (i == 1);
@ -1098,8 +1136,8 @@ xfs_difree(
xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen);
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1));
if ((error = xfs_inobt_delete(cur, &i))) {
cmn_err(CE_WARN, "xfs_difree: xfs_inobt_delete returned an error %d on %s.\n",
if ((error = xfs_btree_delete(cur, &i))) {
cmn_err(CE_WARN, "xfs_difree: xfs_btree_delete returned an error %d on %s.\n",
error, mp->m_fsname);
goto error0;
}
@ -1141,7 +1179,7 @@ xfs_difree(
goto error0;
if (i) {
freecount += rec.ir_freecount;
if ((error = xfs_inobt_increment(cur, 0, &i)))
if ((error = xfs_btree_increment(cur, 0, &i)))
goto error0;
}
} while (i == 1);
@ -1158,36 +1196,28 @@ error0:
}
/*
* Return the location of the inode in bno/off, for mapping it into a buffer.
* Return the location of the inode in imap, for mapping it into a buffer.
*/
/*ARGSUSED*/
int
xfs_dilocate(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
xfs_imap(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
xfs_ino_t ino, /* inode to locate */
xfs_fsblock_t *bno, /* output: block containing inode */
int *len, /* output: num blocks in inode cluster */
int *off, /* output: index in block of inode */
uint flags) /* flags concerning inode lookup */
struct xfs_imap *imap, /* location map structure */
uint flags) /* flags for inode btree lookup */
{
xfs_agblock_t agbno; /* block number of inode in the alloc group */
xfs_buf_t *agbp; /* agi buffer */
xfs_agino_t agino; /* inode number within alloc group */
xfs_agnumber_t agno; /* allocation group number */
int blks_per_cluster; /* num blocks per inode cluster */
xfs_agblock_t chunk_agbno; /* first block in inode chunk */
xfs_agino_t chunk_agino; /* first agino in inode chunk */
__int32_t chunk_cnt; /* count of free inodes in chunk */
xfs_inofree_t chunk_free; /* mask of free inodes in chunk */
xfs_agblock_t cluster_agbno; /* first block in inode cluster */
xfs_btree_cur_t *cur; /* inode btree cursor */
int error; /* error code */
int i; /* temp state */
int offset; /* index of inode in its buffer */
int offset_agbno; /* blks from chunk start to inode */
ASSERT(ino != NULLFSINO);
/*
* Split up the inode number into its parts.
*/
@ -1198,24 +1228,24 @@ xfs_dilocate(
ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
#ifdef DEBUG
/* no diagnostics for bulkstat, ino comes from userspace */
if (flags & XFS_IMAP_BULKSTAT)
if (flags & XFS_IGET_BULKSTAT)
return XFS_ERROR(EINVAL);
if (agno >= mp->m_sb.sb_agcount) {
xfs_fs_cmn_err(CE_ALERT, mp,
"xfs_dilocate: agno (%d) >= "
"xfs_imap: agno (%d) >= "
"mp->m_sb.sb_agcount (%d)",
agno, mp->m_sb.sb_agcount);
}
if (agbno >= mp->m_sb.sb_agblocks) {
xfs_fs_cmn_err(CE_ALERT, mp,
"xfs_dilocate: agbno (0x%llx) >= "
"xfs_imap: agbno (0x%llx) >= "
"mp->m_sb.sb_agblocks (0x%lx)",
(unsigned long long) agbno,
(unsigned long) mp->m_sb.sb_agblocks);
}
if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
xfs_fs_cmn_err(CE_ALERT, mp,
"xfs_dilocate: ino (0x%llx) != "
"xfs_imap: ino (0x%llx) != "
"XFS_AGINO_TO_INO(mp, agno, agino) "
"(0x%llx)",
ino, XFS_AGINO_TO_INO(mp, agno, agino));
@ -1224,65 +1254,89 @@ xfs_dilocate(
#endif /* DEBUG */
return XFS_ERROR(EINVAL);
}
if ((mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) ||
!(flags & XFS_IMAP_LOOKUP)) {
/*
* If the inode cluster size is the same as the blocksize or
* smaller we get to the buffer by simple arithmetics.
*/
if (XFS_INODE_CLUSTER_SIZE(mp) <= mp->m_sb.sb_blocksize) {
offset = XFS_INO_TO_OFFSET(mp, ino);
ASSERT(offset < mp->m_sb.sb_inopblock);
*bno = XFS_AGB_TO_FSB(mp, agno, agbno);
*off = offset;
*len = 1;
imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
imap->im_len = XFS_FSB_TO_BB(mp, 1);
imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
return 0;
}
blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;
if (*bno != NULLFSBLOCK) {
/*
* If we get a block number passed from bulkstat we can use it to
* find the buffer easily.
*/
if (imap->im_blkno) {
offset = XFS_INO_TO_OFFSET(mp, ino);
ASSERT(offset < mp->m_sb.sb_inopblock);
cluster_agbno = XFS_FSB_TO_AGBNO(mp, *bno);
*off = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
offset;
*len = blks_per_cluster;
cluster_agbno = XFS_DADDR_TO_AGBNO(mp, imap->im_blkno);
offset += (agbno - cluster_agbno) * mp->m_sb.sb_inopblock;
imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster);
imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
return 0;
}
/*
* If the inode chunks are aligned then use simple maths to
* find the location. Otherwise we have to do a btree
* lookup to find the location.
*/
if (mp->m_inoalign_mask) {
offset_agbno = agbno & mp->m_inoalign_mask;
chunk_agbno = agbno - offset_agbno;
} else {
xfs_btree_cur_t *cur; /* inode btree cursor */
xfs_agino_t chunk_agino; /* first agino in inode chunk */
__int32_t chunk_cnt; /* count of free inodes in chunk */
xfs_inofree_t chunk_free; /* mask of free inodes in chunk */
xfs_buf_t *agbp; /* agi buffer */
int i; /* temp state */
down_read(&mp->m_peraglock);
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
up_read(&mp->m_peraglock);
if (error) {
#ifdef DEBUG
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_ialloc_read_agi() returned "
"error %d, agno %d",
error, agno);
#endif /* DEBUG */
return error;
}
cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO,
(xfs_inode_t *)0, 0);
if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) {
#ifdef DEBUG
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i);
if (error) {
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_inobt_lookup_le() failed");
#endif /* DEBUG */
goto error0;
}
if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt,
&chunk_free, &i))) {
#ifdef DEBUG
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt,
&chunk_free, &i);
if (error) {
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_inobt_get_rec() failed");
#endif /* DEBUG */
goto error0;
}
if (i == 0) {
#ifdef DEBUG
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_inobt_get_rec() failed");
#endif /* DEBUG */
error = XFS_ERROR(EINVAL);
}
error0:
xfs_trans_brelse(tp, agbp);
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
if (error)
@ -1290,19 +1344,35 @@ xfs_dilocate(
chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino);
offset_agbno = agbno - chunk_agbno;
}
ASSERT(agbno >= chunk_agbno);
cluster_agbno = chunk_agbno +
((offset_agbno / blks_per_cluster) * blks_per_cluster);
offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
XFS_INO_TO_OFFSET(mp, ino);
*bno = XFS_AGB_TO_FSB(mp, agno, cluster_agbno);
*off = offset;
*len = blks_per_cluster;
imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno);
imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster);
imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
/*
* If the inode number maps to a block outside the bounds
* of the file system then return NULL rather than calling
* read_buf and panicing when we get an error from the
* driver.
*/
if ((imap->im_blkno + imap->im_len) >
XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"(imap->im_blkno (0x%llx) + imap->im_len (0x%llx)) > "
" XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) (0x%llx)",
(unsigned long long) imap->im_blkno,
(unsigned long long) imap->im_len,
XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
return XFS_ERROR(EINVAL);
}
return 0;
error0:
xfs_trans_brelse(tp, agbp);
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
return error;
}
/*
@ -1370,70 +1440,95 @@ xfs_ialloc_log_agi(
xfs_trans_log_buf(tp, bp, first, last);
}
#ifdef DEBUG
STATIC void
xfs_check_agi_unlinked(
struct xfs_agi *agi)
{
int i;
for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++)
ASSERT(agi->agi_unlinked[i]);
}
#else
#define xfs_check_agi_unlinked(agi)
#endif
/*
* Read in the allocation group header (inode allocation section)
*/
int
xfs_ialloc_read_agi(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */
xfs_buf_t **bpp) /* allocation group hdr buf */
xfs_read_agi(
struct xfs_mount *mp, /* file system mount structure */
struct xfs_trans *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */
struct xfs_buf **bpp) /* allocation group hdr buf */
{
xfs_agi_t *agi; /* allocation group header */
int agi_ok; /* agi is consistent */
xfs_buf_t *bp; /* allocation group hdr buf */
xfs_perag_t *pag; /* per allocation group data */
int error;
struct xfs_agi *agi; /* allocation group header */
int agi_ok; /* agi is consistent */
int error;
ASSERT(agno != NULLAGNUMBER);
error = xfs_trans_read_buf(
mp, tp, mp->m_ddev_targp,
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), 0, &bp);
XFS_FSS_TO_BB(mp, 1), 0, bpp);
if (error)
return error;
ASSERT(bp && !XFS_BUF_GETERROR(bp));
ASSERT(*bpp && !XFS_BUF_GETERROR(*bpp));
agi = XFS_BUF_TO_AGI(*bpp);
/*
* Validate the magic number of the agi block.
*/
agi = XFS_BUF_TO_AGI(bp);
agi_ok =
be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC &&
XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum));
agi_ok = be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC &&
XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)) &&
be32_to_cpu(agi->agi_seqno) == agno;
if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI,
XFS_RANDOM_IALLOC_READ_AGI))) {
XFS_CORRUPTION_ERROR("xfs_ialloc_read_agi", XFS_ERRLEVEL_LOW,
XFS_CORRUPTION_ERROR("xfs_read_agi", XFS_ERRLEVEL_LOW,
mp, agi);
xfs_trans_brelse(tp, bp);
xfs_trans_brelse(tp, *bpp);
return XFS_ERROR(EFSCORRUPTED);
}
XFS_BUF_SET_VTYPE_REF(*bpp, B_FS_AGI, XFS_AGI_REF);
xfs_check_agi_unlinked(agi);
return 0;
}
int
xfs_ialloc_read_agi(
struct xfs_mount *mp, /* file system mount structure */
struct xfs_trans *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */
struct xfs_buf **bpp) /* allocation group hdr buf */
{
struct xfs_agi *agi; /* allocation group header */
struct xfs_perag *pag; /* per allocation group data */
int error;
error = xfs_read_agi(mp, tp, agno, bpp);
if (error)
return error;
agi = XFS_BUF_TO_AGI(*bpp);
pag = &mp->m_perag[agno];
if (!pag->pagi_init) {
pag->pagi_freecount = be32_to_cpu(agi->agi_freecount);
pag->pagi_count = be32_to_cpu(agi->agi_count);
pag->pagi_init = 1;
} else {
/*
* It's possible for these to be out of sync if
* we are in the middle of a forced shutdown.
*/
ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) ||
XFS_FORCED_SHUTDOWN(mp));
}
#ifdef DEBUG
{
int i;
for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++)
ASSERT(agi->agi_unlinked[i]);
}
#endif
XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGI, XFS_AGI_REF);
*bpp = bp;
/*
* It's possible for these to be out of sync if
* we are in the middle of a forced shutdown.
*/
ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) ||
XFS_FORCED_SHUTDOWN(mp));
return 0;
}

View File

@ -20,6 +20,7 @@
struct xfs_buf;
struct xfs_dinode;
struct xfs_imap;
struct xfs_mount;
struct xfs_trans;
@ -56,7 +57,6 @@ static inline int xfs_ialloc_find_free(xfs_inofree_t *fp)
}
#ifdef __KERNEL__
/*
* Allocate an inode on disk.
* Mode is used to tell whether the new inode will need space, and whether
@ -105,17 +105,14 @@ xfs_difree(
xfs_ino_t *first_ino); /* first inode in deleted cluster */
/*
* Return the location of the inode in bno/len/off,
* for mapping it into a buffer.
* Return the location of the inode in imap, for mapping it into a buffer.
*/
int
xfs_dilocate(
xfs_imap(
struct xfs_mount *mp, /* file system mount structure */
struct xfs_trans *tp, /* transaction pointer */
xfs_ino_t ino, /* inode to locate */
xfs_fsblock_t *bno, /* output: block containing inode */
int *len, /* output: num blocks in cluster*/
int *off, /* output: index in block of inode */
struct xfs_imap *imap, /* location map structure */
uint flags); /* flags for inode btree lookup */
/*
@ -154,6 +151,24 @@ xfs_ialloc_pagi_init(
struct xfs_trans *tp, /* transaction pointer */
xfs_agnumber_t agno); /* allocation group number */
#endif /* __KERNEL__ */
/*
* Lookup the first record greater than or equal to ino
* in the btree given by cur.
*/
int xfs_inobt_lookup_ge(struct xfs_btree_cur *cur, xfs_agino_t ino,
__int32_t fcnt, xfs_inofree_t free, int *stat);
/*
* Lookup the first record less than or equal to ino
* in the btree given by cur.
*/
int xfs_inobt_lookup_le(struct xfs_btree_cur *cur, xfs_agino_t ino,
__int32_t fcnt, xfs_inofree_t free, int *stat);
/*
* Get the data from the pointed-to record.
*/
extern int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_agino_t *ino,
__int32_t *fcnt, xfs_inofree_t *free, int *stat);
#endif /* __XFS_IALLOC_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,6 @@
struct xfs_buf;
struct xfs_btree_cur;
struct xfs_btree_sblock;
struct xfs_mount;
/*
@ -70,11 +69,6 @@ typedef struct xfs_inobt_key {
/* btree pointer type */
typedef __be32 xfs_inobt_ptr_t;
/* btree block header type */
typedef struct xfs_btree_sblock xfs_inobt_block_t;
#define XFS_BUF_TO_INOBT_BLOCK(bp) ((xfs_inobt_block_t *)XFS_BUF_PTR(bp))
/*
* Bit manipulations for ir_free.
*/
@ -84,14 +78,6 @@ typedef struct xfs_btree_sblock xfs_inobt_block_t;
#define XFS_INOBT_SET_FREE(rp,i) ((rp)->ir_free |= XFS_INOBT_MASK(i))
#define XFS_INOBT_CLR_FREE(rp,i) ((rp)->ir_free &= ~XFS_INOBT_MASK(i))
/*
* Real block structures have a size equal to the disk block size.
*/
#define XFS_INOBT_BLOCK_MAXRECS(lev,cur) ((cur)->bc_mp->m_inobt_mxr[lev != 0])
#define XFS_INOBT_BLOCK_MINRECS(lev,cur) ((cur)->bc_mp->m_inobt_mnr[lev != 0])
#define XFS_INOBT_IS_LAST_REC(cur) \
((cur)->bc_ptrs[0] == be16_to_cpu(XFS_BUF_TO_INOBT_BLOCK((cur)->bc_bufs[0])->bb_numrecs))
/*
* Maximum number of inode btree levels.
*/
@ -103,76 +89,39 @@ typedef struct xfs_btree_sblock xfs_inobt_block_t;
#define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1))
#define XFS_PREALLOC_BLOCKS(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
/*
* Btree block header size depends on a superblock flag.
*
* (not quite yet, but soon)
*/
#define XFS_INOBT_BLOCK_LEN(mp) XFS_BTREE_SBLOCK_LEN
/*
* Record, key, and pointer address macros for btree blocks.
*
* (note that some of these may appear unused, but they are used in userspace)
*/
#define XFS_INOBT_REC_ADDR(bb,i,cur) \
(XFS_BTREE_REC_ADDR(xfs_inobt, bb, i))
#define XFS_INOBT_REC_ADDR(mp, block, index) \
((xfs_inobt_rec_t *) \
((char *)(block) + \
XFS_INOBT_BLOCK_LEN(mp) + \
(((index) - 1) * sizeof(xfs_inobt_rec_t))))
#define XFS_INOBT_KEY_ADDR(bb,i,cur) \
(XFS_BTREE_KEY_ADDR(xfs_inobt, bb, i))
#define XFS_INOBT_KEY_ADDR(mp, block, index) \
((xfs_inobt_key_t *) \
((char *)(block) + \
XFS_INOBT_BLOCK_LEN(mp) + \
((index) - 1) * sizeof(xfs_inobt_key_t)))
#define XFS_INOBT_PTR_ADDR(bb,i,cur) \
(XFS_BTREE_PTR_ADDR(xfs_inobt, bb, \
i, XFS_INOBT_BLOCK_MAXRECS(1, cur)))
#define XFS_INOBT_PTR_ADDR(mp, block, index, maxrecs) \
((xfs_inobt_ptr_t *) \
((char *)(block) + \
XFS_INOBT_BLOCK_LEN(mp) + \
(maxrecs) * sizeof(xfs_inobt_key_t) + \
((index) - 1) * sizeof(xfs_inobt_ptr_t)))
/*
* Decrement cursor by one record at the level.
* For nonzero levels the leaf-ward information is untouched.
*/
extern int xfs_inobt_decrement(struct xfs_btree_cur *cur, int level, int *stat);
/*
* Delete the record pointed to by cur.
* The cursor refers to the place where the record was (could be inserted)
* when the operation returns.
*/
extern int xfs_inobt_delete(struct xfs_btree_cur *cur, int *stat);
/*
* Get the data from the pointed-to record.
*/
extern int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_agino_t *ino,
__int32_t *fcnt, xfs_inofree_t *free, int *stat);
/*
* Increment cursor by one record at the level.
* For nonzero levels the leaf-ward information is untouched.
*/
extern int xfs_inobt_increment(struct xfs_btree_cur *cur, int level, int *stat);
/*
* Insert the current record at the point referenced by cur.
* The cursor may be inconsistent on return if splits have been done.
*/
extern int xfs_inobt_insert(struct xfs_btree_cur *cur, int *stat);
/*
* Lookup the record equal to ino in the btree given by cur.
*/
extern int xfs_inobt_lookup_eq(struct xfs_btree_cur *cur, xfs_agino_t ino,
__int32_t fcnt, xfs_inofree_t free, int *stat);
/*
* Lookup the first record greater than or equal to ino
* in the btree given by cur.
*/
extern int xfs_inobt_lookup_ge(struct xfs_btree_cur *cur, xfs_agino_t ino,
__int32_t fcnt, xfs_inofree_t free, int *stat);
/*
* Lookup the first record less than or equal to ino
* in the btree given by cur.
*/
extern int xfs_inobt_lookup_le(struct xfs_btree_cur *cur, xfs_agino_t ino,
__int32_t fcnt, xfs_inofree_t free, int *stat);
/*
* Update the record referred to by cur, to the value given
* by [ino, fcnt, free].
* This either works (return 0) or gets an EFSCORRUPTED error.
*/
extern int xfs_inobt_update(struct xfs_btree_cur *cur, xfs_agino_t ino,
__int32_t fcnt, xfs_inofree_t free);
extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t);
extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
#endif /* __XFS_IALLOC_BTREE_H__ */

View File

@ -38,15 +38,268 @@
#include "xfs_ialloc.h"
#include "xfs_quota.h"
#include "xfs_utils.h"
#include "xfs_trans_priv.h"
#include "xfs_inode_item.h"
#include "xfs_bmap.h"
#include "xfs_btree_trace.h"
#include "xfs_dir2_trace.h"
/*
* Allocate and initialise an xfs_inode.
*/
STATIC struct xfs_inode *
xfs_inode_alloc(
struct xfs_mount *mp,
xfs_ino_t ino)
{
struct xfs_inode *ip;
/*
* if this didn't occur in transactions, we could use
* KM_MAYFAIL and return NULL here on ENOMEM. Set the
* code up to do this anyway.
*/
ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP);
if (!ip)
return NULL;
ASSERT(atomic_read(&ip->i_iocount) == 0);
ASSERT(atomic_read(&ip->i_pincount) == 0);
ASSERT(!spin_is_locked(&ip->i_flags_lock));
ASSERT(completion_done(&ip->i_flush));
/*
* initialise the VFS inode here to get failures
* out of the way early.
*/
if (!inode_init_always(mp->m_super, VFS_I(ip))) {
kmem_zone_free(xfs_inode_zone, ip);
return NULL;
}
/* initialise the xfs inode */
ip->i_ino = ino;
ip->i_mount = mp;
memset(&ip->i_imap, 0, sizeof(struct xfs_imap));
ip->i_afp = NULL;
memset(&ip->i_df, 0, sizeof(xfs_ifork_t));
ip->i_flags = 0;
ip->i_update_core = 0;
ip->i_update_size = 0;
ip->i_delayed_blks = 0;
memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
ip->i_size = 0;
ip->i_new_size = 0;
/*
* Initialize inode's trace buffers.
*/
#ifdef XFS_INODE_TRACE
ip->i_trace = ktrace_alloc(INODE_TRACE_SIZE, KM_NOFS);
#endif
#ifdef XFS_BMAP_TRACE
ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_NOFS);
#endif
#ifdef XFS_BTREE_TRACE
ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_NOFS);
#endif
#ifdef XFS_RW_TRACE
ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_NOFS);
#endif
#ifdef XFS_ILOCK_TRACE
ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_NOFS);
#endif
#ifdef XFS_DIR2_TRACE
ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS);
#endif
return ip;
}
/*
* Check the validity of the inode we just found it the cache
*/
static int
xfs_iget_cache_hit(
struct xfs_perag *pag,
struct xfs_inode *ip,
int flags,
int lock_flags) __releases(pag->pag_ici_lock)
{
struct xfs_mount *mp = ip->i_mount;
int error = EAGAIN;
/*
* If INEW is set this inode is being set up
* If IRECLAIM is set this inode is being torn down
* Pause and try again.
*/
if (xfs_iflags_test(ip, (XFS_INEW|XFS_IRECLAIM))) {
XFS_STATS_INC(xs_ig_frecycle);
goto out_error;
}
/* If IRECLAIMABLE is set, we've torn down the vfs inode part */
if (xfs_iflags_test(ip, XFS_IRECLAIMABLE)) {
/*
* If lookup is racing with unlink, then we should return an
* error immediately so we don't remove it from the reclaim
* list and potentially leak the inode.
*/
if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
error = ENOENT;
goto out_error;
}
xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
/*
* We need to re-initialise the VFS inode as it has been
* 'freed' by the VFS. Do this here so we can deal with
* errors cleanly, then tag it so it can be set up correctly
* later.
*/
if (!inode_init_always(mp->m_super, VFS_I(ip))) {
error = ENOMEM;
goto out_error;
}
/*
* We must set the XFS_INEW flag before clearing the
* XFS_IRECLAIMABLE flag so that if a racing lookup does
* not find the XFS_IRECLAIMABLE above but has the igrab()
* below succeed we can safely check XFS_INEW to detect
* that this inode is still being initialised.
*/
xfs_iflags_set(ip, XFS_INEW);
xfs_iflags_clear(ip, XFS_IRECLAIMABLE);
/* clear the radix tree reclaim flag as well. */
__xfs_inode_clear_reclaim_tag(mp, pag, ip);
} else if (!igrab(VFS_I(ip))) {
/* If the VFS inode is being torn down, pause and try again. */
XFS_STATS_INC(xs_ig_frecycle);
goto out_error;
} else if (xfs_iflags_test(ip, XFS_INEW)) {
/*
* We are racing with another cache hit that is
* currently recycling this inode out of the XFS_IRECLAIMABLE
* state. Wait for the initialisation to complete before
* continuing.
*/
wait_on_inode(VFS_I(ip));
}
if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {
error = ENOENT;
iput(VFS_I(ip));
goto out_error;
}
/* We've got a live one. */
read_unlock(&pag->pag_ici_lock);
if (lock_flags != 0)
xfs_ilock(ip, lock_flags);
xfs_iflags_clear(ip, XFS_ISTALE);
xfs_itrace_exit_tag(ip, "xfs_iget.found");
XFS_STATS_INC(xs_ig_found);
return 0;
out_error:
read_unlock(&pag->pag_ici_lock);
return error;
}
static int
xfs_iget_cache_miss(
struct xfs_mount *mp,
struct xfs_perag *pag,
xfs_trans_t *tp,
xfs_ino_t ino,
struct xfs_inode **ipp,
xfs_daddr_t bno,
int flags,
int lock_flags) __releases(pag->pag_ici_lock)
{
struct xfs_inode *ip;
int error;
unsigned long first_index, mask;
xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ino);
ip = xfs_inode_alloc(mp, ino);
if (!ip)
return ENOMEM;
error = xfs_iread(mp, tp, ip, bno, flags);
if (error)
goto out_destroy;
xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
error = ENOENT;
goto out_destroy;
}
if (lock_flags)
xfs_ilock(ip, lock_flags);
/*
* Preload the radix tree so we can insert safely under the
* write spinlock. Note that we cannot sleep inside the preload
* region.
*/
if (radix_tree_preload(GFP_KERNEL)) {
error = EAGAIN;
goto out_unlock;
}
mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
first_index = agino & mask;
write_lock(&pag->pag_ici_lock);
/* insert the new inode */
error = radix_tree_insert(&pag->pag_ici_root, agino, ip);
if (unlikely(error)) {
WARN_ON(error != -EEXIST);
XFS_STATS_INC(xs_ig_dup);
error = EAGAIN;
goto out_preload_end;
}
/* These values _must_ be set before releasing the radix tree lock! */
ip->i_udquot = ip->i_gdquot = NULL;
xfs_iflags_set(ip, XFS_INEW);
write_unlock(&pag->pag_ici_lock);
radix_tree_preload_end();
*ipp = ip;
return 0;
out_preload_end:
write_unlock(&pag->pag_ici_lock);
radix_tree_preload_end();
out_unlock:
if (lock_flags)
xfs_iunlock(ip, lock_flags);
out_destroy:
xfs_destroy_inode(ip);
return error;
}
/*
* Look up an inode by number in the given file system.
* The inode is looked up in the cache held in each AG.
* If the inode is found in the cache, attach it to the provided
* vnode.
* If the inode is found in the cache, initialise the vfs inode
* if necessary.
*
* If it is not in core, read it in from the file system's device,
* add it to the cache and attach the provided vnode.
* add it to the cache and initialise the vfs inode.
*
* The inode is locked according to the value of the lock_flags parameter.
* This flag parameter indicates how and if the inode's IO lock and inode lock
@ -63,9 +316,8 @@
* bno -- the block number starting the buffer containing the inode,
* if known (as by bulkstat), else 0.
*/
STATIC int
xfs_iget_core(
struct inode *inode,
int
xfs_iget(
xfs_mount_t *mp,
xfs_trans_t *tp,
xfs_ino_t ino,
@ -74,11 +326,8 @@ xfs_iget_core(
xfs_inode_t **ipp,
xfs_daddr_t bno)
{
struct inode *old_inode;
xfs_inode_t *ip;
xfs_inode_t *iq;
int error;
unsigned long first_index, mask;
xfs_perag_t *pag;
xfs_agino_t agino;
@ -94,291 +343,47 @@ xfs_iget_core(
agino = XFS_INO_TO_AGINO(mp, ino);
again:
error = 0;
read_lock(&pag->pag_ici_lock);
ip = radix_tree_lookup(&pag->pag_ici_root, agino);
if (ip != NULL) {
/*
* If INEW is set this inode is being set up
* we need to pause and try again.
*/
if (xfs_iflags_test(ip, XFS_INEW)) {
read_unlock(&pag->pag_ici_lock);
delay(1);
XFS_STATS_INC(xs_ig_frecycle);
goto again;
}
old_inode = ip->i_vnode;
if (old_inode == NULL) {
/*
* If IRECLAIM is set this inode is
* on its way out of the system,
* we need to pause and try again.
*/
if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
read_unlock(&pag->pag_ici_lock);
delay(1);
XFS_STATS_INC(xs_ig_frecycle);
goto again;
}
ASSERT(xfs_iflags_test(ip, XFS_IRECLAIMABLE));
/*
* If lookup is racing with unlink, then we
* should return an error immediately so we
* don't remove it from the reclaim list and
* potentially leak the inode.
*/
if ((ip->i_d.di_mode == 0) &&
!(flags & XFS_IGET_CREATE)) {
read_unlock(&pag->pag_ici_lock);
xfs_put_perag(mp, pag);
return ENOENT;
}
xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
XFS_STATS_INC(xs_ig_found);
xfs_iflags_clear(ip, XFS_IRECLAIMABLE);
read_unlock(&pag->pag_ici_lock);
XFS_MOUNT_ILOCK(mp);
list_del_init(&ip->i_reclaim);
XFS_MOUNT_IUNLOCK(mp);
goto finish_inode;
} else if (inode != old_inode) {
/* The inode is being torn down, pause and
* try again.
*/
if (old_inode->i_state & (I_FREEING | I_CLEAR)) {
read_unlock(&pag->pag_ici_lock);
delay(1);
XFS_STATS_INC(xs_ig_frecycle);
goto again;
}
/* Chances are the other vnode (the one in the inode) is being torn
* down right now, and we landed on top of it. Question is, what do
* we do? Unhook the old inode and hook up the new one?
*/
cmn_err(CE_PANIC,
"xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p",
old_inode, inode);
}
/*
* Inode cache hit
*/
read_unlock(&pag->pag_ici_lock);
XFS_STATS_INC(xs_ig_found);
finish_inode:
if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {
xfs_put_perag(mp, pag);
return ENOENT;
}
if (lock_flags != 0)
xfs_ilock(ip, lock_flags);
xfs_iflags_clear(ip, XFS_ISTALE);
xfs_itrace_exit_tag(ip, "xfs_iget.found");
goto return_ip;
}
/*
* Inode cache miss
*/
read_unlock(&pag->pag_ici_lock);
XFS_STATS_INC(xs_ig_missed);
/*
* Read the disk inode attributes into a new inode structure and get
* a new vnode for it. This should also initialize i_ino and i_mount.
*/
error = xfs_iread(mp, tp, ino, &ip, bno,
(flags & XFS_IGET_BULKSTAT) ? XFS_IMAP_BULKSTAT : 0);
if (error) {
xfs_put_perag(mp, pag);
return error;
}
xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
"xfsino", ip->i_ino);
mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
init_waitqueue_head(&ip->i_ipin_wait);
atomic_set(&ip->i_pincount, 0);
/*
* Because we want to use a counting completion, complete
* the flush completion once to allow a single access to
* the flush completion without blocking.
*/
init_completion(&ip->i_flush);
complete(&ip->i_flush);
if (lock_flags)
xfs_ilock(ip, lock_flags);
if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
xfs_idestroy(ip);
xfs_put_perag(mp, pag);
return ENOENT;
}
/*
* Preload the radix tree so we can insert safely under the
* write spinlock.
*/
if (radix_tree_preload(GFP_KERNEL)) {
xfs_idestroy(ip);
delay(1);
goto again;
}
mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
first_index = agino & mask;
write_lock(&pag->pag_ici_lock);
/*
* insert the new inode
*/
error = radix_tree_insert(&pag->pag_ici_root, agino, ip);
if (unlikely(error)) {
BUG_ON(error != -EEXIST);
write_unlock(&pag->pag_ici_lock);
radix_tree_preload_end();
xfs_idestroy(ip);
XFS_STATS_INC(xs_ig_dup);
goto again;
}
/*
* These values _must_ be set before releasing the radix tree lock!
*/
ip->i_udquot = ip->i_gdquot = NULL;
xfs_iflags_set(ip, XFS_INEW);
write_unlock(&pag->pag_ici_lock);
radix_tree_preload_end();
/*
* Link ip to its mount and thread it on the mount's inode list.
*/
XFS_MOUNT_ILOCK(mp);
if ((iq = mp->m_inodes)) {
ASSERT(iq->i_mprev->i_mnext == iq);
ip->i_mprev = iq->i_mprev;
iq->i_mprev->i_mnext = ip;
iq->i_mprev = ip;
ip->i_mnext = iq;
if (ip) {
error = xfs_iget_cache_hit(pag, ip, flags, lock_flags);
if (error)
goto out_error_or_again;
} else {
ip->i_mnext = ip;
ip->i_mprev = ip;
}
mp->m_inodes = ip;
read_unlock(&pag->pag_ici_lock);
XFS_STATS_INC(xs_ig_missed);
XFS_MOUNT_IUNLOCK(mp);
error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip, bno,
flags, lock_flags);
if (error)
goto out_error_or_again;
}
xfs_put_perag(mp, pag);
return_ip:
ASSERT(ip->i_df.if_ext_max ==
XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
xfs_iflags_set(ip, XFS_IMODIFIED);
*ipp = ip;
/*
* Set up the Linux with the Linux inode.
*/
ip->i_vnode = inode;
inode->i_private = ip;
ASSERT(ip->i_df.if_ext_max ==
XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
/*
* If we have a real type for an on-disk inode, we can set ops(&unlock)
* now. If it's a new inode being created, xfs_ialloc will handle it.
*/
if (ip->i_d.di_mode != 0)
if (xfs_iflags_test(ip, XFS_INEW) && ip->i_d.di_mode != 0)
xfs_setup_inode(ip);
return 0;
out_error_or_again:
if (error == EAGAIN) {
delay(1);
goto again;
}
xfs_put_perag(mp, pag);
return error;
}
/*
* The 'normal' internal xfs_iget, if needed it will
* 'allocate', or 'get', the vnode.
*/
int
xfs_iget(
xfs_mount_t *mp,
xfs_trans_t *tp,
xfs_ino_t ino,
uint flags,
uint lock_flags,
xfs_inode_t **ipp,
xfs_daddr_t bno)
{
struct inode *inode;
xfs_inode_t *ip;
int error;
XFS_STATS_INC(xs_ig_attempts);
retry:
inode = iget_locked(mp->m_super, ino);
if (!inode)
/* If we got no inode we are out of memory */
return ENOMEM;
if (inode->i_state & I_NEW) {
XFS_STATS_INC(vn_active);
XFS_STATS_INC(vn_alloc);
error = xfs_iget_core(inode, mp, tp, ino, flags,
lock_flags, ipp, bno);
if (error) {
make_bad_inode(inode);
if (inode->i_state & I_NEW)
unlock_new_inode(inode);
iput(inode);
}
return error;
}
/*
* If the inode is not fully constructed due to
* filehandle mismatches wait for the inode to go
* away and try again.
*
* iget_locked will call __wait_on_freeing_inode
* to wait for the inode to go away.
*/
if (is_bad_inode(inode)) {
iput(inode);
delay(1);
goto retry;
}
ip = XFS_I(inode);
if (!ip) {
iput(inode);
delay(1);
goto retry;
}
if (lock_flags != 0)
xfs_ilock(ip, lock_flags);
XFS_STATS_INC(xs_ig_found);
*ipp = ip;
return 0;
}
/*
* Look for the inode corresponding to the given ino in the hash table.
* If it is there and its i_transp pointer matches tp, return it.
@ -444,99 +449,109 @@ xfs_iput_new(
IRELE(ip);
}
/*
* This routine embodies the part of the reclaim code that pulls
* the inode from the inode hash table and the mount structure's
* inode list.
* This should only be called from xfs_reclaim().
* This is called free all the memory associated with an inode.
* It must free the inode itself and any buffers allocated for
* if_extents/if_data and if_broot. It must also free the lock
* associated with the inode.
*
* Note: because we don't initialise everything on reallocation out
* of the zone, we must ensure we nullify everything correctly before
* freeing the structure.
*/
void
xfs_ireclaim(xfs_inode_t *ip)
xfs_ireclaim(
struct xfs_inode *ip)
{
/*
* Remove from old hash list and mount list.
*/
struct xfs_mount *mp = ip->i_mount;
struct xfs_perag *pag;
XFS_STATS_INC(xs_ig_reclaims);
xfs_iextract(ip);
/*
* Here we do a spurious inode lock in order to coordinate with
* xfs_sync(). This is because xfs_sync() references the inodes
* in the mount list without taking references on the corresponding
* vnodes. We make that OK here by ensuring that we wait until
* the inode is unlocked in xfs_sync() before we go ahead and
* free it. We get both the regular lock and the io lock because
* the xfs_sync() code may need to drop the regular one but will
* still hold the io lock.
* Remove the inode from the per-AG radix tree. It doesn't matter
* if it was never added to it because radix_tree_delete can deal
* with that case just fine.
*/
xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
/*
* Release dquots (and their references) if any. An inode may escape
* xfs_inactive and get here via vn_alloc->vn_reclaim path.
*/
XFS_QM_DQDETACH(ip->i_mount, ip);
/*
* Pull our behavior descriptor from the vnode chain.
*/
if (ip->i_vnode) {
ip->i_vnode->i_private = NULL;
ip->i_vnode = NULL;
}
/*
* Free all memory associated with the inode.
*/
xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_idestroy(ip);
}
/*
* This routine removes an about-to-be-destroyed inode from
* all of the lists in which it is located with the exception
* of the behavior chain.
*/
void
xfs_iextract(
xfs_inode_t *ip)
{
xfs_mount_t *mp = ip->i_mount;
xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino);
xfs_inode_t *iq;
pag = xfs_get_perag(mp, ip->i_ino);
write_lock(&pag->pag_ici_lock);
radix_tree_delete(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino));
write_unlock(&pag->pag_ici_lock);
xfs_put_perag(mp, pag);
/*
* Remove from mount's inode list.
* Here we do an (almost) spurious inode lock in order to coordinate
* with inode cache radix tree lookups. This is because the lookup
* can reference the inodes in the cache without taking references.
*
* We make that OK here by ensuring that we wait until the inode is
* unlocked after the lookup before we go ahead and free it. We get
* both the ilock and the iolock because the code may need to drop the
* ilock one but will still hold the iolock.
*/
XFS_MOUNT_ILOCK(mp);
ASSERT((ip->i_mnext != NULL) && (ip->i_mprev != NULL));
iq = ip->i_mnext;
iq->i_mprev = ip->i_mprev;
ip->i_mprev->i_mnext = iq;
xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
/*
* Fix up the head pointer if it points to the inode being deleted.
* Release dquots (and their references) if any.
*/
if (mp->m_inodes == ip) {
if (ip == iq) {
mp->m_inodes = NULL;
} else {
mp->m_inodes = iq;
}
XFS_QM_DQDETACH(ip->i_mount, ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
switch (ip->i_d.di_mode & S_IFMT) {
case S_IFREG:
case S_IFDIR:
case S_IFLNK:
xfs_idestroy_fork(ip, XFS_DATA_FORK);
break;
}
/* Deal with the deleted inodes list */
list_del_init(&ip->i_reclaim);
if (ip->i_afp)
xfs_idestroy_fork(ip, XFS_ATTR_FORK);
mp->m_ireclaims++;
XFS_MOUNT_IUNLOCK(mp);
#ifdef XFS_INODE_TRACE
ktrace_free(ip->i_trace);
#endif
#ifdef XFS_BMAP_TRACE
ktrace_free(ip->i_xtrace);
#endif
#ifdef XFS_BTREE_TRACE
ktrace_free(ip->i_btrace);
#endif
#ifdef XFS_RW_TRACE
ktrace_free(ip->i_rwtrace);
#endif
#ifdef XFS_ILOCK_TRACE
ktrace_free(ip->i_lock_trace);
#endif
#ifdef XFS_DIR2_TRACE
ktrace_free(ip->i_dir_trace);
#endif
if (ip->i_itemp) {
/*
* Only if we are shutting down the fs will we see an
* inode still in the AIL. If it is there, we should remove
* it to prevent a use-after-free from occurring.
*/
xfs_log_item_t *lip = &ip->i_itemp->ili_item;
struct xfs_ail *ailp = lip->li_ailp;
ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) ||
XFS_FORCED_SHUTDOWN(ip->i_mount));
if (lip->li_flags & XFS_LI_IN_AIL) {
spin_lock(&ailp->xa_lock);
if (lip->li_flags & XFS_LI_IN_AIL)
xfs_trans_ail_delete(ailp, lip);
else
spin_unlock(&ailp->xa_lock);
}
xfs_inode_item_destroy(ip);
ip->i_itemp = NULL;
}
/* asserts to verify all state is correct here */
ASSERT(atomic_read(&ip->i_iocount) == 0);
ASSERT(atomic_read(&ip->i_pincount) == 0);
ASSERT(!spin_is_locked(&ip->i_flags_lock));
ASSERT(completion_done(&ip->i_flush));
kmem_zone_free(xfs_inode_zone, ip);
}
/*
@ -737,7 +752,7 @@ xfs_iunlock(
* it is in the AIL and anyone is waiting on it. Don't do
* this if the caller has asked us not to.
*/
xfs_trans_unlocked_item(ip->i_mount,
xfs_trans_unlocked_item(ip->i_itemp->ili_item.li_ailp,
(xfs_log_item_t*)(ip->i_itemp));
}
xfs_ilock_trace(ip, 3, lock_flags, (inst_t *)__return_address);
@ -790,3 +805,51 @@ xfs_isilocked(
}
#endif
#ifdef XFS_INODE_TRACE
#define KTRACE_ENTER(ip, vk, s, line, ra) \
ktrace_enter((ip)->i_trace, \
/* 0 */ (void *)(__psint_t)(vk), \
/* 1 */ (void *)(s), \
/* 2 */ (void *)(__psint_t) line, \
/* 3 */ (void *)(__psint_t)atomic_read(&VFS_I(ip)->i_count), \
/* 4 */ (void *)(ra), \
/* 5 */ NULL, \
/* 6 */ (void *)(__psint_t)current_cpu(), \
/* 7 */ (void *)(__psint_t)current_pid(), \
/* 8 */ (void *)__return_address, \
/* 9 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL)
/*
* Vnode tracing code.
*/
void
_xfs_itrace_entry(xfs_inode_t *ip, const char *func, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_ENTRY, func, 0, ra);
}
void
_xfs_itrace_exit(xfs_inode_t *ip, const char *func, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_EXIT, func, 0, ra);
}
void
xfs_itrace_hold(xfs_inode_t *ip, char *file, int line, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_HOLD, file, line, ra);
}
void
_xfs_itrace_ref(xfs_inode_t *ip, char *file, int line, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_REF, file, line, ra);
}
void
xfs_itrace_rele(xfs_inode_t *ip, char *file, int line, inst_t *ra)
{
KTRACE_ENTER(ip, INODE_KTRACE_RELE, file, line, ra);
}
#endif /* XFS_INODE_TRACE */

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2000,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_IMAP_H__
#define __XFS_IMAP_H__
/*
* This is the structure passed to xfs_imap() to map
* an inode number to its on disk location.
*/
typedef struct xfs_imap {
xfs_daddr_t im_blkno; /* starting BB of inode chunk */
uint im_len; /* length in BBs of inode chunk */
xfs_agblock_t im_agblkno; /* logical block of inode chunk in ag */
ushort im_ioffset; /* inode offset in block in "inodes" */
ushort im_boffset; /* inode offset in block in bytes */
} xfs_imap_t;
#ifdef __KERNEL__
struct xfs_mount;
struct xfs_trans;
int xfs_imap(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
xfs_imap_t *, uint);
#endif
#endif /* __XFS_IMAP_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,7 @@
#define __XFS_INODE_H__
struct xfs_dinode;
struct xfs_dinode_core;
struct xfs_inode;
/*
* Fork identifiers.
@ -63,7 +62,7 @@ typedef struct xfs_ext_irec {
typedef struct xfs_ifork {
int if_bytes; /* bytes in if_u1 */
int if_real_bytes; /* bytes allocated in if_u1 */
xfs_bmbt_block_t *if_broot; /* file's incore btree root */
struct xfs_btree_block *if_broot; /* file's incore btree root */
short if_broot_bytes; /* bytes allocated for root */
unsigned char if_flags; /* per-fork flags */
unsigned char if_ext_max; /* max # of extent records */
@ -84,52 +83,14 @@ typedef struct xfs_ifork {
} xfs_ifork_t;
/*
* Flags for xfs_ichgtime().
* Inode location information. Stored in the inode and passed to
* xfs_imap_to_bp() to get a buffer and dinode for a given inode.
*/
#define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */
#define XFS_ICHGTIME_CHG 0x2 /* inode field change timestamp */
/*
* Per-fork incore inode flags.
*/
#define XFS_IFINLINE 0x01 /* Inline data is read in */
#define XFS_IFEXTENTS 0x02 /* All extent pointers are read in */
#define XFS_IFBROOT 0x04 /* i_broot points to the bmap b-tree root */
#define XFS_IFEXTIREC 0x08 /* Indirection array of extent blocks */
/*
* Flags for xfs_itobp(), xfs_imap() and xfs_dilocate().
*/
#define XFS_IMAP_LOOKUP 0x1
#define XFS_IMAP_BULKSTAT 0x2
#ifdef __KERNEL__
struct bhv_desc;
struct cred;
struct ktrace;
struct xfs_buf;
struct xfs_bmap_free;
struct xfs_bmbt_irec;
struct xfs_bmbt_block;
struct xfs_inode;
struct xfs_inode_log_item;
struct xfs_mount;
struct xfs_trans;
struct xfs_dquot;
#if defined(XFS_ILOCK_TRACE)
#define XFS_ILOCK_KTRACE_SIZE 32
extern ktrace_t *xfs_ilock_trace_buf;
extern void xfs_ilock_trace(struct xfs_inode *, int, unsigned int, inst_t *);
#else
#define xfs_ilock_trace(i,n,f,ra)
#endif
typedef struct dm_attrs_s {
__uint32_t da_dmevmask; /* DMIG event mask */
__uint16_t da_dmstate; /* DMIG state info */
__uint16_t da_pad; /* DMIG extra padding */
} dm_attrs_t;
struct xfs_imap {
xfs_daddr_t im_blkno; /* starting BB of inode chunk */
ushort im_len; /* length in BBs of inode chunk */
ushort im_boffset; /* inode offset in block in bytes */
};
/*
* This is the xfs in-core inode structure.
@ -160,7 +121,7 @@ typedef struct xfs_ictimestamp {
} xfs_ictimestamp_t;
/*
* NOTE: This structure must be kept identical to struct xfs_dinode_core
* NOTE: This structure must be kept identical to struct xfs_dinode
* in xfs_dinode.h except for the endianess annotations.
*/
typedef struct xfs_icdinode {
@ -191,27 +152,97 @@ typedef struct xfs_icdinode {
__uint32_t di_gen; /* generation number */
} xfs_icdinode_t;
typedef struct {
struct xfs_inode *ip_mnext; /* next inode in mount list */
struct xfs_inode *ip_mprev; /* ptr to prev inode */
struct xfs_mount *ip_mount; /* fs mount struct ptr */
} xfs_iptr_t;
/*
* Flags for xfs_ichgtime().
*/
#define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */
#define XFS_ICHGTIME_CHG 0x2 /* inode field change timestamp */
/*
* Per-fork incore inode flags.
*/
#define XFS_IFINLINE 0x01 /* Inline data is read in */
#define XFS_IFEXTENTS 0x02 /* All extent pointers are read in */
#define XFS_IFBROOT 0x04 /* i_broot points to the bmap b-tree root */
#define XFS_IFEXTIREC 0x08 /* Indirection array of extent blocks */
/*
* Fork handling.
*/
#define XFS_IFORK_Q(ip) ((ip)->i_d.di_forkoff != 0)
#define XFS_IFORK_BOFF(ip) ((int)((ip)->i_d.di_forkoff << 3))
#define XFS_IFORK_PTR(ip,w) \
((w) == XFS_DATA_FORK ? \
&(ip)->i_df : \
(ip)->i_afp)
#define XFS_IFORK_DSIZE(ip) \
(XFS_IFORK_Q(ip) ? \
XFS_IFORK_BOFF(ip) : \
XFS_LITINO((ip)->i_mount))
#define XFS_IFORK_ASIZE(ip) \
(XFS_IFORK_Q(ip) ? \
XFS_LITINO((ip)->i_mount) - XFS_IFORK_BOFF(ip) : \
0)
#define XFS_IFORK_SIZE(ip,w) \
((w) == XFS_DATA_FORK ? \
XFS_IFORK_DSIZE(ip) : \
XFS_IFORK_ASIZE(ip))
#define XFS_IFORK_FORMAT(ip,w) \
((w) == XFS_DATA_FORK ? \
(ip)->i_d.di_format : \
(ip)->i_d.di_aformat)
#define XFS_IFORK_FMT_SET(ip,w,n) \
((w) == XFS_DATA_FORK ? \
((ip)->i_d.di_format = (n)) : \
((ip)->i_d.di_aformat = (n)))
#define XFS_IFORK_NEXTENTS(ip,w) \
((w) == XFS_DATA_FORK ? \
(ip)->i_d.di_nextents : \
(ip)->i_d.di_anextents)
#define XFS_IFORK_NEXT_SET(ip,w,n) \
((w) == XFS_DATA_FORK ? \
((ip)->i_d.di_nextents = (n)) : \
((ip)->i_d.di_anextents = (n)))
#ifdef __KERNEL__
struct bhv_desc;
struct cred;
struct ktrace;
struct xfs_buf;
struct xfs_bmap_free;
struct xfs_bmbt_irec;
struct xfs_inode_log_item;
struct xfs_mount;
struct xfs_trans;
struct xfs_dquot;
#if defined(XFS_ILOCK_TRACE)
#define XFS_ILOCK_KTRACE_SIZE 32
extern void xfs_ilock_trace(struct xfs_inode *, int, unsigned int, inst_t *);
#else
#define xfs_ilock_trace(i,n,f,ra)
#endif
typedef struct dm_attrs_s {
__uint32_t da_dmevmask; /* DMIG event mask */
__uint16_t da_dmstate; /* DMIG state info */
__uint16_t da_pad; /* DMIG extra padding */
} dm_attrs_t;
typedef struct xfs_inode {
/* Inode linking and identification information. */
struct xfs_inode *i_mnext; /* next inode in mount list */
struct xfs_inode *i_mprev; /* ptr to prev inode */
struct xfs_mount *i_mount; /* fs mount struct ptr */
struct list_head i_reclaim; /* reclaim list */
struct inode *i_vnode; /* vnode backpointer */
struct xfs_dquot *i_udquot; /* user dquot */
struct xfs_dquot *i_gdquot; /* group dquot */
/* Inode location stuff */
xfs_ino_t i_ino; /* inode number (agno/agino)*/
xfs_daddr_t i_blkno; /* blkno of inode buffer */
ushort i_len; /* len of inode buffer */
ushort i_boffset; /* off of inode in buffer */
struct xfs_imap i_imap; /* location for xfs_imap() */
/* Extent information. */
xfs_ifork_t *i_afp; /* attribute fork pointer */
@ -230,7 +261,6 @@ typedef struct xfs_inode {
unsigned short i_flags; /* see defined flags below */
unsigned char i_update_core; /* timestamps/size is dirty */
unsigned char i_update_size; /* di_size field is dirty */
unsigned int i_gen; /* generation count */
unsigned int i_delayed_blks; /* count of delay alloc blks */
xfs_icdinode_t i_d; /* most of ondisk inode */
@ -238,6 +268,10 @@ typedef struct xfs_inode {
xfs_fsize_t i_size; /* in-memory size */
xfs_fsize_t i_new_size; /* size when write completes */
atomic_t i_iocount; /* outstanding I/O count */
/* VFS inode */
struct inode i_vnode; /* embedded VFS inode */
/* Trace buffers per inode. */
#ifdef XFS_INODE_TRACE
struct ktrace *i_trace; /* general inode trace */
@ -245,7 +279,7 @@ typedef struct xfs_inode {
#ifdef XFS_BMAP_TRACE
struct ktrace *i_xtrace; /* inode extent list trace */
#endif
#ifdef XFS_BMBT_TRACE
#ifdef XFS_BTREE_TRACE
struct ktrace *i_btrace; /* inode bmap btree trace */
#endif
#ifdef XFS_RW_TRACE
@ -265,13 +299,30 @@ typedef struct xfs_inode {
/* Convert from vfs inode to xfs inode */
static inline struct xfs_inode *XFS_I(struct inode *inode)
{
return (struct xfs_inode *)inode->i_private;
return container_of(inode, struct xfs_inode, i_vnode);
}
/* convert from xfs inode to vfs inode */
static inline struct inode *VFS_I(struct xfs_inode *ip)
{
return (struct inode *)ip->i_vnode;
return &ip->i_vnode;
}
/*
* Get rid of a partially initialized inode.
*
* We have to go through destroy_inode to make sure allocations
* from init_inode_always like the security data are undone.
*
* We mark the inode bad so that it takes the short cut in
* the reclaim path instead of going through the flush path
* which doesn't make sense for an inode that has never seen the
* light of day.
*/
static inline void xfs_destroy_inode(struct xfs_inode *ip)
{
make_bad_inode(VFS_I(ip));
return destroy_inode(VFS_I(ip));
}
/*
@ -327,65 +378,36 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags)
spin_unlock(&ip->i_flags_lock);
return ret;
}
#endif /* __KERNEL__ */
/*
* Fork handling.
* Manage the i_flush queue embedded in the inode. This completion
* queue synchronizes processes attempting to flush the in-core
* inode back to disk.
*/
static inline void xfs_iflock(xfs_inode_t *ip)
{
wait_for_completion(&ip->i_flush);
}
#define XFS_IFORK_Q(ip) ((ip)->i_d.di_forkoff != 0)
#define XFS_IFORK_BOFF(ip) ((int)((ip)->i_d.di_forkoff << 3))
static inline int xfs_iflock_nowait(xfs_inode_t *ip)
{
return try_wait_for_completion(&ip->i_flush);
}
#define XFS_IFORK_PTR(ip,w) \
((w) == XFS_DATA_FORK ? \
&(ip)->i_df : \
(ip)->i_afp)
#define XFS_IFORK_DSIZE(ip) \
(XFS_IFORK_Q(ip) ? \
XFS_IFORK_BOFF(ip) : \
XFS_LITINO((ip)->i_mount))
#define XFS_IFORK_ASIZE(ip) \
(XFS_IFORK_Q(ip) ? \
XFS_LITINO((ip)->i_mount) - XFS_IFORK_BOFF(ip) : \
0)
#define XFS_IFORK_SIZE(ip,w) \
((w) == XFS_DATA_FORK ? \
XFS_IFORK_DSIZE(ip) : \
XFS_IFORK_ASIZE(ip))
#define XFS_IFORK_FORMAT(ip,w) \
((w) == XFS_DATA_FORK ? \
(ip)->i_d.di_format : \
(ip)->i_d.di_aformat)
#define XFS_IFORK_FMT_SET(ip,w,n) \
((w) == XFS_DATA_FORK ? \
((ip)->i_d.di_format = (n)) : \
((ip)->i_d.di_aformat = (n)))
#define XFS_IFORK_NEXTENTS(ip,w) \
((w) == XFS_DATA_FORK ? \
(ip)->i_d.di_nextents : \
(ip)->i_d.di_anextents)
#define XFS_IFORK_NEXT_SET(ip,w,n) \
((w) == XFS_DATA_FORK ? \
((ip)->i_d.di_nextents = (n)) : \
((ip)->i_d.di_anextents = (n)))
#ifdef __KERNEL__
static inline void xfs_ifunlock(xfs_inode_t *ip)
{
complete(&ip->i_flush);
}
/*
* In-core inode flags.
*/
#define XFS_IGRIO 0x0001 /* inode used for guaranteed rate i/o */
#define XFS_IUIOSZ 0x0002 /* inode i/o sizes have been explicitly set */
#define XFS_IQUIESCE 0x0004 /* we have started quiescing for this inode */
#define XFS_IRECLAIM 0x0008 /* we have started reclaiming this inode */
#define XFS_ISTALE 0x0010 /* inode has been staled */
#define XFS_IRECLAIMABLE 0x0020 /* inode can be reclaimed */
#define XFS_INEW 0x0040
#define XFS_IFILESTREAM 0x0080 /* inode is in a filestream directory */
#define XFS_IMODIFIED 0x0100 /* XFS inode state possibly differs */
/* to the Linux inode state. */
#define XFS_ITRUNCATED 0x0200 /* truncated down so flush-on-close */
#define XFS_IRECLAIM 0x0001 /* we have started reclaiming this inode */
#define XFS_ISTALE 0x0002 /* inode has been staled */
#define XFS_IRECLAIMABLE 0x0004 /* inode can be reclaimed */
#define XFS_INEW 0x0008 /* inode has just been allocated */
#define XFS_IFILESTREAM 0x0010 /* inode is in a filestream directory */
#define XFS_ITRUNCATED 0x0020 /* truncated down so flush-on-close */
/*
* Flags for inode locking.
@ -459,17 +481,9 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags)
(((pip)->i_mount->m_flags & XFS_MOUNT_GRPID) || \
((pip)->i_d.di_mode & S_ISGID))
/*
* Flags for xfs_iget()
*/
#define XFS_IGET_CREATE 0x1
#define XFS_IGET_BULKSTAT 0x2
/*
* xfs_iget.c prototypes.
*/
void xfs_ihash_init(struct xfs_mount *);
void xfs_ihash_free(struct xfs_mount *);
xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t,
struct xfs_trans *);
int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
@ -484,25 +498,13 @@ int xfs_isilocked(xfs_inode_t *, uint);
uint xfs_ilock_map_shared(xfs_inode_t *);
void xfs_iunlock_map_shared(xfs_inode_t *, uint);
void xfs_ireclaim(xfs_inode_t *);
int xfs_finish_reclaim(xfs_inode_t *, int, int);
int xfs_finish_reclaim_all(struct xfs_mount *, int);
/*
* xfs_inode.c prototypes.
*/
int xfs_itobp(struct xfs_mount *, struct xfs_trans *,
xfs_inode_t *, struct xfs_dinode **, struct xfs_buf **,
xfs_daddr_t, uint, uint);
int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
xfs_inode_t **, xfs_daddr_t, uint);
int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int);
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 **);
void xfs_dinode_from_disk(struct xfs_icdinode *,
struct xfs_dinode_core *);
void xfs_dinode_to_disk(struct xfs_dinode_core *,
struct xfs_icdinode *);
uint xfs_ip2xflags(struct xfs_inode *);
uint xfs_dic2xflags(struct xfs_dinode *);
@ -513,17 +515,10 @@ int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
xfs_fsize_t, int, int);
int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
void xfs_idestroy_fork(xfs_inode_t *, int);
void xfs_idestroy(xfs_inode_t *);
void xfs_idata_realloc(xfs_inode_t *, int, int);
void xfs_iextract(xfs_inode_t *);
void xfs_iext_realloc(xfs_inode_t *, int, int);
void xfs_iroot_realloc(xfs_inode_t *, int, int);
void xfs_ipin(xfs_inode_t *);
void xfs_iunpin(xfs_inode_t *);
int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int);
int xfs_iflush(xfs_inode_t *, uint);
void xfs_iflush_all(struct xfs_mount *);
void xfs_ichgtime(xfs_inode_t *, int);
xfs_fsize_t xfs_file_last_byte(xfs_inode_t *);
void xfs_lock_inodes(xfs_inode_t **, int, uint);
@ -532,6 +527,77 @@ void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
void xfs_synchronize_atime(xfs_inode_t *);
void xfs_mark_inode_dirty_sync(xfs_inode_t *);
#if defined(XFS_INODE_TRACE)
#define INODE_TRACE_SIZE 16 /* number of trace entries */
#define INODE_KTRACE_ENTRY 1
#define INODE_KTRACE_EXIT 2
#define INODE_KTRACE_HOLD 3
#define INODE_KTRACE_REF 4
#define INODE_KTRACE_RELE 5
extern void _xfs_itrace_entry(struct xfs_inode *, const char *, inst_t *);
extern void _xfs_itrace_exit(struct xfs_inode *, const char *, inst_t *);
extern void xfs_itrace_hold(struct xfs_inode *, char *, int, inst_t *);
extern void _xfs_itrace_ref(struct xfs_inode *, char *, int, inst_t *);
extern void xfs_itrace_rele(struct xfs_inode *, char *, int, inst_t *);
#define xfs_itrace_entry(ip) \
_xfs_itrace_entry(ip, __func__, (inst_t *)__return_address)
#define xfs_itrace_exit(ip) \
_xfs_itrace_exit(ip, __func__, (inst_t *)__return_address)
#define xfs_itrace_exit_tag(ip, tag) \
_xfs_itrace_exit(ip, tag, (inst_t *)__return_address)
#define xfs_itrace_ref(ip) \
_xfs_itrace_ref(ip, __FILE__, __LINE__, (inst_t *)__return_address)
#else
#define xfs_itrace_entry(a)
#define xfs_itrace_exit(a)
#define xfs_itrace_exit_tag(a, b)
#define xfs_itrace_hold(a, b, c, d)
#define xfs_itrace_ref(a)
#define xfs_itrace_rele(a, b, c, d)
#endif
#define IHOLD(ip) \
do { \
ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
atomic_inc(&(VFS_I(ip)->i_count)); \
xfs_itrace_hold((ip), __FILE__, __LINE__, (inst_t *)__return_address); \
} while (0)
#define IRELE(ip) \
do { \
xfs_itrace_rele((ip), __FILE__, __LINE__, (inst_t *)__return_address); \
iput(VFS_I(ip)); \
} while (0)
#endif /* __KERNEL__ */
/*
* Flags for xfs_iget()
*/
#define XFS_IGET_CREATE 0x1
#define XFS_IGET_BULKSTAT 0x2
int xfs_inotobp(struct xfs_mount *, struct xfs_trans *,
xfs_ino_t, struct xfs_dinode **,
struct xfs_buf **, int *, uint);
int xfs_itobp(struct xfs_mount *, struct xfs_trans *,
struct xfs_inode *, struct xfs_dinode **,
struct xfs_buf **, uint);
int xfs_iread(struct xfs_mount *, struct xfs_trans *,
struct xfs_inode *, xfs_daddr_t, uint);
void xfs_dinode_from_disk(struct xfs_icdinode *,
struct xfs_dinode *);
void xfs_dinode_to_disk(struct xfs_dinode *,
struct xfs_icdinode *);
void xfs_idestroy_fork(struct xfs_inode *, int);
void xfs_idata_realloc(struct xfs_inode *, int, int);
void xfs_iroot_realloc(struct xfs_inode *, int, int);
int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int);
int xfs_iextents_copy(struct xfs_inode *, xfs_bmbt_rec_t *, int);
xfs_bmbt_rec_host_t *xfs_iext_get_ext(xfs_ifork_t *, xfs_extnum_t);
void xfs_iext_insert(xfs_ifork_t *, xfs_extnum_t, xfs_extnum_t,
xfs_bmbt_irec_t *);
@ -561,7 +627,8 @@ void xfs_iext_irec_update_extoffs(xfs_ifork_t *, int, int);
#define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount))
#ifdef DEBUG
void xfs_isize_check(struct xfs_mount *, xfs_inode_t *, xfs_fsize_t);
void xfs_isize_check(struct xfs_mount *, struct xfs_inode *,
xfs_fsize_t);
#else /* DEBUG */
#define xfs_isize_check(mp, ip, isize)
#endif /* DEBUG */
@ -576,26 +643,4 @@ extern struct kmem_zone *xfs_ifork_zone;
extern struct kmem_zone *xfs_inode_zone;
extern struct kmem_zone *xfs_ili_zone;
/*
* Manage the i_flush queue embedded in the inode. This completion
* queue synchronizes processes attempting to flush the in-core
* inode back to disk.
*/
static inline void xfs_iflock(xfs_inode_t *ip)
{
wait_for_completion(&ip->i_flush);
}
static inline int xfs_iflock_nowait(xfs_inode_t *ip)
{
return try_wait_for_completion(&ip->i_flush);
}
static inline void xfs_ifunlock(xfs_inode_t *ip)
{
complete(&ip->i_flush);
}
#endif /* __KERNEL__ */
#endif /* __XFS_INODE_H__ */

View File

@ -281,7 +281,7 @@ xfs_inode_item_format(
xfs_mark_inode_dirty_sync(ip);
vecp->i_addr = (xfs_caddr_t)&ip->i_d;
vecp->i_len = sizeof(xfs_dinode_core_t);
vecp->i_len = sizeof(struct xfs_icdinode);
XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ICORE);
vecp++;
nvecs++;
@ -296,9 +296,8 @@ xfs_inode_item_format(
* has a new version number, then we don't bother converting back.
*/
mp = ip->i_mount;
ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 ||
xfs_sb_version_hasnlink(&mp->m_sb));
if (ip->i_d.di_version == XFS_DINODE_VERSION_1) {
ASSERT(ip->i_d.di_version == 1 || xfs_sb_version_hasnlink(&mp->m_sb));
if (ip->i_d.di_version == 1) {
if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
/*
* Convert it back.
@ -311,7 +310,7 @@ xfs_inode_item_format(
* so just make the conversion to the new inode
* format permanent.
*/
ip->i_d.di_version = XFS_DINODE_VERSION_2;
ip->i_d.di_version = 2;
ip->i_d.di_onlink = 0;
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
}
@ -932,6 +931,7 @@ xfs_inode_item_init(
iip->ili_item.li_type = XFS_LI_INODE;
iip->ili_item.li_ops = &xfs_inode_item_ops;
iip->ili_item.li_mountp = mp;
iip->ili_item.li_ailp = mp->m_ail;
iip->ili_inode = ip;
/*
@ -942,9 +942,9 @@ xfs_inode_item_init(
iip->ili_format.ilf_type = XFS_LI_INODE;
iip->ili_format.ilf_ino = ip->i_ino;
iip->ili_format.ilf_blkno = ip->i_blkno;
iip->ili_format.ilf_len = ip->i_len;
iip->ili_format.ilf_boffset = ip->i_boffset;
iip->ili_format.ilf_blkno = ip->i_imap.im_blkno;
iip->ili_format.ilf_len = ip->i_imap.im_len;
iip->ili_format.ilf_boffset = ip->i_imap.im_boffset;
}
/*
@ -976,9 +976,8 @@ xfs_iflush_done(
xfs_buf_t *bp,
xfs_inode_log_item_t *iip)
{
xfs_inode_t *ip;
ip = iip->ili_inode;
xfs_inode_t *ip = iip->ili_inode;
struct xfs_ail *ailp = iip->ili_item.li_ailp;
/*
* We only want to pull the item from the AIL if it is
@ -991,15 +990,12 @@ xfs_iflush_done(
*/
if (iip->ili_logged &&
(iip->ili_item.li_lsn == iip->ili_flush_lsn)) {
spin_lock(&ip->i_mount->m_ail_lock);
spin_lock(&ailp->xa_lock);
if (iip->ili_item.li_lsn == iip->ili_flush_lsn) {
/*
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(ip->i_mount,
(xfs_log_item_t*)iip);
/* xfs_trans_ail_delete() drops the AIL lock. */
xfs_trans_ail_delete(ailp, (xfs_log_item_t*)iip);
} else {
spin_unlock(&ip->i_mount->m_ail_lock);
spin_unlock(&ailp->xa_lock);
}
}
@ -1031,21 +1027,20 @@ void
xfs_iflush_abort(
xfs_inode_t *ip)
{
xfs_inode_log_item_t *iip;
xfs_inode_log_item_t *iip = ip->i_itemp;
xfs_mount_t *mp;
iip = ip->i_itemp;
mp = ip->i_mount;
if (iip) {
struct xfs_ail *ailp = iip->ili_item.li_ailp;
if (iip->ili_item.li_flags & XFS_LI_IN_AIL) {
spin_lock(&mp->m_ail_lock);
spin_lock(&ailp->xa_lock);
if (iip->ili_item.li_flags & XFS_LI_IN_AIL) {
/*
* xfs_trans_delete_ail() drops the AIL lock.
*/
xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip);
/* xfs_trans_ail_delete() drops the AIL lock. */
xfs_trans_ail_delete(ailp, (xfs_log_item_t *)iip);
} else
spin_unlock(&mp->m_ail_lock);
spin_unlock(&ailp->xa_lock);
}
iip->ili_logged = 0;
/*

View File

@ -112,6 +112,24 @@ typedef struct xfs_inode_log_format_64 {
#define XFS_ILI_IOLOCKED_ANY (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED)
#define XFS_ILOG_FBROOT(w) xfs_ilog_fbroot(w)
static inline int xfs_ilog_fbroot(int w)
{
return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT);
}
#define XFS_ILOG_FEXT(w) xfs_ilog_fext(w)
static inline int xfs_ilog_fext(int w)
{
return (w == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT);
}
#define XFS_ILOG_FDATA(w) xfs_ilog_fdata(w)
static inline int xfs_ilog_fdata(int w)
{
return (w == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA);
}
#ifdef __KERNEL__
struct xfs_buf;
@ -148,26 +166,6 @@ typedef struct xfs_inode_log_item {
} xfs_inode_log_item_t;
#define XFS_ILOG_FDATA(w) xfs_ilog_fdata(w)
static inline int xfs_ilog_fdata(int w)
{
return (w == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA);
}
#endif /* __KERNEL__ */
#define XFS_ILOG_FBROOT(w) xfs_ilog_fbroot(w)
static inline int xfs_ilog_fbroot(int w)
{
return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT);
}
#define XFS_ILOG_FEXT(w) xfs_ilog_fext(w)
static inline int xfs_ilog_fext(int w)
{
return (w == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT);
}
static inline int xfs_inode_clean(xfs_inode_t *ip)
{
return (!ip->i_itemp ||
@ -175,9 +173,6 @@ static inline int xfs_inode_clean(xfs_inode_t *ip)
!ip->i_update_core;
}
#ifdef __KERNEL__
extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
extern void xfs_inode_item_destroy(struct xfs_inode *);
extern void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *);

View File

@ -290,7 +290,6 @@ STATIC int
xfs_iomap_eof_align_last_fsb(
xfs_mount_t *mp,
xfs_inode_t *ip,
xfs_fsize_t isize,
xfs_extlen_t extsize,
xfs_fileoff_t *last_fsb)
{
@ -306,14 +305,14 @@ xfs_iomap_eof_align_last_fsb(
* stripe width and we are allocating past the allocation eof.
*/
else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) &&
(isize >= XFS_FSB_TO_B(mp, mp->m_swidth)))
(ip->i_size >= XFS_FSB_TO_B(mp, mp->m_swidth)))
new_last_fsb = roundup_64(*last_fsb, mp->m_swidth);
/*
* Roundup the allocation request to a stripe unit (m_dalign) boundary
* if the file size is >= stripe unit size, and we are allocating past
* the allocation eof.
*/
else if (mp->m_dalign && (isize >= XFS_FSB_TO_B(mp, mp->m_dalign)))
else if (mp->m_dalign && (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_dalign)))
new_last_fsb = roundup_64(*last_fsb, mp->m_dalign);
/*
@ -403,7 +402,6 @@ xfs_iomap_write_direct(
xfs_filblks_t count_fsb, resaligned;
xfs_fsblock_t firstfsb;
xfs_extlen_t extsz, temp;
xfs_fsize_t isize;
int nimaps;
int bmapi_flag;
int quota_flag;
@ -426,15 +424,10 @@ xfs_iomap_write_direct(
rt = XFS_IS_REALTIME_INODE(ip);
extsz = xfs_get_extsz_hint(ip);
isize = ip->i_size;
if (ip->i_new_size > isize)
isize = ip->i_new_size;
offset_fsb = XFS_B_TO_FSBT(mp, offset);
last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
if ((offset + count) > isize) {
error = xfs_iomap_eof_align_last_fsb(mp, ip, isize, extsz,
&last_fsb);
if ((offset + count) > ip->i_size) {
error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
if (error)
goto error_out;
} else {
@ -559,7 +552,6 @@ STATIC int
xfs_iomap_eof_want_preallocate(
xfs_mount_t *mp,
xfs_inode_t *ip,
xfs_fsize_t isize,
xfs_off_t offset,
size_t count,
int ioflag,
@ -573,7 +565,7 @@ xfs_iomap_eof_want_preallocate(
int n, error, imaps;
*prealloc = 0;
if ((ioflag & BMAPI_SYNC) || (offset + count) <= isize)
if ((ioflag & BMAPI_SYNC) || (offset + count) <= ip->i_size)
return 0;
/*
@ -617,7 +609,6 @@ xfs_iomap_write_delay(
xfs_fileoff_t ioalign;
xfs_fsblock_t firstblock;
xfs_extlen_t extsz;
xfs_fsize_t isize;
int nimaps;
xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS];
int prealloc, fsynced = 0;
@ -637,11 +628,7 @@ xfs_iomap_write_delay(
offset_fsb = XFS_B_TO_FSBT(mp, offset);
retry:
isize = ip->i_size;
if (ip->i_new_size > isize)
isize = ip->i_new_size;
error = xfs_iomap_eof_want_preallocate(mp, ip, isize, offset, count,
error = xfs_iomap_eof_want_preallocate(mp, ip, offset, count,
ioflag, imap, XFS_WRITE_IMAPS, &prealloc);
if (error)
return error;
@ -655,8 +642,7 @@ retry:
}
if (prealloc || extsz) {
error = xfs_iomap_eof_align_last_fsb(mp, ip, isize, extsz,
&last_fsb);
error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
if (error)
return error;
}

View File

@ -69,7 +69,7 @@ xfs_bulkstat_one_iget(
}
ASSERT(ip != NULL);
ASSERT(ip->i_blkno != (xfs_daddr_t)0);
ASSERT(ip->i_imap.im_blkno != 0);
dic = &ip->i_d;
@ -125,13 +125,9 @@ STATIC void
xfs_bulkstat_one_dinode(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t ino, /* inode number to get data for */
xfs_dinode_t *dip, /* dinode inode pointer */
xfs_dinode_t *dic, /* dinode inode pointer */
xfs_bstat_t *buf) /* return buffer */
{
xfs_dinode_core_t *dic; /* dinode core info pointer */
dic = &dip->di_core;
/*
* The inode format changed when we moved the link count and
* made it 32 bits long. If this is an old format inode,
@ -143,7 +139,7 @@ xfs_bulkstat_one_dinode(
* the new format. We don't change the version number so that we
* can distinguish this from a real new format inode.
*/
if (dic->di_version == XFS_DINODE_VERSION_1) {
if (dic->di_version == 1) {
buf->bs_nlink = be16_to_cpu(dic->di_onlink);
buf->bs_projid = 0;
} else {
@ -162,7 +158,7 @@ xfs_bulkstat_one_dinode(
buf->bs_mtime.tv_nsec = be32_to_cpu(dic->di_mtime.t_nsec);
buf->bs_ctime.tv_sec = be32_to_cpu(dic->di_ctime.t_sec);
buf->bs_ctime.tv_nsec = be32_to_cpu(dic->di_ctime.t_nsec);
buf->bs_xflags = xfs_dic2xflags(dip);
buf->bs_xflags = xfs_dic2xflags(dic);
buf->bs_extsize = be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog;
buf->bs_extents = be32_to_cpu(dic->di_nextents);
buf->bs_gen = be32_to_cpu(dic->di_gen);
@ -173,7 +169,7 @@ xfs_bulkstat_one_dinode(
switch (dic->di_format) {
case XFS_DINODE_FMT_DEV:
buf->bs_rdev = be32_to_cpu(dip->di_u.di_dev);
buf->bs_rdev = xfs_dinode_get_rdev(dic);
buf->bs_blksize = BLKDEV_IOSIZE;
buf->bs_blocks = 0;
break;
@ -192,27 +188,34 @@ xfs_bulkstat_one_dinode(
}
}
/* Return 0 on success or positive error */
STATIC int
xfs_bulkstat_one_fmt(
void __user *ubuffer,
int ubsize,
int *ubused,
const xfs_bstat_t *buffer)
{
if (ubsize < sizeof(*buffer))
return XFS_ERROR(ENOMEM);
if (copy_to_user(ubuffer, buffer, sizeof(*buffer)))
return -EFAULT;
return sizeof(*buffer);
return XFS_ERROR(EFAULT);
if (ubused)
*ubused = sizeof(*buffer);
return 0;
}
/*
* Return stat information for one inode.
* Return 0 if ok, else errno.
*/
int /* error status */
xfs_bulkstat_one(
int /* error status */
xfs_bulkstat_one_int(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t ino, /* inode number to get data for */
void __user *buffer, /* buffer to place output in */
int ubsize, /* size of buffer */
void *private_data, /* my private data */
bulkstat_one_fmt_pf formatter, /* formatter, copy to user */
xfs_daddr_t bno, /* starting bno of inode cluster */
int *ubused, /* bytes used by me */
void *dibuff, /* on-disk inode buffer */
@ -221,15 +224,12 @@ xfs_bulkstat_one(
xfs_bstat_t *buf; /* return buffer */
int error = 0; /* error value */
xfs_dinode_t *dip; /* dinode inode pointer */
bulkstat_one_fmt_pf formatter = private_data ? : xfs_bulkstat_one_fmt;
dip = (xfs_dinode_t *)dibuff;
*stat = BULKSTAT_RV_NOTHING;
if (!buffer || xfs_internal_inum(mp, ino))
return XFS_ERROR(EINVAL);
if (ubsize < sizeof(*buf))
return XFS_ERROR(ENOMEM);
buf = kmem_alloc(sizeof(*buf), KM_SLEEP);
@ -244,21 +244,34 @@ xfs_bulkstat_one(
xfs_bulkstat_one_dinode(mp, ino, dip, buf);
}
error = formatter(buffer, buf);
if (error < 0) {
error = EFAULT;
error = formatter(buffer, ubsize, ubused, buf);
if (error)
goto out_free;
}
*stat = BULKSTAT_RV_DIDONE;
if (ubused)
*ubused = error;
out_free:
kmem_free(buf);
return error;
}
int
xfs_bulkstat_one(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t ino, /* inode number to get data for */
void __user *buffer, /* buffer to place output in */
int ubsize, /* size of buffer */
void *private_data, /* my private data */
xfs_daddr_t bno, /* starting bno of inode cluster */
int *ubused, /* bytes used by me */
void *dibuff, /* on-disk inode buffer */
int *stat) /* BULKSTAT_RV_... */
{
return xfs_bulkstat_one_int(mp, ino, buffer, ubsize,
xfs_bulkstat_one_fmt, bno,
ubused, dibuff, stat);
}
/*
* Test to see whether we can use the ondisk inode directly, based
* on the given bulkstat flags, filling in dipp accordingly.
@ -287,19 +300,19 @@ xfs_bulkstat_use_dinode(
* to disk yet. This is a temporary hack that would require a proper
* fix in the future.
*/
if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC ||
!XFS_DINODE_GOOD_VERSION(dip->di_core.di_version) ||
!dip->di_core.di_mode)
if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC ||
!XFS_DINODE_GOOD_VERSION(dip->di_version) ||
!dip->di_mode)
return 0;
if (flags & BULKSTAT_FG_QUICK) {
*dipp = dip;
return 1;
}
/* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */
aformat = dip->di_core.di_aformat;
aformat = dip->di_aformat;
if ((XFS_DFORK_Q(dip) == 0) ||
(aformat == XFS_DINODE_FMT_LOCAL) ||
(aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_core.di_anextents)) {
(aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_anextents)) {
*dipp = dip;
return 1;
}
@ -359,7 +372,6 @@ xfs_bulkstat(
int ubused; /* bytes used by formatter */
xfs_buf_t *bp; /* ptr to on-disk inode cluster buf */
xfs_dinode_t *dip; /* ptr into bp for specific inode */
xfs_inode_t *ip; /* ptr to in-core inode struct */
/*
* Get the last inode value, see if there's nothing to do.
@ -416,8 +428,7 @@ xfs_bulkstat(
/*
* Allocate and initialize a btree cursor for ialloc btree.
*/
cur = xfs_btree_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_INO,
(xfs_inode_t *)0, 0);
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
irbp = irbuf;
irbufend = irbuf + nirbuf;
end_of_ag = 0;
@ -472,7 +483,7 @@ xfs_bulkstat(
* In any case, increment to the next record.
*/
if (!error)
error = xfs_inobt_increment(cur, 0, &tmp);
error = xfs_btree_increment(cur, 0, &tmp);
} else {
/*
* Start of ag. Lookup the first inode chunk.
@ -539,7 +550,7 @@ xfs_bulkstat(
* Set agino to after this chunk and bump the cursor.
*/
agino = gino + XFS_INODES_PER_CHUNK;
error = xfs_inobt_increment(cur, 0, &tmp);
error = xfs_btree_increment(cur, 0, &tmp);
cond_resched();
}
/*
@ -586,6 +597,8 @@ xfs_bulkstat(
if (flags & (BULKSTAT_FG_QUICK |
BULKSTAT_FG_INLINE)) {
int offset;
ino = XFS_AGINO_TO_INO(mp, agno,
agino);
bno = XFS_AGB_TO_DADDR(mp, agno,
@ -594,21 +607,15 @@ xfs_bulkstat(
/*
* Get the inode cluster buffer
*/
ASSERT(xfs_inode_zone != NULL);
ip = kmem_zone_zalloc(xfs_inode_zone,
KM_SLEEP);
ip->i_ino = ino;
ip->i_mount = mp;
spin_lock_init(&ip->i_flags_lock);
if (bp)
xfs_buf_relse(bp);
error = xfs_itobp(mp, NULL, ip,
&dip, &bp, bno,
XFS_IMAP_BULKSTAT,
XFS_BUF_LOCK);
error = xfs_inotobp(mp, NULL, ino, &dip,
&bp, &offset,
XFS_IGET_BULKSTAT);
if (!error)
clustidx = ip->i_boffset / mp->m_sb.sb_inodesize;
kmem_zone_free(xfs_inode_zone, ip);
clustidx = offset / mp->m_sb.sb_inodesize;
if (XFS_TEST_ERROR(error != 0,
mp, XFS_ERRTAG_BULKSTAT_READ_CHUNK,
XFS_RANDOM_BULKSTAT_READ_CHUNK)) {
@ -842,8 +849,7 @@ xfs_inumbers(
agino = 0;
continue;
}
cur = xfs_btree_init_cursor(mp, NULL, agbp, agno,
XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
error = xfs_inobt_lookup_ge(cur, agino, 0, 0, &tmp);
if (error) {
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
@ -887,7 +893,7 @@ xfs_inumbers(
bufidx = 0;
}
if (left) {
error = xfs_inobt_increment(cur, 0, &tmp);
error = xfs_btree_increment(cur, 0, &tmp);
if (error) {
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
cur = NULL;

View File

@ -71,8 +71,22 @@ xfs_bulkstat_single(
typedef int (*bulkstat_one_fmt_pf)( /* used size in bytes or negative error */
void __user *ubuffer, /* buffer to write to */
int ubsize, /* remaining user buffer sz */
int *ubused, /* bytes used by formatter */
const xfs_bstat_t *buffer); /* buffer to read from */
int
xfs_bulkstat_one_int(
xfs_mount_t *mp,
xfs_ino_t ino,
void __user *buffer,
int ubsize,
bulkstat_one_fmt_pf formatter,
xfs_daddr_t bno,
int *ubused,
void *dibuff,
int *stat);
int
xfs_bulkstat_one(
xfs_mount_t *mp,

View File

@ -100,12 +100,11 @@ STATIC void xlog_ungrant_log_space(xlog_t *log,
/* local ticket functions */
STATIC xlog_ticket_t *xlog_ticket_get(xlog_t *log,
STATIC xlog_ticket_t *xlog_ticket_alloc(xlog_t *log,
int unit_bytes,
int count,
char clientid,
uint flags);
STATIC void xlog_ticket_put(xlog_t *log, xlog_ticket_t *ticket);
#if defined(DEBUG)
STATIC void xlog_verify_dest_ptr(xlog_t *log, __psint_t ptr);
@ -360,7 +359,7 @@ xfs_log_done(xfs_mount_t *mp,
*/
xlog_trace_loggrant(log, ticket, "xfs_log_done: (non-permanent)");
xlog_ungrant_log_space(log, ticket);
xlog_ticket_put(log, ticket);
xfs_log_ticket_put(ticket);
} else {
xlog_trace_loggrant(log, ticket, "xfs_log_done: (permanent)");
xlog_regrant_reserve_log_space(log, ticket);
@ -514,7 +513,7 @@ xfs_log_reserve(xfs_mount_t *mp,
retval = xlog_regrant_write_log_space(log, internal_ticket);
} else {
/* may sleep if need to allocate more tickets */
internal_ticket = xlog_ticket_get(log, unit_bytes, cnt,
internal_ticket = xlog_ticket_alloc(log, unit_bytes, cnt,
client, flags);
if (!internal_ticket)
return XFS_ERROR(ENOMEM);
@ -572,12 +571,12 @@ xfs_log_mount(
/*
* Initialize the AIL now we have a log.
*/
spin_lock_init(&mp->m_ail_lock);
error = xfs_trans_ail_init(mp);
if (error) {
cmn_err(CE_WARN, "XFS: AIL initialisation failed: error %d", error);
goto error;
}
mp->m_log->l_ailp = mp->m_ail;
/*
* skip log recovery on a norecovery mount. pretend it all
@ -730,8 +729,8 @@ xfs_log_unmount_write(xfs_mount_t *mp)
spin_lock(&log->l_icloglock);
iclog = log->l_iclog;
atomic_inc(&iclog->ic_refcnt);
spin_unlock(&log->l_icloglock);
xlog_state_want_sync(log, iclog);
spin_unlock(&log->l_icloglock);
error = xlog_state_release_iclog(log, iclog);
spin_lock(&log->l_icloglock);
@ -749,7 +748,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
if (tic) {
xlog_trace_loggrant(log, tic, "unmount rec");
xlog_ungrant_log_space(log, tic);
xlog_ticket_put(log, tic);
xfs_log_ticket_put(tic);
}
} else {
/*
@ -768,9 +767,9 @@ xfs_log_unmount_write(xfs_mount_t *mp)
spin_lock(&log->l_icloglock);
iclog = log->l_iclog;
atomic_inc(&iclog->ic_refcnt);
spin_unlock(&log->l_icloglock);
xlog_state_want_sync(log, iclog);
spin_unlock(&log->l_icloglock);
error = xlog_state_release_iclog(log, iclog);
spin_lock(&log->l_icloglock);
@ -906,7 +905,7 @@ xfs_log_move_tail(xfs_mount_t *mp,
int
xfs_log_need_covered(xfs_mount_t *mp)
{
int needed = 0, gen;
int needed = 0;
xlog_t *log = mp->m_log;
if (!xfs_fs_writable(mp))
@ -915,7 +914,7 @@ xfs_log_need_covered(xfs_mount_t *mp)
spin_lock(&log->l_icloglock);
if (((log->l_covered_state == XLOG_STATE_COVER_NEED) ||
(log->l_covered_state == XLOG_STATE_COVER_NEED2))
&& !xfs_trans_first_ail(mp, &gen)
&& !xfs_trans_ail_tail(log->l_ailp)
&& xlog_iclogs_empty(log)) {
if (log->l_covered_state == XLOG_STATE_COVER_NEED)
log->l_covered_state = XLOG_STATE_COVER_DONE;
@ -952,7 +951,7 @@ xlog_assign_tail_lsn(xfs_mount_t *mp)
xfs_lsn_t tail_lsn;
xlog_t *log = mp->m_log;
tail_lsn = xfs_trans_tail_ail(mp);
tail_lsn = xfs_trans_ail_tail(mp->m_ail);
spin_lock(&log->l_grant_lock);
if (tail_lsn != 0) {
log->l_tail_lsn = tail_lsn;
@ -1030,12 +1029,6 @@ xlog_iodone(xfs_buf_t *bp)
ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == (unsigned long) 2);
XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
aborted = 0;
/*
* Some versions of cpp barf on the recursive definition of
* ic_log -> hic_fields.ic_log and expand ic_log twice when
* it is passed through two macros. Workaround broken cpp.
*/
l = iclog->ic_log;
/*
@ -1302,7 +1295,7 @@ xlog_alloc_log(xfs_mount_t *mp,
XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
iclog->ic_bp = bp;
iclog->hic_data = bp->b_addr;
iclog->ic_data = bp->b_addr;
#ifdef DEBUG
log->l_iclog_bak[i] = (xfs_caddr_t)&(iclog->ic_header);
#endif
@ -1322,7 +1315,7 @@ xlog_alloc_log(xfs_mount_t *mp,
atomic_set(&iclog->ic_refcnt, 0);
spin_lock_init(&iclog->ic_callback_lock);
iclog->ic_callback_tail = &(iclog->ic_callback);
iclog->ic_datap = (char *)iclog->hic_data + log->l_iclog_hsize;
iclog->ic_datap = (char *)iclog->ic_data + log->l_iclog_hsize;
ASSERT(XFS_BUF_ISBUSY(iclog->ic_bp));
ASSERT(XFS_BUF_VALUSEMA(iclog->ic_bp) <= 0);
@ -1446,7 +1439,7 @@ xlog_grant_push_ail(xfs_mount_t *mp,
*/
if (threshold_lsn &&
!XLOG_FORCED_SHUTDOWN(log))
xfs_trans_push_ail(mp, threshold_lsn);
xfs_trans_ail_push(log->l_ailp, threshold_lsn);
} /* xlog_grant_push_ail */
@ -1991,7 +1984,9 @@ xlog_write(xfs_mount_t * mp,
if (iclog->ic_size - log_offset <= sizeof(xlog_op_header_t)) {
xlog_state_finish_copy(log, iclog, record_cnt, data_cnt);
record_cnt = data_cnt = 0;
spin_lock(&log->l_icloglock);
xlog_state_want_sync(log, iclog);
spin_unlock(&log->l_icloglock);
if (commit_iclog) {
ASSERT(flags & XLOG_COMMIT_TRANS);
*commit_iclog = iclog;
@ -3200,7 +3195,7 @@ try_again:
STATIC void
xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog)
{
spin_lock(&log->l_icloglock);
ASSERT(spin_is_locked(&log->l_icloglock));
if (iclog->ic_state == XLOG_STATE_ACTIVE) {
xlog_state_switch_iclogs(log, iclog, 0);
@ -3208,10 +3203,7 @@ xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog)
ASSERT(iclog->ic_state &
(XLOG_STATE_WANT_SYNC|XLOG_STATE_IOERROR));
}
spin_unlock(&log->l_icloglock);
} /* xlog_state_want_sync */
}
/*****************************************************************************
@ -3222,22 +3214,33 @@ xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog)
*/
/*
* Free a used ticket.
* Free a used ticket when it's refcount falls to zero.
*/
STATIC void
xlog_ticket_put(xlog_t *log,
xlog_ticket_t *ticket)
void
xfs_log_ticket_put(
xlog_ticket_t *ticket)
{
sv_destroy(&ticket->t_wait);
kmem_zone_free(xfs_log_ticket_zone, ticket);
} /* xlog_ticket_put */
ASSERT(atomic_read(&ticket->t_ref) > 0);
if (atomic_dec_and_test(&ticket->t_ref)) {
sv_destroy(&ticket->t_wait);
kmem_zone_free(xfs_log_ticket_zone, ticket);
}
}
xlog_ticket_t *
xfs_log_ticket_get(
xlog_ticket_t *ticket)
{
ASSERT(atomic_read(&ticket->t_ref) > 0);
atomic_inc(&ticket->t_ref);
return ticket;
}
/*
* Allocate and initialise a new log ticket.
*/
STATIC xlog_ticket_t *
xlog_ticket_get(xlog_t *log,
xlog_ticket_alloc(xlog_t *log,
int unit_bytes,
int cnt,
char client,
@ -3308,6 +3311,7 @@ xlog_ticket_get(xlog_t *log,
unit_bytes += 2*BBSIZE;
}
atomic_set(&tic->t_ref, 1);
tic->t_unit_res = unit_bytes;
tic->t_curr_res = unit_bytes;
tic->t_cnt = cnt;
@ -3323,7 +3327,7 @@ xlog_ticket_get(xlog_t *log,
xlog_tic_reset_res(tic);
return tic;
} /* xlog_ticket_get */
}
/******************************************************************************
@ -3452,7 +3456,7 @@ xlog_verify_iclog(xlog_t *log,
ptr = iclog->ic_datap;
base_ptr = ptr;
ophead = (xlog_op_header_t *)ptr;
xhdr = (xlog_in_core_2_t *)&iclog->ic_header;
xhdr = iclog->ic_data;
for (i = 0; i < len; i++) {
ophead = (xlog_op_header_t *)ptr;
@ -3558,7 +3562,8 @@ xfs_log_force_umount(
if (!log ||
log->l_flags & XLOG_ACTIVE_RECOVERY) {
mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN;
XFS_BUF_DONE(mp->m_sb_bp);
if (mp->m_sb_bp)
XFS_BUF_DONE(mp->m_sb_bp);
return 0;
}
@ -3579,7 +3584,9 @@ xfs_log_force_umount(
spin_lock(&log->l_icloglock);
spin_lock(&log->l_grant_lock);
mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN;
XFS_BUF_DONE(mp->m_sb_bp);
if (mp->m_sb_bp)
XFS_BUF_DONE(mp->m_sb_bp);
/*
* This flag is sort of redundant because of the mount flag, but
* it's good to maintain the separation between the log and the rest

View File

@ -134,6 +134,7 @@ typedef struct xfs_log_callback {
#ifdef __KERNEL__
/* Log manager interfaces */
struct xfs_mount;
struct xlog_ticket;
xfs_lsn_t xfs_log_done(struct xfs_mount *mp,
xfs_log_ticket_t ticket,
void **iclog,
@ -177,6 +178,9 @@ int xfs_log_need_covered(struct xfs_mount *mp);
void xlog_iodone(struct xfs_buf *);
struct xlog_ticket * xfs_log_ticket_get(struct xlog_ticket *ticket);
void xfs_log_ticket_put(struct xlog_ticket *ticket);
#endif

View File

@ -245,6 +245,7 @@ typedef struct xlog_ticket {
struct xlog_ticket *t_next; /* :4|8 */
struct xlog_ticket *t_prev; /* :4|8 */
xlog_tid_t t_tid; /* transaction identifier : 4 */
atomic_t t_ref; /* ticket reference count : 4 */
int t_curr_res; /* current reservation in bytes : 4 */
int t_unit_res; /* unit reservation in bytes : 4 */
char t_ocnt; /* original count : 1 */
@ -309,6 +310,16 @@ typedef struct xlog_rec_ext_header {
} xlog_rec_ext_header_t;
#ifdef __KERNEL__
/*
* Quite misnamed, because this union lays out the actual on-disk log buffer.
*/
typedef union xlog_in_core2 {
xlog_rec_header_t hic_header;
xlog_rec_ext_header_t hic_xheader;
char hic_sector[XLOG_HEADER_SIZE];
} xlog_in_core_2_t;
/*
* - A log record header is 512 bytes. There is plenty of room to grow the
* xlog_rec_header_t into the reserved space.
@ -338,7 +349,7 @@ typedef struct xlog_rec_ext_header {
* We'll put all the read-only and l_icloglock fields in the first cacheline,
* and move everything else out to subsequent cachelines.
*/
typedef struct xlog_iclog_fields {
typedef struct xlog_in_core {
sv_t ic_force_wait;
sv_t ic_write_wait;
struct xlog_in_core *ic_next;
@ -361,40 +372,10 @@ typedef struct xlog_iclog_fields {
/* reference counts need their own cacheline */
atomic_t ic_refcnt ____cacheline_aligned_in_smp;
} xlog_iclog_fields_t;
typedef union xlog_in_core2 {
xlog_rec_header_t hic_header;
xlog_rec_ext_header_t hic_xheader;
char hic_sector[XLOG_HEADER_SIZE];
} xlog_in_core_2_t;
typedef struct xlog_in_core {
xlog_iclog_fields_t hic_fields;
xlog_in_core_2_t *hic_data;
xlog_in_core_2_t *ic_data;
#define ic_header ic_data->hic_header
} xlog_in_core_t;
/*
* Defines to save our code from this glop.
*/
#define ic_force_wait hic_fields.ic_force_wait
#define ic_write_wait hic_fields.ic_write_wait
#define ic_next hic_fields.ic_next
#define ic_prev hic_fields.ic_prev
#define ic_bp hic_fields.ic_bp
#define ic_log hic_fields.ic_log
#define ic_callback hic_fields.ic_callback
#define ic_callback_lock hic_fields.ic_callback_lock
#define ic_callback_tail hic_fields.ic_callback_tail
#define ic_trace hic_fields.ic_trace
#define ic_size hic_fields.ic_size
#define ic_offset hic_fields.ic_offset
#define ic_refcnt hic_fields.ic_refcnt
#define ic_bwritecnt hic_fields.ic_bwritecnt
#define ic_state hic_fields.ic_state
#define ic_datap hic_fields.ic_datap
#define ic_header hic_data->hic_header
/*
* The reservation head lsn is not made up of a cycle number and block number.
* Instead, it uses a cycle number and byte number. Logs don't expect to
@ -404,6 +385,7 @@ typedef struct xlog_in_core {
typedef struct log {
/* The following fields don't need locking */
struct xfs_mount *l_mp; /* mount point */
struct xfs_ail *l_ailp; /* AIL log is working with */
struct xfs_buf *l_xbuf; /* extra buffer for log
* wrapping */
struct xfs_buftarg *l_targ; /* buftarg of log */

View File

@ -36,7 +36,6 @@
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_imap.h"
#include "xfs_alloc.h"
#include "xfs_ialloc.h"
#include "xfs_log_priv.h"
@ -54,10 +53,8 @@ STATIC void xlog_recover_insert_item_backq(xlog_recover_item_t **q,
xlog_recover_item_t *item);
#if defined(DEBUG)
STATIC void xlog_recover_check_summary(xlog_t *);
STATIC void xlog_recover_check_ail(xfs_mount_t *, xfs_log_item_t *, int);
#else
#define xlog_recover_check_summary(log)
#define xlog_recover_check_ail(mp, lip, gen)
#endif
@ -270,21 +267,16 @@ STATIC void
xlog_recover_iodone(
struct xfs_buf *bp)
{
xfs_mount_t *mp;
ASSERT(XFS_BUF_FSPRIVATE(bp, void *));
if (XFS_BUF_GETERROR(bp)) {
/*
* We're not going to bother about retrying
* this during recovery. One strike!
*/
mp = XFS_BUF_FSPRIVATE(bp, xfs_mount_t *);
xfs_ioerror_alert("xlog_recover_iodone",
mp, bp, XFS_BUF_ADDR(bp));
xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
bp->b_mount, bp, XFS_BUF_ADDR(bp));
xfs_force_shutdown(bp->b_mount, SHUTDOWN_META_IO_ERROR);
}
XFS_BUF_SET_FSPRIVATE(bp, NULL);
bp->b_mount = NULL;
XFS_BUF_CLR_IODONE_FUNC(bp);
xfs_biodone(bp);
}
@ -2228,9 +2220,8 @@ xlog_recover_do_buffer_trans(
XFS_BUF_STALE(bp);
error = xfs_bwrite(mp, bp);
} else {
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL ||
XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp);
XFS_BUF_SET_FSPRIVATE(bp, mp);
ASSERT(bp->b_mount == NULL || bp->b_mount == mp);
bp->b_mount = mp;
XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone);
xfs_bdwrite(mp, bp);
}
@ -2247,7 +2238,6 @@ xlog_recover_do_inode_trans(
xfs_inode_log_format_t *in_f;
xfs_mount_t *mp;
xfs_buf_t *bp;
xfs_imap_t imap;
xfs_dinode_t *dip;
xfs_ino_t ino;
int len;
@ -2275,54 +2265,35 @@ xlog_recover_do_inode_trans(
}
ino = in_f->ilf_ino;
mp = log->l_mp;
if (ITEM_TYPE(item) == XFS_LI_INODE) {
imap.im_blkno = (xfs_daddr_t)in_f->ilf_blkno;
imap.im_len = in_f->ilf_len;
imap.im_boffset = in_f->ilf_boffset;
} else {
/*
* It's an old inode format record. We don't know where
* its cluster is located on disk, and we can't allow
* xfs_imap() to figure it out because the inode btrees
* are not ready to be used. Therefore do not pass the
* XFS_IMAP_LOOKUP flag to xfs_imap(). This will give
* us only the single block in which the inode lives
* rather than its cluster, so we must make sure to
* invalidate the buffer when we write it out below.
*/
imap.im_blkno = 0;
error = xfs_imap(log->l_mp, NULL, ino, &imap, 0);
if (error)
goto error;
}
/*
* Inode buffers can be freed, look out for it,
* and do not replay the inode.
*/
if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0)) {
if (xlog_check_buffer_cancelled(log, in_f->ilf_blkno,
in_f->ilf_len, 0)) {
error = 0;
goto error;
}
bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len,
XFS_BUF_LOCK);
bp = xfs_buf_read_flags(mp->m_ddev_targp, in_f->ilf_blkno,
in_f->ilf_len, XFS_BUF_LOCK);
if (XFS_BUF_ISERROR(bp)) {
xfs_ioerror_alert("xlog_recover_do..(read#2)", mp,
bp, imap.im_blkno);
bp, in_f->ilf_blkno);
error = XFS_BUF_GETERROR(bp);
xfs_buf_relse(bp);
goto error;
}
error = 0;
ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
dip = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);
dip = (xfs_dinode_t *)xfs_buf_offset(bp, in_f->ilf_boffset);
/*
* Make sure the place we're flushing out to really looks
* like an inode!
*/
if (unlikely(be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC)) {
if (unlikely(be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC)) {
xfs_buf_relse(bp);
xfs_fs_cmn_err(CE_ALERT, mp,
"xfs_inode_recover: Bad inode magic number, dino ptr = 0x%p, dino bp = 0x%p, ino = %Ld",
@ -2345,12 +2316,12 @@ xlog_recover_do_inode_trans(
}
/* Skip replay when the on disk inode is newer than the log one */
if (dicp->di_flushiter < be16_to_cpu(dip->di_core.di_flushiter)) {
if (dicp->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
/*
* Deal with the wrap case, DI_MAX_FLUSH is less
* than smaller numbers
*/
if (be16_to_cpu(dip->di_core.di_flushiter) == DI_MAX_FLUSH &&
if (be16_to_cpu(dip->di_flushiter) == DI_MAX_FLUSH &&
dicp->di_flushiter < (DI_MAX_FLUSH >> 1)) {
/* do nothing */
} else {
@ -2410,7 +2381,7 @@ xlog_recover_do_inode_trans(
error = EFSCORRUPTED;
goto error;
}
if (unlikely(item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t))) {
if (unlikely(item->ri_buf[1].i_len > sizeof(struct xfs_icdinode))) {
XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(7)",
XFS_ERRLEVEL_LOW, mp, dicp);
xfs_buf_relse(bp);
@ -2422,23 +2393,24 @@ xlog_recover_do_inode_trans(
}
/* The core is in in-core format */
xfs_dinode_to_disk(&dip->di_core,
(xfs_icdinode_t *)item->ri_buf[1].i_addr);
xfs_dinode_to_disk(dip, (xfs_icdinode_t *)item->ri_buf[1].i_addr);
/* the rest is in on-disk format */
if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) {
memcpy((xfs_caddr_t) dip + sizeof(xfs_dinode_core_t),
item->ri_buf[1].i_addr + sizeof(xfs_dinode_core_t),
item->ri_buf[1].i_len - sizeof(xfs_dinode_core_t));
if (item->ri_buf[1].i_len > sizeof(struct xfs_icdinode)) {
memcpy((xfs_caddr_t) dip + sizeof(struct xfs_icdinode),
item->ri_buf[1].i_addr + sizeof(struct xfs_icdinode),
item->ri_buf[1].i_len - sizeof(struct xfs_icdinode));
}
fields = in_f->ilf_fields;
switch (fields & (XFS_ILOG_DEV | XFS_ILOG_UUID)) {
case XFS_ILOG_DEV:
dip->di_u.di_dev = cpu_to_be32(in_f->ilf_u.ilfu_rdev);
xfs_dinode_put_rdev(dip, in_f->ilf_u.ilfu_rdev);
break;
case XFS_ILOG_UUID:
dip->di_u.di_muuid = in_f->ilf_u.ilfu_uuid;
memcpy(XFS_DFORK_DPTR(dip),
&in_f->ilf_u.ilfu_uuid,
sizeof(uuid_t));
break;
}
@ -2454,12 +2426,12 @@ xlog_recover_do_inode_trans(
switch (fields & XFS_ILOG_DFORK) {
case XFS_ILOG_DDATA:
case XFS_ILOG_DEXT:
memcpy(&dip->di_u, src, len);
memcpy(XFS_DFORK_DPTR(dip), src, len);
break;
case XFS_ILOG_DBROOT:
xfs_bmbt_to_bmdr((xfs_bmbt_block_t *)src, len,
&(dip->di_u.di_bmbt),
xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src, len,
(xfs_bmdr_block_t *)XFS_DFORK_DPTR(dip),
XFS_DFORK_DSIZE(dip, mp));
break;
@ -2496,8 +2468,8 @@ xlog_recover_do_inode_trans(
case XFS_ILOG_ABROOT:
dest = XFS_DFORK_APTR(dip);
xfs_bmbt_to_bmdr((xfs_bmbt_block_t *)src, len,
(xfs_bmdr_block_t*)dest,
xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src,
len, (xfs_bmdr_block_t*)dest,
XFS_DFORK_ASIZE(dip, mp));
break;
@ -2512,9 +2484,8 @@ xlog_recover_do_inode_trans(
write_inode_buffer:
if (ITEM_TYPE(item) == XFS_LI_INODE) {
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL ||
XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp);
XFS_BUF_SET_FSPRIVATE(bp, mp);
ASSERT(bp->b_mount == NULL || bp->b_mount == mp);
bp->b_mount = mp;
XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone);
xfs_bdwrite(mp, bp);
} else {
@ -2645,9 +2616,8 @@ xlog_recover_do_dquot_trans(
memcpy(ddq, recddq, item->ri_buf[1].i_len);
ASSERT(dq_f->qlf_size == 2);
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL ||
XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp);
XFS_BUF_SET_FSPRIVATE(bp, mp);
ASSERT(bp->b_mount == NULL || bp->b_mount == mp);
bp->b_mount = mp;
XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone);
xfs_bdwrite(mp, bp);
@ -2689,11 +2659,11 @@ xlog_recover_do_efi_trans(
efip->efi_next_extent = efi_formatp->efi_nextents;
efip->efi_flags |= XFS_EFI_COMMITTED;
spin_lock(&mp->m_ail_lock);
spin_lock(&log->l_ailp->xa_lock);
/*
* xfs_trans_update_ail() drops the AIL lock.
* xfs_trans_ail_update() drops the AIL lock.
*/
xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn);
xfs_trans_ail_update(log->l_ailp, (xfs_log_item_t *)efip, lsn);
return 0;
}
@ -2712,12 +2682,12 @@ xlog_recover_do_efd_trans(
xlog_recover_item_t *item,
int pass)
{
xfs_mount_t *mp;
xfs_efd_log_format_t *efd_formatp;
xfs_efi_log_item_t *efip = NULL;
xfs_log_item_t *lip;
int gen;
__uint64_t efi_id;
struct xfs_ail_cursor cur;
struct xfs_ail *ailp = log->l_ailp;
if (pass == XLOG_RECOVER_PASS1) {
return;
@ -2734,25 +2704,26 @@ xlog_recover_do_efd_trans(
* Search for the efi with the id in the efd format structure
* in the AIL.
*/
mp = log->l_mp;
spin_lock(&mp->m_ail_lock);
lip = xfs_trans_first_ail(mp, &gen);
spin_lock(&ailp->xa_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
while (lip != NULL) {
if (lip->li_type == XFS_LI_EFI) {
efip = (xfs_efi_log_item_t *)lip;
if (efip->efi_format.efi_id == efi_id) {
/*
* xfs_trans_delete_ail() drops the
* xfs_trans_ail_delete() drops the
* AIL lock.
*/
xfs_trans_delete_ail(mp, lip);
xfs_trans_ail_delete(ailp, lip);
xfs_efi_item_free(efip);
return;
spin_lock(&ailp->xa_lock);
break;
}
}
lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
lip = xfs_trans_ail_cursor_next(ailp, &cur);
}
spin_unlock(&mp->m_ail_lock);
xfs_trans_ail_cursor_done(ailp, &cur);
spin_unlock(&ailp->xa_lock);
}
/*
@ -3035,33 +3006,6 @@ abort_error:
return error;
}
/*
* Verify that once we've encountered something other than an EFI
* in the AIL that there are no more EFIs in the AIL.
*/
#if defined(DEBUG)
STATIC void
xlog_recover_check_ail(
xfs_mount_t *mp,
xfs_log_item_t *lip,
int gen)
{
int orig_gen = gen;
do {
ASSERT(lip->li_type != XFS_LI_EFI);
lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
/*
* The check will be bogus if we restart from the
* beginning of the AIL, so ASSERT that we don't.
* We never should since we're holding the AIL lock
* the entire time.
*/
ASSERT(gen == orig_gen);
} while (lip != NULL);
}
#endif /* DEBUG */
/*
* When this is called, all of the EFIs which did not have
* corresponding EFDs should be in the AIL. What we do now
@ -3086,20 +3030,23 @@ xlog_recover_process_efis(
{
xfs_log_item_t *lip;
xfs_efi_log_item_t *efip;
int gen;
xfs_mount_t *mp;
int error = 0;
struct xfs_ail_cursor cur;
struct xfs_ail *ailp;
mp = log->l_mp;
spin_lock(&mp->m_ail_lock);
lip = xfs_trans_first_ail(mp, &gen);
ailp = log->l_ailp;
spin_lock(&ailp->xa_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
while (lip != NULL) {
/*
* We're done when we see something other than an EFI.
* There should be no EFIs left in the AIL now.
*/
if (lip->li_type != XFS_LI_EFI) {
xlog_recover_check_ail(mp, lip, gen);
#ifdef DEBUG
for (; lip; lip = xfs_trans_ail_cursor_next(ailp, &cur))
ASSERT(lip->li_type != XFS_LI_EFI);
#endif
break;
}
@ -3108,18 +3055,20 @@ xlog_recover_process_efis(
*/
efip = (xfs_efi_log_item_t *)lip;
if (efip->efi_flags & XFS_EFI_RECOVERED) {
lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
lip = xfs_trans_ail_cursor_next(ailp, &cur);
continue;
}
spin_unlock(&mp->m_ail_lock);
error = xlog_recover_process_efi(mp, efip);
spin_unlock(&ailp->xa_lock);
error = xlog_recover_process_efi(log->l_mp, efip);
spin_lock(&ailp->xa_lock);
if (error)
return error;
spin_lock(&mp->m_ail_lock);
lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
goto out;
lip = xfs_trans_ail_cursor_next(ailp, &cur);
}
spin_unlock(&mp->m_ail_lock);
out:
xfs_trans_ail_cursor_done(ailp, &cur);
spin_unlock(&ailp->xa_lock);
return error;
}
@ -3140,19 +3089,16 @@ xlog_recover_clear_agi_bucket(
int error;
tp = xfs_trans_alloc(mp, XFS_TRANS_CLEAR_AGI_BUCKET);
error = xfs_trans_reserve(tp, 0, XFS_CLEAR_AGI_BUCKET_LOG_RES(mp), 0, 0, 0);
if (!error)
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), 0, &agibp);
error = xfs_trans_reserve(tp, 0, XFS_CLEAR_AGI_BUCKET_LOG_RES(mp),
0, 0, 0);
if (error)
goto out_abort;
error = EINVAL;
agi = XFS_BUF_TO_AGI(agibp);
if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC)
error = xfs_read_agi(mp, tp, agno, &agibp);
if (error)
goto out_abort;
agi = XFS_BUF_TO_AGI(agibp);
agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
offset = offsetof(xfs_agi_t, agi_unlinked) +
(sizeof(xfs_agino_t) * bucket);
@ -3172,6 +3118,62 @@ out_error:
return;
}
STATIC xfs_agino_t
xlog_recover_process_one_iunlink(
struct xfs_mount *mp,
xfs_agnumber_t agno,
xfs_agino_t agino,
int bucket)
{
struct xfs_buf *ibp;
struct xfs_dinode *dip;
struct xfs_inode *ip;
xfs_ino_t ino;
int error;
ino = XFS_AGINO_TO_INO(mp, agno, agino);
error = xfs_iget(mp, NULL, ino, 0, 0, &ip, 0);
if (error)
goto fail;
/*
* Get the on disk inode to find the next inode in the bucket.
*/
error = xfs_itobp(mp, NULL, ip, &dip, &ibp, XFS_BUF_LOCK);
if (error)
goto fail_iput;
ASSERT(ip->i_d.di_nlink == 0);
ASSERT(ip->i_d.di_mode != 0);
/* setup for the next pass */
agino = be32_to_cpu(dip->di_next_unlinked);
xfs_buf_relse(ibp);
/*
* Prevent any DMAPI event from being sent when the reference on
* the inode is dropped.
*/
ip->i_d.di_dmevmask = 0;
IRELE(ip);
return agino;
fail_iput:
IRELE(ip);
fail:
/*
* We can't read in the inode this bucket points to, or this inode
* is messed up. Just ditch this bucket of inodes. We will lose
* some inodes and space, but at least we won't hang.
*
* Call xlog_recover_clear_agi_bucket() to perform a transaction to
* clear the inode pointer in the bucket.
*/
xlog_recover_clear_agi_bucket(mp, agno, bucket);
return NULLAGINO;
}
/*
* xlog_iunlink_recover
*
@ -3192,11 +3194,7 @@ xlog_recover_process_iunlinks(
xfs_agnumber_t agno;
xfs_agi_t *agi;
xfs_buf_t *agibp;
xfs_buf_t *ibp;
xfs_dinode_t *dip;
xfs_inode_t *ip;
xfs_agino_t agino;
xfs_ino_t ino;
int bucket;
int error;
uint mp_dmevmask;
@ -3213,22 +3211,21 @@ xlog_recover_process_iunlinks(
/*
* Find the agi for this ag.
*/
agibp = xfs_buf_read(mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), 0);
if (XFS_BUF_ISERROR(agibp)) {
xfs_ioerror_alert("xlog_recover_process_iunlinks(#1)",
log->l_mp, agibp,
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)));
error = xfs_read_agi(mp, NULL, agno, &agibp);
if (error) {
/*
* AGI is b0rked. Don't process it.
*
* We should probably mark the filesystem as corrupt
* after we've recovered all the ag's we can....
*/
continue;
}
agi = XFS_BUF_TO_AGI(agibp);
ASSERT(XFS_AGI_MAGIC == be32_to_cpu(agi->agi_magicnum));
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) {
agino = be32_to_cpu(agi->agi_unlinked[bucket]);
while (agino != NULLAGINO) {
/*
* Release the agi buffer so that it can
* be acquired in the normal course of the
@ -3236,87 +3233,17 @@ xlog_recover_process_iunlinks(
*/
xfs_buf_relse(agibp);
ino = XFS_AGINO_TO_INO(mp, agno, agino);
error = xfs_iget(mp, NULL, ino, 0, 0, &ip, 0);
ASSERT(error || (ip != NULL));
if (!error) {
/*
* Get the on disk inode to find the
* next inode in the bucket.
*/
error = xfs_itobp(mp, NULL, ip, &dip,
&ibp, 0, 0,
XFS_BUF_LOCK);
ASSERT(error || (dip != NULL));
}
if (!error) {
ASSERT(ip->i_d.di_nlink == 0);
/* setup for the next pass */
agino = be32_to_cpu(
dip->di_next_unlinked);
xfs_buf_relse(ibp);
/*
* Prevent any DMAPI event from
* being sent when the
* reference on the inode is
* dropped.
*/
ip->i_d.di_dmevmask = 0;
/*
* If this is a new inode, handle
* it specially. Otherwise,
* just drop our reference to the
* inode. If there are no
* other references, this will
* send the inode to
* xfs_inactive() which will
* truncate the file and free
* the inode.
*/
if (ip->i_d.di_mode == 0)
xfs_iput_new(ip, 0);
else
IRELE(ip);
} else {
/*
* We can't read in the inode
* this bucket points to, or
* this inode is messed up. Just
* ditch this bucket of inodes. We
* will lose some inodes and space,
* but at least we won't hang. Call
* xlog_recover_clear_agi_bucket()
* to perform a transaction to clear
* the inode pointer in the bucket.
*/
xlog_recover_clear_agi_bucket(mp, agno,
bucket);
agino = NULLAGINO;
}
agino = xlog_recover_process_one_iunlink(mp,
agno, agino, bucket);
/*
* Reacquire the agibuffer and continue around
* the loop.
* the loop. This should never fail as we know
* the buffer was good earlier on.
*/
agibp = xfs_buf_read(mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno,
XFS_AGI_DADDR(mp)),
XFS_FSS_TO_BB(mp, 1), 0);
if (XFS_BUF_ISERROR(agibp)) {
xfs_ioerror_alert(
"xlog_recover_process_iunlinks(#2)",
log->l_mp, agibp,
XFS_AG_DADDR(mp, agno,
XFS_AGI_DADDR(mp)));
}
error = xfs_read_agi(mp, NULL, agno, &agibp);
ASSERT(error == 0);
agi = XFS_BUF_TO_AGI(agibp);
ASSERT(XFS_AGI_MAGIC == be32_to_cpu(
agi->agi_magicnum));
}
}
@ -3367,7 +3294,6 @@ xlog_pack_data(
int size = iclog->ic_offset + roundoff;
__be32 cycle_lsn;
xfs_caddr_t dp;
xlog_in_core_2_t *xhdr;
xlog_pack_data_checksum(log, iclog, size);
@ -3382,7 +3308,8 @@ xlog_pack_data(
}
if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) {
xhdr = (xlog_in_core_2_t *)&iclog->ic_header;
xlog_in_core_2_t *xhdr = iclog->ic_data;
for ( ; i < BTOBB(size); i++) {
j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
@ -3440,7 +3367,6 @@ xlog_unpack_data(
xlog_t *log)
{
int i, j, k;
xlog_in_core_2_t *xhdr;
for (i = 0; i < BTOBB(be32_to_cpu(rhead->h_len)) &&
i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) {
@ -3449,7 +3375,7 @@ xlog_unpack_data(
}
if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) {
xhdr = (xlog_in_core_2_t *)rhead;
xlog_in_core_2_t *xhdr = (xlog_in_core_2_t *)rhead;
for ( ; i < BTOBB(be32_to_cpu(rhead->h_len)); i++) {
j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
@ -4003,11 +3929,8 @@ xlog_recover_check_summary(
{
xfs_mount_t *mp;
xfs_agf_t *agfp;
xfs_agi_t *agip;
xfs_buf_t *agfbp;
xfs_buf_t *agibp;
xfs_daddr_t agfdaddr;
xfs_daddr_t agidaddr;
xfs_buf_t *sbbp;
#ifdef XFS_LOUD_RECOVERY
xfs_sb_t *sbp;
@ -4016,6 +3939,7 @@ xlog_recover_check_summary(
__uint64_t freeblks;
__uint64_t itotal;
__uint64_t ifree;
int error;
mp = log->l_mp;
@ -4023,37 +3947,27 @@ xlog_recover_check_summary(
itotal = 0LL;
ifree = 0LL;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
agfdaddr = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp));
agfbp = xfs_buf_read(mp->m_ddev_targp, agfdaddr,
XFS_FSS_TO_BB(mp, 1), 0);
if (XFS_BUF_ISERROR(agfbp)) {
xfs_ioerror_alert("xlog_recover_check_summary(agf)",
mp, agfbp, agfdaddr);
error = xfs_read_agf(mp, NULL, agno, 0, &agfbp);
if (error) {
xfs_fs_cmn_err(CE_ALERT, mp,
"xlog_recover_check_summary(agf)"
"agf read failed agno %d error %d",
agno, error);
} else {
agfp = XFS_BUF_TO_AGF(agfbp);
freeblks += be32_to_cpu(agfp->agf_freeblks) +
be32_to_cpu(agfp->agf_flcount);
xfs_buf_relse(agfbp);
}
agfp = XFS_BUF_TO_AGF(agfbp);
ASSERT(XFS_AGF_MAGIC == be32_to_cpu(agfp->agf_magicnum));
ASSERT(XFS_AGF_GOOD_VERSION(be32_to_cpu(agfp->agf_versionnum)));
ASSERT(be32_to_cpu(agfp->agf_seqno) == agno);
freeblks += be32_to_cpu(agfp->agf_freeblks) +
be32_to_cpu(agfp->agf_flcount);
xfs_buf_relse(agfbp);
error = xfs_read_agi(mp, NULL, agno, &agibp);
if (!error) {
struct xfs_agi *agi = XFS_BUF_TO_AGI(agibp);
agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp));
agibp = xfs_buf_read(mp->m_ddev_targp, agidaddr,
XFS_FSS_TO_BB(mp, 1), 0);
if (XFS_BUF_ISERROR(agibp)) {
xfs_ioerror_alert("xlog_recover_check_summary(agi)",
mp, agibp, agidaddr);
itotal += be32_to_cpu(agi->agi_count);
ifree += be32_to_cpu(agi->agi_freecount);
xfs_buf_relse(agibp);
}
agip = XFS_BUF_TO_AGI(agibp);
ASSERT(XFS_AGI_MAGIC == be32_to_cpu(agip->agi_magicnum));
ASSERT(XFS_AGI_GOOD_VERSION(be32_to_cpu(agip->agi_versionnum)));
ASSERT(be32_to_cpu(agip->agi_seqno) == agno);
itotal += be32_to_cpu(agip->agi_count);
ifree += be32_to_cpu(agip->agi_freecount);
xfs_buf_relse(agibp);
}
sbbp = xfs_getsb(mp, 0);

View File

@ -567,8 +567,6 @@ xfs_readsb(xfs_mount_t *mp, int flags)
STATIC void
xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
{
int i;
mp->m_agfrotor = mp->m_agirotor = 0;
spin_lock_init(&mp->m_agirotor_lock);
mp->m_maxagi = mp->m_sb.sb_agcount;
@ -577,12 +575,10 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1;
mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
mp->m_litino = sbp->sb_inodesize -
((uint)sizeof(xfs_dinode_core_t) + (uint)sizeof(xfs_agino_t));
mp->m_litino = sbp->sb_inodesize - sizeof(struct xfs_dinode);
mp->m_blockmask = sbp->sb_blocksize - 1;
mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
mp->m_blockwmask = mp->m_blockwsize - 1;
INIT_LIST_HEAD(&mp->m_del_inodes);
/*
* Setup for attributes, in case they get created.
@ -605,24 +601,20 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
}
ASSERT(mp->m_attroffset < XFS_LITINO(mp));
for (i = 0; i < 2; i++) {
mp->m_alloc_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize,
xfs_alloc, i == 0);
mp->m_alloc_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize,
xfs_alloc, i == 0);
}
for (i = 0; i < 2; i++) {
mp->m_bmap_dmxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize,
xfs_bmbt, i == 0);
mp->m_bmap_dmnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize,
xfs_bmbt, i == 0);
}
for (i = 0; i < 2; i++) {
mp->m_inobt_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize,
xfs_inobt, i == 0);
mp->m_inobt_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize,
xfs_inobt, i == 0);
}
mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2;
mp->m_inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
mp->m_inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
mp->m_inobt_mnr[0] = mp->m_inobt_mxr[0] / 2;
mp->m_inobt_mnr[1] = mp->m_inobt_mxr[1] / 2;
mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1);
mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0);
mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK,
@ -1228,6 +1220,16 @@ xfs_unmountfs(
__uint64_t resblks;
int error;
/*
* Release dquot that rootinode, rbmino and rsumino might be holding,
* and release the quota inodes.
*/
XFS_QM_UNMOUNT(mp);
if (mp->m_rbmip)
IRELE(mp->m_rbmip);
if (mp->m_rsumip)
IRELE(mp->m_rsumip);
IRELE(mp->m_rootip);
/*
@ -1241,7 +1243,7 @@ xfs_unmountfs(
* need to force the log first.
*/
xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
xfs_iflush_all(mp);
xfs_reclaim_inodes(mp, 0, XFS_IFLUSH_ASYNC);
XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING);
@ -1288,11 +1290,6 @@ xfs_unmountfs(
xfs_unmountfs_wait(mp); /* wait for async bufs */
xfs_log_unmount(mp); /* Done! No more fs ops. */
/*
* All inodes from this mount point should be freed.
*/
ASSERT(mp->m_inodes == NULL);
if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0)
uuid_table_remove(&mp->m_sb.sb_uuid);
@ -1365,24 +1362,6 @@ xfs_log_sbcount(
return error;
}
STATIC void
xfs_mark_shared_ro(
xfs_mount_t *mp,
xfs_buf_t *bp)
{
xfs_dsb_t *sb = XFS_BUF_TO_SBP(bp);
__uint16_t version;
if (!(sb->sb_flags & XFS_SBF_READONLY))
sb->sb_flags |= XFS_SBF_READONLY;
version = be16_to_cpu(sb->sb_versionnum);
if ((version & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4 ||
!(version & XFS_SB_VERSION_SHAREDBIT))
version |= XFS_SB_VERSION_SHAREDBIT;
sb->sb_versionnum = cpu_to_be16(version);
}
int
xfs_unmountfs_writesb(xfs_mount_t *mp)
{
@ -1398,12 +1377,6 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
sbp = xfs_getsb(mp, 0);
/*
* mark shared-readonly if desired
*/
if (mp->m_mk_sharedro)
xfs_mark_shared_ro(mp, sbp);
XFS_BUF_UNDONE(sbp);
XFS_BUF_UNREAD(sbp);
XFS_BUF_UNDELAYWRITE(sbp);
@ -1415,8 +1388,6 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
if (error)
xfs_ioerror_alert("xfs_unmountfs_writesb",
mp, sbp, XFS_BUF_ADDR(sbp));
if (error && mp->m_mk_sharedro)
xfs_fs_cmn_err(CE_ALERT, mp, "Superblock write error detected while unmounting. Filesystem may not be marked shared readonly");
xfs_buf_relse(sbp);
}
return error;

View File

@ -18,7 +18,6 @@
#ifndef __XFS_MOUNT_H__
#define __XFS_MOUNT_H__
typedef struct xfs_trans_reservations {
uint tr_write; /* extent alloc trans */
uint tr_itruncate; /* truncate trans */
@ -44,14 +43,16 @@ typedef struct xfs_trans_reservations {
} xfs_trans_reservations_t;
#ifndef __KERNEL__
/*
* Moved here from xfs_ag.h to avoid reordering header files
*/
#define XFS_DADDR_TO_AGNO(mp,d) \
((xfs_agnumber_t)(XFS_BB_TO_FSBT(mp, d) / (mp)->m_sb.sb_agblocks))
#define XFS_DADDR_TO_AGBNO(mp,d) \
((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks))
#else
#else /* __KERNEL__ */
#include "xfs_sync.h"
struct cred;
struct log;
struct xfs_mount_args;
@ -62,6 +63,7 @@ struct xfs_extdelta;
struct xfs_swapext;
struct xfs_mru_cache;
struct xfs_nameops;
struct xfs_ail;
/*
* Prototypes and functions for the Data Migration subsystem.
@ -115,7 +117,7 @@ struct xfs_quotainfo;
typedef int (*xfs_qminit_t)(struct xfs_mount *, uint *, uint *);
typedef int (*xfs_qmmount_t)(struct xfs_mount *, uint, uint);
typedef int (*xfs_qmunmount_t)(struct xfs_mount *);
typedef void (*xfs_qmunmount_t)(struct xfs_mount *);
typedef void (*xfs_qmdone_t)(struct xfs_mount *);
typedef void (*xfs_dqrele_t)(struct xfs_dquot *);
typedef int (*xfs_dqattach_t)(struct xfs_inode *, uint);
@ -132,7 +134,7 @@ typedef struct xfs_dquot * (*xfs_dqvopchown_t)(
struct xfs_dquot **, struct xfs_dquot *);
typedef int (*xfs_dqvopchownresv_t)(struct xfs_trans *, struct xfs_inode *,
struct xfs_dquot *, struct xfs_dquot *, uint);
typedef void (*xfs_dqstatvfs_t)(struct xfs_inode *, bhv_statvfs_t *);
typedef void (*xfs_dqstatvfs_t)(struct xfs_inode *, struct kstatfs *);
typedef int (*xfs_dqsync_t)(struct xfs_mount *, int flags);
typedef int (*xfs_quotactl_t)(struct xfs_mount *, int, int, xfs_caddr_t);
@ -223,18 +225,10 @@ extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int);
#define xfs_icsb_sync_counters_locked(mp, flags) do { } while (0)
#endif
typedef struct xfs_ail {
struct list_head xa_ail;
uint xa_gen;
struct task_struct *xa_task;
xfs_lsn_t xa_target;
} xfs_ail_t;
typedef struct xfs_mount {
struct super_block *m_super;
xfs_tid_t m_tid; /* next unused tid for fs */
spinlock_t m_ail_lock; /* fs AIL mutex */
xfs_ail_t m_ail; /* fs active log item list */
struct xfs_ail *m_ail; /* fs active log item list */
xfs_sb_t m_sb; /* copy of fs superblock */
spinlock_t m_sb_lock; /* sb counter lock */
struct xfs_buf *m_sb_bp; /* buffer for superblock */
@ -247,10 +241,6 @@ typedef struct xfs_mount {
xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */
spinlock_t m_agirotor_lock;/* .. and lock protecting it */
xfs_agnumber_t m_maxagi; /* highest inode alloc group */
struct xfs_inode *m_inodes; /* active inode list */
struct list_head m_del_inodes; /* inodes to reclaim */
mutex_t m_ilock; /* inode list mutex */
uint m_ireclaims; /* count of calls to reclaim*/
uint m_readio_log; /* min read size log bytes */
uint m_readio_blocks; /* min read size blocks */
uint m_writeio_log; /* min write size log bytes */
@ -267,7 +257,6 @@ typedef struct xfs_mount {
xfs_buftarg_t *m_ddev_targp; /* saves taking the address */
xfs_buftarg_t *m_logdev_targp;/* ptr to log device */
xfs_buftarg_t *m_rtdev_targp; /* ptr to rt device */
__uint8_t m_dircook_elog; /* log d-cookie entry bits */
__uint8_t m_blkbit_log; /* blocklog + NBBY */
__uint8_t m_blkbb_log; /* blocklog - BBSHIFT */
__uint8_t m_agno_log; /* log #ag's */
@ -276,12 +265,12 @@ typedef struct xfs_mount {
uint m_blockmask; /* sb_blocksize-1 */
uint m_blockwsize; /* sb_blocksize in words */
uint m_blockwmask; /* blockwsize-1 */
uint m_alloc_mxr[2]; /* XFS_ALLOC_BLOCK_MAXRECS */
uint m_alloc_mnr[2]; /* XFS_ALLOC_BLOCK_MINRECS */
uint m_bmap_dmxr[2]; /* XFS_BMAP_BLOCK_DMAXRECS */
uint m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */
uint m_inobt_mxr[2]; /* XFS_INOBT_BLOCK_MAXRECS */
uint m_inobt_mnr[2]; /* XFS_INOBT_BLOCK_MINRECS */
uint m_alloc_mxr[2]; /* max alloc btree records */
uint m_alloc_mnr[2]; /* min alloc btree records */
uint m_bmap_dmxr[2]; /* max bmap btree records */
uint m_bmap_dmnr[2]; /* min bmap btree records */
uint m_inobt_mxr[2]; /* max inobt btree records */
uint m_inobt_mnr[2]; /* min inobt btree records */
uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */
uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */
uint m_in_maxlevels; /* XFS_IN_MAXLEVELS */
@ -312,9 +301,6 @@ typedef struct xfs_mount {
int m_sinoalign; /* stripe unit inode alignment */
int m_attr_magicpct;/* 37% of the blocksize */
int m_dir_magicpct; /* 37% of the dir blocksize */
__uint8_t m_mk_sharedro; /* mark shared ro on unmount */
__uint8_t m_inode_quiesce;/* call quiesce on new inodes.
field governed by m_ilock */
__uint8_t m_sectbb_log; /* sectlog - BBSHIFT */
const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */
int m_dirblksize; /* directory block sz--bytes */
@ -362,7 +348,6 @@ typedef struct xfs_mount {
#define XFS_MOUNT_ATTR2 (1ULL << 8) /* allow use of attr2 format */
#define XFS_MOUNT_GRPID (1ULL << 9) /* group-ID assigned from directory */
#define XFS_MOUNT_NORECOVERY (1ULL << 10) /* no recovery - dirty fs */
#define XFS_MOUNT_SHARED (1ULL << 11) /* shared mount */
#define XFS_MOUNT_DFLT_IOSIZE (1ULL << 12) /* set default i/o size */
#define XFS_MOUNT_OSYNCISOSYNC (1ULL << 13) /* o_sync is REALLY o_sync */
/* osyncisdsync is now default*/
@ -439,6 +424,16 @@ void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname,
#define xfs_force_shutdown(m,f) \
xfs_do_force_shutdown(m, f, __FILE__, __LINE__)
#define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */
#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */
#define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */
#define SHUTDOWN_CORRUPT_INCORE 0x0008 /* corrupt in-memory data structures */
#define SHUTDOWN_REMOTE_REQ 0x0010 /* shutdown came from remote cell */
#define SHUTDOWN_DEVICE_REQ 0x0020 /* failed all paths to the device */
#define xfs_test_for_freeze(mp) ((mp)->m_super->s_frozen)
#define xfs_wait_for_freeze(mp,l) vfs_check_frozen((mp)->m_super, (l))
/*
* Flags for xfs_mountfs
*/
@ -508,14 +503,12 @@ typedef struct xfs_mod_sb {
#define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock))
#define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock))
extern void xfs_mod_sb(xfs_trans_t *, __int64_t);
extern int xfs_log_sbcount(xfs_mount_t *, uint);
extern int xfs_mountfs(xfs_mount_t *mp);
extern void xfs_mountfs_check_barriers(xfs_mount_t *mp);
extern void xfs_unmountfs(xfs_mount_t *);
extern int xfs_unmountfs_writesb(xfs_mount_t *);
extern int xfs_unmount_flush(xfs_mount_t *, int);
extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
extern int xfs_mod_incore_sb_unlocked(xfs_mount_t *, xfs_sb_field_t,
int64_t, int);
@ -525,20 +518,20 @@ extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
extern int xfs_readsb(xfs_mount_t *, int);
extern void xfs_freesb(xfs_mount_t *);
extern int xfs_fs_writable(xfs_mount_t *);
extern int xfs_syncsub(xfs_mount_t *, int, int *);
extern int xfs_sync_inodes(xfs_mount_t *, int, int *);
extern xfs_agnumber_t xfs_initialize_perag(xfs_mount_t *, xfs_agnumber_t);
extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t);
extern int xfs_dmops_get(struct xfs_mount *, struct xfs_mount_args *);
extern int xfs_dmops_get(struct xfs_mount *);
extern void xfs_dmops_put(struct xfs_mount *);
extern int xfs_qmops_get(struct xfs_mount *, struct xfs_mount_args *);
extern int xfs_qmops_get(struct xfs_mount *);
extern void xfs_qmops_put(struct xfs_mount *);
extern struct xfs_dmops xfs_dmcore_xfs;
#endif /* __KERNEL__ */
extern void xfs_mod_sb(struct xfs_trans *, __int64_t);
extern xfs_agnumber_t xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t);
extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
#endif /* __XFS_MOUNT_H__ */

View File

@ -28,7 +28,6 @@
#include "xfs_mount.h"
#include "xfs_quota.h"
#include "xfs_error.h"
#include "xfs_clnt.h"
STATIC struct xfs_dquot *
@ -131,9 +130,9 @@ static struct xfs_qmops xfs_qmcore_stub = {
};
int
xfs_qmops_get(struct xfs_mount *mp, struct xfs_mount_args *args)
xfs_qmops_get(struct xfs_mount *mp)
{
if (args->flags & (XFSMNT_UQUOTA | XFSMNT_PQUOTA | XFSMNT_GQUOTA)) {
if (XFS_IS_QUOTA_RUNNING(mp)) {
#ifdef CONFIG_XFS_QUOTA
mp->m_qm_ops = &xfs_qmcore_xfs;
#else

View File

@ -84,11 +84,9 @@ typedef struct xfs_dqblk {
#define XFS_DQ_USER 0x0001 /* a user quota */
#define XFS_DQ_PROJ 0x0002 /* project quota */
#define XFS_DQ_GROUP 0x0004 /* a group quota */
#define XFS_DQ_FLOCKED 0x0008 /* flush lock taken */
#define XFS_DQ_DIRTY 0x0010 /* dquot is dirty */
#define XFS_DQ_WANT 0x0020 /* for lookup/reclaim race */
#define XFS_DQ_INACTIVE 0x0040 /* dq off mplist & hashlist */
#define XFS_DQ_MARKER 0x0080 /* sentinel */
#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
#define XFS_DQ_WANT 0x0010 /* for lookup/reclaim race */
#define XFS_DQ_INACTIVE 0x0020 /* dq off mplist & hashlist */
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)

View File

@ -41,31 +41,6 @@
#include "xfs_vnodeops.h"
/*
* Given an array of up to 4 inode pointers, unlock the pointed to inodes.
* If there are fewer than 4 entries in the array, the empty entries will
* be at the end and will have NULL pointers in them.
*/
STATIC void
xfs_rename_unlock4(
xfs_inode_t **i_tab,
uint lock_mode)
{
int i;
xfs_iunlock(i_tab[0], lock_mode);
for (i = 1; i < 4; i++) {
if (i_tab[i] == NULL)
break;
/*
* Watch out for duplicate entries in the table.
*/
if (i_tab[i] != i_tab[i-1])
xfs_iunlock(i_tab[i], lock_mode);
}
}
/*
* Enter all inodes for a rename transaction into a sorted array.
*/
@ -204,19 +179,6 @@ xfs_rename(
*/
xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
/*
* If we are using project inheritance, we only allow renames
* into our tree when the project IDs are the same; else the
* 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))) {
error = XFS_ERROR(EXDEV);
xfs_rename_unlock4(inodes, XFS_ILOCK_EXCL);
xfs_trans_cancel(tp, cancel_flags);
goto std_return;
}
/*
* Join all the inodes to the transaction. From this point on,
* we can rely on either trans_commit or trans_cancel to unlock
@ -241,6 +203,17 @@ xfs_rename(
xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
}
/*
* If we are using project inheritance, we only allow renames
* into our tree when the project IDs are the same; else the
* 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))) {
error = XFS_ERROR(EXDEV);
goto error_return;
}
/*
* Set up the target.
*/
@ -367,19 +340,11 @@ xfs_rename(
&first_block, &free_list, spaceres);
if (error)
goto abort_return;
xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
/*
* Update the generation counts on all the directory inodes
* that we're modifying.
*/
src_dp->i_gen++;
xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
if (new_parent) {
target_dp->i_gen++;
if (new_parent)
xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
}
/*
* If this is a synchronous mount, make sure that the

View File

@ -85,7 +85,6 @@ xfs_growfs_rt_alloc(
{
xfs_fileoff_t bno; /* block number in file */
xfs_buf_t *bp; /* temporary buffer for zeroing */
int cancelflags; /* flags for xfs_trans_cancel */
int committed; /* transaction committed flag */
xfs_daddr_t d; /* disk block address */
int error; /* error return value */
@ -96,15 +95,16 @@ xfs_growfs_rt_alloc(
xfs_bmbt_irec_t map; /* block map output */
int nmap; /* number of block maps */
int resblks; /* space reservation */
xfs_trans_t *tp; /* transaction pointer */
/*
* Allocate space to the file, as necessary.
*/
while (oblocks < nblocks) {
int cancelflags = 0;
xfs_trans_t *tp;
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC);
resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks);
cancelflags = 0;
/*
* Reserve space & log for one extent added to the file.
*/
@ -171,7 +171,9 @@ xfs_growfs_rt_alloc(
mp->m_bsize, 0);
if (bp == NULL) {
error = XFS_ERROR(EIO);
goto error_cancel;
error_cancel:
xfs_trans_cancel(tp, cancelflags);
goto error;
}
memset(XFS_BUF_PTR(bp), 0, mp->m_sb.sb_blocksize);
xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
@ -188,8 +190,6 @@ xfs_growfs_rt_alloc(
oblocks = map.br_startoff + map.br_blockcount;
}
return 0;
error_cancel:
xfs_trans_cancel(tp, cancelflags);
error:
return error;
}
@ -1856,7 +1856,6 @@ xfs_growfs_rt(
{
xfs_rtblock_t bmbno; /* bitmap block number */
xfs_buf_t *bp; /* temporary buffer */
int cancelflags; /* flags for xfs_trans_cancel */
int error; /* error return value */
xfs_inode_t *ip; /* bitmap inode, used as lock */
xfs_mount_t *nmp; /* new (fake) mount structure */
@ -1872,13 +1871,13 @@ xfs_growfs_rt(
xfs_extlen_t rsumblocks; /* current number of rt summary blks */
xfs_sb_t *sbp; /* old superblock */
xfs_fsblock_t sumbno; /* summary block number */
xfs_trans_t *tp; /* transaction pointer */
sbp = &mp->m_sb;
cancelflags = 0;
/*
* Initial error checking.
*/
if (!capable(CAP_SYS_ADMIN))
return XFS_ERROR(EPERM);
if (mp->m_rtdev_targp == NULL || mp->m_rbmip == NULL ||
(nrblocks = in->newblocks) <= sbp->sb_rblocks ||
(sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))
@ -1942,6 +1941,9 @@ xfs_growfs_rt(
((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
bmbno < nrbmblocks;
bmbno++) {
xfs_trans_t *tp;
int cancelflags = 0;
*nmp = *mp;
nsbp = &nmp->m_sb;
/*
@ -1967,16 +1969,15 @@ xfs_growfs_rt(
* Start a transaction, get the log reservation.
*/
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_FREE);
cancelflags = 0;
if ((error = xfs_trans_reserve(tp, 0,
XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0)))
break;
goto error_cancel;
/*
* Lock out other callers by grabbing the bitmap inode lock.
*/
if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
XFS_ILOCK_EXCL, &ip)))
break;
goto error_cancel;
ASSERT(ip == mp->m_rbmip);
/*
* Update the bitmap inode's size.
@ -1990,7 +1991,7 @@ xfs_growfs_rt(
*/
if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0,
XFS_ILOCK_EXCL, &ip)))
break;
goto error_cancel;
ASSERT(ip == mp->m_rsumip);
/*
* Update the summary inode's size.
@ -2005,7 +2006,7 @@ xfs_growfs_rt(
mp->m_rsumlevels != nmp->m_rsumlevels) {
error = xfs_rtcopy_summary(mp, nmp, tp);
if (error)
break;
goto error_cancel;
}
/*
* Update superblock fields.
@ -2031,8 +2032,11 @@ xfs_growfs_rt(
bp = NULL;
error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
if (error)
if (error) {
error_cancel:
xfs_trans_cancel(tp, cancelflags);
break;
}
/*
* Mark more blocks free in the superblock.
*/
@ -2045,15 +2049,10 @@ xfs_growfs_rt(
mp->m_rsumsize = nrsumsize;
error = xfs_trans_commit(tp, 0);
if (error) {
tp = NULL;
if (error)
break;
}
}
if (error && tp)
xfs_trans_cancel(tp, cancelflags);
/*
* Free the fake mp structure.
*/

View File

@ -406,7 +406,7 @@ xfs_bwrite(
* XXXsup how does this work for quotas.
*/
XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb);
XFS_BUF_SET_FSPRIVATE3(bp, mp);
bp->b_mount = mp;
XFS_BUF_WRITE(bp);
if ((error = XFS_bwrite(bp))) {

View File

@ -79,6 +79,7 @@ struct xfs_mount;
#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
#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_OKREALFBITS \
(XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
@ -296,30 +297,34 @@ typedef enum {
#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
static inline int xfs_sb_good_version(xfs_sb_t *sbp)
{
/* We always support version 1-3 */
if (sbp->sb_versionnum >= XFS_SB_VERSION_1 &&
sbp->sb_versionnum <= XFS_SB_VERSION_3)
return 1;
/* We support version 4 if all feature bits are supported */
if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) {
if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) ||
((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) &&
(sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS)))
return 0;
#ifdef __KERNEL__
static inline int xfs_sb_good_version(xfs_sb_t *sbp)
{
return (((sbp->sb_versionnum >= XFS_SB_VERSION_1) && \
(sbp->sb_versionnum <= XFS_SB_VERSION_3)) || \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
!((sbp->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) || \
((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && \
(sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS))) && \
(sbp->sb_shared_vn <= XFS_SB_MAX_SHARED_VN)));
}
if (sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
return 0;
#else
static inline int xfs_sb_good_version(xfs_sb_t *sbp)
{
return (((sbp->sb_versionnum >= XFS_SB_VERSION_1) && \
(sbp->sb_versionnum <= XFS_SB_VERSION_3)) || \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
!((sbp->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) || \
((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && \
(sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS))) && \
(!(sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) || \
(sbp->sb_shared_vn <= XFS_SB_MAX_SHARED_VN))));
if ((sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) &&
sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
return 0;
#endif
return 1;
}
return 0;
}
#endif /* __KERNEL__ */
/*
* Detect a mismatched features2 field. Older kernels read/wrote
@ -332,123 +337,127 @@ static inline int xfs_sb_has_mismatched_features2(xfs_sb_t *sbp)
static inline unsigned xfs_sb_version_tonew(unsigned v)
{
return ((((v) == XFS_SB_VERSION_1) ? \
0 : \
(((v) == XFS_SB_VERSION_2) ? \
XFS_SB_VERSION_ATTRBIT : \
(XFS_SB_VERSION_ATTRBIT | XFS_SB_VERSION_NLINKBIT))) | \
XFS_SB_VERSION_4);
if (v == XFS_SB_VERSION_1)
return XFS_SB_VERSION_4;
if (v == XFS_SB_VERSION_2)
return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT |
XFS_SB_VERSION_NLINKBIT;
}
static inline unsigned xfs_sb_version_toold(unsigned v)
{
return (((v) & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT)) ? \
0 : \
(((v) & XFS_SB_VERSION_NLINKBIT) ? \
XFS_SB_VERSION_3 : \
(((v) & XFS_SB_VERSION_ATTRBIT) ? \
XFS_SB_VERSION_2 : \
XFS_SB_VERSION_1)));
if (v & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT))
return 0;
if (v & XFS_SB_VERSION_NLINKBIT)
return XFS_SB_VERSION_3;
if (v & XFS_SB_VERSION_ATTRBIT)
return XFS_SB_VERSION_2;
return XFS_SB_VERSION_1;
}
static inline int xfs_sb_version_hasattr(xfs_sb_t *sbp)
{
return ((sbp)->sb_versionnum == XFS_SB_VERSION_2) || \
((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_ATTRBIT));
return sbp->sb_versionnum == XFS_SB_VERSION_2 ||
sbp->sb_versionnum == XFS_SB_VERSION_3 ||
(XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT));
}
static inline void xfs_sb_version_addattr(xfs_sb_t *sbp)
{
(sbp)->sb_versionnum = (((sbp)->sb_versionnum == XFS_SB_VERSION_1) ? \
XFS_SB_VERSION_2 : \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) ? \
((sbp)->sb_versionnum | XFS_SB_VERSION_ATTRBIT) : \
(XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT)));
if (sbp->sb_versionnum == XFS_SB_VERSION_1)
sbp->sb_versionnum = XFS_SB_VERSION_2;
else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
else
sbp->sb_versionnum = XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
}
static inline int xfs_sb_version_hasnlink(xfs_sb_t *sbp)
{
return ((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \
((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_NLINKBIT));
return sbp->sb_versionnum == XFS_SB_VERSION_3 ||
(XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT));
}
static inline void xfs_sb_version_addnlink(xfs_sb_t *sbp)
{
(sbp)->sb_versionnum = ((sbp)->sb_versionnum <= XFS_SB_VERSION_2 ? \
XFS_SB_VERSION_3 : \
((sbp)->sb_versionnum | XFS_SB_VERSION_NLINKBIT));
if (sbp->sb_versionnum <= XFS_SB_VERSION_2)
sbp->sb_versionnum = XFS_SB_VERSION_3;
else
sbp->sb_versionnum |= XFS_SB_VERSION_NLINKBIT;
}
static inline int xfs_sb_version_hasquota(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_QUOTABIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT);
}
static inline void xfs_sb_version_addquota(xfs_sb_t *sbp)
{
(sbp)->sb_versionnum = \
(XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 ? \
((sbp)->sb_versionnum | XFS_SB_VERSION_QUOTABIT) : \
(xfs_sb_version_tonew((sbp)->sb_versionnum) | \
XFS_SB_VERSION_QUOTABIT));
if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT;
else
sbp->sb_versionnum = xfs_sb_version_tonew(sbp->sb_versionnum) |
XFS_SB_VERSION_QUOTABIT;
}
static inline int xfs_sb_version_hasalign(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_ALIGNBIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT);
}
static inline int xfs_sb_version_hasdalign(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_DALIGNBIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT);
}
static inline int xfs_sb_version_hasshared(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT);
}
static inline int xfs_sb_version_hasdirv2(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
}
static inline int xfs_sb_version_haslogv2(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_LOGV2BIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT);
}
static inline int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT);
}
static inline int xfs_sb_version_hassector(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
}
static inline int xfs_sb_version_hasasciici(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT);
}
static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
((sbp)->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT);
}
/*
@ -463,22 +472,20 @@ static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp)
{
return (xfs_sb_version_hasmorebits(sbp) && \
((sbp)->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT));
return xfs_sb_version_hasmorebits(sbp) &&
(sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT);
}
static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp)
{
return (xfs_sb_version_hasmorebits(sbp)) && \
((sbp)->sb_features2 & XFS_SB_VERSION2_ATTR2BIT);
return xfs_sb_version_hasmorebits(sbp) &&
(sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT);
}
static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp)
{
((sbp)->sb_versionnum = \
((sbp)->sb_versionnum | XFS_SB_VERSION_MOREBITSBIT), \
((sbp)->sb_features2 = \
((sbp)->sb_features2 | XFS_SB_VERSION2_ATTR2BIT)));
sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT;
}
static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp)

View File

@ -290,7 +290,7 @@ xfs_trans_dup(
ASSERT(tp->t_ticket != NULL);
ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE);
ntp->t_ticket = tp->t_ticket;
ntp->t_ticket = xfs_log_ticket_get(tp->t_ticket);
ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used;
tp->t_blk_res = tp->t_blk_res_used;
ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
@ -1259,6 +1259,13 @@ xfs_trans_roll(
trans = *tpp;
/*
* transaction commit worked ok so we can drop the extra ticket
* reference that we gained in xfs_trans_dup()
*/
xfs_log_ticket_put(trans->t_ticket);
/*
* Reserve space in the log for th next transaction.
* This also pushes items in the "AIL", the list of logged items,
@ -1383,11 +1390,12 @@ xfs_trans_chunk_committed(
xfs_log_item_desc_t *lidp;
xfs_log_item_t *lip;
xfs_lsn_t item_lsn;
struct xfs_mount *mp;
int i;
lidp = licp->lic_descs;
for (i = 0; i < licp->lic_unused; i++, lidp++) {
struct xfs_ail *ailp;
if (xfs_lic_isfree(licp, i)) {
continue;
}
@ -1424,19 +1432,19 @@ xfs_trans_chunk_committed(
* This would cause the earlier transaction to fail
* the test below.
*/
mp = lip->li_mountp;
spin_lock(&mp->m_ail_lock);
ailp = lip->li_ailp;
spin_lock(&ailp->xa_lock);
if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) {
/*
* This will set the item's lsn to item_lsn
* and update the position of the item in
* the AIL.
*
* xfs_trans_update_ail() drops the AIL lock.
* xfs_trans_ail_update() drops the AIL lock.
*/
xfs_trans_update_ail(mp, lip, item_lsn);
xfs_trans_ail_update(ailp, lip, item_lsn);
} else {
spin_unlock(&mp->m_ail_lock);
spin_unlock(&ailp->xa_lock);
}
/*

View File

@ -18,6 +18,8 @@
#ifndef __XFS_TRANS_H__
#define __XFS_TRANS_H__
struct xfs_log_item;
/*
* This is the structure written in the log at the head of
* every transaction. It identifies the type and id of the
@ -98,76 +100,6 @@ typedef struct xfs_trans_header {
#define XFS_TRANS_TYPE_MAX 41
/* new transaction types need to be reflected in xfs_logprint(8) */
#ifdef __KERNEL__
struct xfs_buf;
struct xfs_buftarg;
struct xfs_efd_log_item;
struct xfs_efi_log_item;
struct xfs_inode;
struct xfs_item_ops;
struct xfs_log_iovec;
struct xfs_log_item;
struct xfs_log_item_desc;
struct xfs_mount;
struct xfs_trans;
struct xfs_dquot_acct;
typedef struct xfs_log_item {
struct list_head li_ail; /* AIL pointers */
xfs_lsn_t li_lsn; /* last on-disk lsn */
struct xfs_log_item_desc *li_desc; /* ptr to current desc*/
struct xfs_mount *li_mountp; /* ptr to fs mount */
uint li_type; /* item type */
uint li_flags; /* misc flags */
struct xfs_log_item *li_bio_list; /* buffer item list */
void (*li_cb)(struct xfs_buf *,
struct xfs_log_item *);
/* buffer item iodone */
/* callback func */
struct xfs_item_ops *li_ops; /* function list */
} xfs_log_item_t;
#define XFS_LI_IN_AIL 0x1
#define XFS_LI_ABORTED 0x2
typedef struct xfs_item_ops {
uint (*iop_size)(xfs_log_item_t *);
void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
void (*iop_pin)(xfs_log_item_t *);
void (*iop_unpin)(xfs_log_item_t *, int);
void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *);
uint (*iop_trylock)(xfs_log_item_t *);
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
void (*iop_push)(xfs_log_item_t *);
void (*iop_pushbuf)(xfs_log_item_t *);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
} xfs_item_ops_t;
#define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip)
#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp)
#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip)
#define IOP_UNPIN(ip, flags) (*(ip)->li_ops->iop_unpin)(ip, flags)
#define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp)
#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip)
#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)
#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
#define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip)
#define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip)
#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn)
/*
* Return values for the IOP_TRYLOCK() routines.
*/
#define XFS_ITEM_SUCCESS 0
#define XFS_ITEM_PINNED 1
#define XFS_ITEM_LOCKED 2
#define XFS_ITEM_FLUSHING 3
#define XFS_ITEM_PUSHBUF 4
#endif /* __KERNEL__ */
/*
* This structure is used to track log items associated with
* a transaction. It points to the log item and keeps some
@ -176,7 +108,7 @@ typedef struct xfs_item_ops {
* once we get to commit processing (see xfs_trans_commit()).
*/
typedef struct xfs_log_item_desc {
xfs_log_item_t *lid_item;
struct xfs_log_item *lid_item;
ushort lid_size;
unsigned char lid_flags;
unsigned char lid_index;
@ -276,94 +208,6 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
(xfs_caddr_t)(((xfs_log_item_chunk_t*)0)->lic_descs));
}
#ifdef __KERNEL__
/*
* This structure is used to maintain a list of block ranges that have been
* freed in the transaction. The ranges are listed in the perag[] busy list
* between when they're freed and the transaction is committed to disk.
*/
typedef struct xfs_log_busy_slot {
xfs_agnumber_t lbc_ag;
ushort lbc_idx; /* index in perag.busy[] */
} xfs_log_busy_slot_t;
#define XFS_LBC_NUM_SLOTS 31
typedef struct xfs_log_busy_chunk {
struct xfs_log_busy_chunk *lbc_next;
uint lbc_free; /* free slots bitmask */
ushort lbc_unused; /* first unused */
xfs_log_busy_slot_t lbc_busy[XFS_LBC_NUM_SLOTS];
} xfs_log_busy_chunk_t;
#define XFS_LBC_MAX_SLOT (XFS_LBC_NUM_SLOTS - 1)
#define XFS_LBC_FREEMASK ((1U << XFS_LBC_NUM_SLOTS) - 1)
#define XFS_LBC_INIT(cp) ((cp)->lbc_free = XFS_LBC_FREEMASK)
#define XFS_LBC_CLAIM(cp, slot) ((cp)->lbc_free &= ~(1 << (slot)))
#define XFS_LBC_SLOT(cp, slot) (&((cp)->lbc_busy[(slot)]))
#define XFS_LBC_VACANCY(cp) (((cp)->lbc_free) & XFS_LBC_FREEMASK)
#define XFS_LBC_ISFREE(cp, slot) ((cp)->lbc_free & (1 << (slot)))
/*
* This is the type of function which can be given to xfs_trans_callback()
* to be called upon the transaction's commit to disk.
*/
typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *);
/*
* This is the structure maintained for every active transaction.
*/
typedef struct xfs_trans {
unsigned int t_magic; /* magic number */
xfs_log_callback_t t_logcb; /* log callback struct */
unsigned int t_type; /* transaction type */
unsigned int t_log_res; /* amt of log space resvd */
unsigned int t_log_count; /* count for perm log res */
unsigned int t_blk_res; /* # of blocks resvd */
unsigned int t_blk_res_used; /* # of resvd blocks used */
unsigned int t_rtx_res; /* # of rt extents resvd */
unsigned int t_rtx_res_used; /* # of resvd rt extents used */
xfs_log_ticket_t t_ticket; /* log mgr ticket */
xfs_lsn_t t_lsn; /* log seq num of start of
* transaction. */
xfs_lsn_t t_commit_lsn; /* log seq num of end of
* 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 */
int64_t t_fdblocks_delta; /* superblock fdblocks chg */
int64_t t_res_fdblocks_delta; /* on-disk only chg */
int64_t t_frextents_delta;/* superblock freextents chg*/
int64_t t_res_frextents_delta; /* on-disk only chg */
#ifdef DEBUG
int64_t t_ag_freeblks_delta; /* debugging counter */
int64_t t_ag_flist_delta; /* debugging counter */
int64_t t_ag_btree_delta; /* debugging counter */
#endif
int64_t t_dblocks_delta;/* superblock dblocks change */
int64_t t_agcount_delta;/* superblock agcount change */
int64_t t_imaxpct_delta;/* superblock imaxpct change */
int64_t t_rextsize_delta;/* superblock rextsize chg */
int64_t t_rbmblocks_delta;/* superblock rbmblocks chg */
int64_t t_rblocks_delta;/* superblock rblocks change */
int64_t t_rextents_delta;/* superblocks rextents chg */
int64_t t_rextslog_delta;/* superblocks rextslog chg */
unsigned int t_items_free; /* log item descs free */
xfs_log_item_chunk_t t_items; /* first log item desc chunk */
xfs_trans_header_t t_header; /* header for in-log trans */
unsigned int t_busy_free; /* busy descs free */
xfs_log_busy_chunk_t t_busy; /* busy/async free blocks */
unsigned long t_pflags; /* saved process flags state */
} xfs_trans_t;
#endif /* __KERNEL__ */
#define XFS_TRANS_MAGIC 0x5452414E /* 'TRAN' */
/*
* Values for t_flags.
@ -906,6 +750,157 @@ typedef struct xfs_trans {
#define XFS_DQUOT_REF 1
#ifdef __KERNEL__
struct xfs_buf;
struct xfs_buftarg;
struct xfs_efd_log_item;
struct xfs_efi_log_item;
struct xfs_inode;
struct xfs_item_ops;
struct xfs_log_iovec;
struct xfs_log_item_desc;
struct xfs_mount;
struct xfs_trans;
struct xfs_dquot_acct;
typedef struct xfs_log_item {
struct list_head li_ail; /* AIL pointers */
xfs_lsn_t li_lsn; /* last on-disk lsn */
struct xfs_log_item_desc *li_desc; /* ptr to current desc*/
struct xfs_mount *li_mountp; /* ptr to fs mount */
struct xfs_ail *li_ailp; /* ptr to AIL */
uint li_type; /* item type */
uint li_flags; /* misc flags */
struct xfs_log_item *li_bio_list; /* buffer item list */
void (*li_cb)(struct xfs_buf *,
struct xfs_log_item *);
/* buffer item iodone */
/* callback func */
struct xfs_item_ops *li_ops; /* function list */
} xfs_log_item_t;
#define XFS_LI_IN_AIL 0x1
#define XFS_LI_ABORTED 0x2
typedef struct xfs_item_ops {
uint (*iop_size)(xfs_log_item_t *);
void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
void (*iop_pin)(xfs_log_item_t *);
void (*iop_unpin)(xfs_log_item_t *, int);
void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *);
uint (*iop_trylock)(xfs_log_item_t *);
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
void (*iop_push)(xfs_log_item_t *);
void (*iop_pushbuf)(xfs_log_item_t *);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
} xfs_item_ops_t;
#define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip)
#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp)
#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip)
#define IOP_UNPIN(ip, flags) (*(ip)->li_ops->iop_unpin)(ip, flags)
#define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp)
#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip)
#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)
#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
#define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip)
#define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip)
#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn)
/*
* Return values for the IOP_TRYLOCK() routines.
*/
#define XFS_ITEM_SUCCESS 0
#define XFS_ITEM_PINNED 1
#define XFS_ITEM_LOCKED 2
#define XFS_ITEM_FLUSHING 3
#define XFS_ITEM_PUSHBUF 4
/*
* This structure is used to maintain a list of block ranges that have been
* freed in the transaction. The ranges are listed in the perag[] busy list
* between when they're freed and the transaction is committed to disk.
*/
typedef struct xfs_log_busy_slot {
xfs_agnumber_t lbc_ag;
ushort lbc_idx; /* index in perag.busy[] */
} xfs_log_busy_slot_t;
#define XFS_LBC_NUM_SLOTS 31
typedef struct xfs_log_busy_chunk {
struct xfs_log_busy_chunk *lbc_next;
uint lbc_free; /* free slots bitmask */
ushort lbc_unused; /* first unused */
xfs_log_busy_slot_t lbc_busy[XFS_LBC_NUM_SLOTS];
} xfs_log_busy_chunk_t;
#define XFS_LBC_MAX_SLOT (XFS_LBC_NUM_SLOTS - 1)
#define XFS_LBC_FREEMASK ((1U << XFS_LBC_NUM_SLOTS) - 1)
#define XFS_LBC_INIT(cp) ((cp)->lbc_free = XFS_LBC_FREEMASK)
#define XFS_LBC_CLAIM(cp, slot) ((cp)->lbc_free &= ~(1 << (slot)))
#define XFS_LBC_SLOT(cp, slot) (&((cp)->lbc_busy[(slot)]))
#define XFS_LBC_VACANCY(cp) (((cp)->lbc_free) & XFS_LBC_FREEMASK)
#define XFS_LBC_ISFREE(cp, slot) ((cp)->lbc_free & (1 << (slot)))
/*
* This is the type of function which can be given to xfs_trans_callback()
* to be called upon the transaction's commit to disk.
*/
typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *);
/*
* This is the structure maintained for every active transaction.
*/
typedef struct xfs_trans {
unsigned int t_magic; /* magic number */
xfs_log_callback_t t_logcb; /* log callback struct */
unsigned int t_type; /* transaction type */
unsigned int t_log_res; /* amt of log space resvd */
unsigned int t_log_count; /* count for perm log res */
unsigned int t_blk_res; /* # of blocks resvd */
unsigned int t_blk_res_used; /* # of resvd blocks used */
unsigned int t_rtx_res; /* # of rt extents resvd */
unsigned int t_rtx_res_used; /* # of resvd rt extents used */
xfs_log_ticket_t t_ticket; /* log mgr ticket */
xfs_lsn_t t_lsn; /* log seq num of start of
* transaction. */
xfs_lsn_t t_commit_lsn; /* log seq num of end of
* 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 */
int64_t t_fdblocks_delta; /* superblock fdblocks chg */
int64_t t_res_fdblocks_delta; /* on-disk only chg */
int64_t t_frextents_delta;/* superblock freextents chg*/
int64_t t_res_frextents_delta; /* on-disk only chg */
#ifdef DEBUG
int64_t t_ag_freeblks_delta; /* debugging counter */
int64_t t_ag_flist_delta; /* debugging counter */
int64_t t_ag_btree_delta; /* debugging counter */
#endif
int64_t t_dblocks_delta;/* superblock dblocks change */
int64_t t_agcount_delta;/* superblock agcount change */
int64_t t_imaxpct_delta;/* superblock imaxpct change */
int64_t t_rextsize_delta;/* superblock rextsize chg */
int64_t t_rbmblocks_delta;/* superblock rbmblocks chg */
int64_t t_rblocks_delta;/* superblock rblocks change */
int64_t t_rextents_delta;/* superblocks rextents chg */
int64_t t_rextslog_delta;/* superblocks rextslog chg */
unsigned int t_items_free; /* log item descs free */
xfs_log_item_chunk_t t_items; /* first log item desc chunk */
xfs_trans_header_t t_header; /* header for in-log trans */
unsigned int t_busy_free; /* busy descs free */
xfs_log_busy_chunk_t t_busy; /* busy/async free blocks */
unsigned long t_pflags; /* saved process flags state */
} xfs_trans_t;
/*
* XFS transaction mechanism exported interfaces that are
* actually macros.
@ -928,7 +923,6 @@ typedef struct xfs_trans {
/*
* XFS transaction mechanism exported interfaces.
*/
void xfs_trans_init(struct xfs_mount *);
xfs_trans_t *xfs_trans_alloc(struct xfs_mount *, uint);
xfs_trans_t *_xfs_trans_alloc(struct xfs_mount *, uint);
xfs_trans_t *xfs_trans_dup(xfs_trans_t *);
@ -975,13 +969,8 @@ int _xfs_trans_commit(xfs_trans_t *,
int *);
#define xfs_trans_commit(tp, flags) _xfs_trans_commit(tp, flags, NULL)
void xfs_trans_cancel(xfs_trans_t *, int);
int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *);
int xfs_trans_ail_init(struct xfs_mount *);
void xfs_trans_ail_destroy(struct xfs_mount *);
void xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t);
xfs_lsn_t xfs_trans_tail_ail(struct xfs_mount *);
void xfs_trans_unlocked_item(struct xfs_mount *,
xfs_log_item_t *);
xfs_log_busy_slot_t *xfs_trans_add_busy(xfs_trans_t *tp,
xfs_agnumber_t ag,
xfs_extlen_t idx);
@ -990,4 +979,7 @@ extern kmem_zone_t *xfs_trans_zone;
#endif /* __KERNEL__ */
void xfs_trans_init(struct xfs_mount *);
int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *);
#endif /* __XFS_TRANS_H__ */

Some files were not shown because too many files have changed in this diff Show More