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

* 'for-linus' of git://oss.sgi.com:8090/xfs/xfs-pull: (64 commits)
  [XFS] Remove vn_revalidate calls in xfs.
  [XFS] Now that xfs_setattr is only used for attributes set from ->setattr
  [XFS] xfs_setattr currently doesn't just handle the attributes set through
  [XFS] fix use after free with external logs or real-time devices
  [XFS] A bug was found in xfs_bmap_add_extent_unwritten_real(). In a
  [XFS] fix compilation without CONFIG_PROC_FS
  [XFS] s/XFS_PURGE_INODE/IRELE/g s/VN_HOLD(XFS_ITOV())/IHOLD()/
  [XFS] fix mount option parsing in remount
  [XFS] Disable queue flag test in barrier check.
  [XFS] streamline init/exit path
  [XFS] Fix up problem when CONFIG_XFS_POSIX_ACL is not set and yet we still
  [XFS] Don't assert if trying to mount with blocksize > pagesize
  [XFS] Don't update mtime on rename source
  [XFS] Allow xfs_bmbt_split() to fallback to the lowspace allocator
  [XFS] Restore the lowspace extent allocator algorithm
  [XFS] use minleft when allocating in xfs_bmbt_split()
  [XFS] attrmulti cleanup
  [XFS] Check for invalid flags in xfs_attrlist_by_handle.
  [XFS] Fix CI lookup in leaf-form directories
  [XFS] Use the generic xattr methods.
  ...
This commit is contained in:
Linus Torvalds 2008-08-01 12:39:09 -07:00
commit b8a327be3f
83 changed files with 3113 additions and 3106 deletions

View File

@ -1220,6 +1220,107 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
return new; return new;
} }
/**
* d_add_ci - lookup or allocate new dentry with case-exact name
* @inode: the inode case-insensitive lookup has found
* @dentry: the negative dentry that was passed to the parent's lookup func
* @name: the case-exact name to be associated with the returned dentry
*
* This is to avoid filling the dcache with case-insensitive names to the
* same inode, only the actual correct case is stored in the dcache for
* case-insensitive filesystems.
*
* For a case-insensitive lookup match and if the the case-exact dentry
* already exists in in the dcache, use it and return it.
*
* If no entry exists with the exact case name, allocate new dentry with
* the exact case, and return the spliced entry.
*/
struct dentry *d_add_ci(struct inode *inode, struct dentry *dentry,
struct qstr *name)
{
int error;
struct dentry *found;
struct dentry *new;
/* Does a dentry matching the name exist already? */
found = d_hash_and_lookup(dentry->d_parent, name);
/* If not, create it now and return */
if (!found) {
new = d_alloc(dentry->d_parent, name);
if (!new) {
error = -ENOMEM;
goto err_out;
}
found = d_splice_alias(inode, new);
if (found) {
dput(new);
return found;
}
return new;
}
/* Matching dentry exists, check if it is negative. */
if (found->d_inode) {
if (unlikely(found->d_inode != inode)) {
/* This can't happen because bad inodes are unhashed. */
BUG_ON(!is_bad_inode(inode));
BUG_ON(!is_bad_inode(found->d_inode));
}
/*
* Already have the inode and the dentry attached, decrement
* the reference count to balance the iget() done
* earlier on. We found the dentry using d_lookup() so it
* cannot be disconnected and thus we do not need to worry
* about any NFS/disconnectedness issues here.
*/
iput(inode);
return found;
}
/*
* Negative dentry: instantiate it unless the inode is a directory and
* has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED),
* in which case d_move() that in place of the found dentry.
*/
if (!S_ISDIR(inode->i_mode)) {
/* Not a directory; everything is easy. */
d_instantiate(found, inode);
return found;
}
spin_lock(&dcache_lock);
if (list_empty(&inode->i_dentry)) {
/*
* Directory without a 'disconnected' dentry; we need to do
* d_instantiate() by hand because it takes dcache_lock which
* we already hold.
*/
list_add(&found->d_alias, &inode->i_dentry);
found->d_inode = inode;
spin_unlock(&dcache_lock);
security_d_instantiate(found, inode);
return found;
}
/*
* Directory with a 'disconnected' dentry; get a reference to the
* 'disconnected' dentry.
*/
new = list_entry(inode->i_dentry.next, struct dentry, d_alias);
dget_locked(new);
spin_unlock(&dcache_lock);
/* Do security vodoo. */
security_d_instantiate(found, inode);
/* Move new in place of found. */
d_move(new, found);
/* Balance the iget() we did above. */
iput(inode);
/* Throw away found. */
dput(found);
/* Use new as the actual dentry. */
return new;
err_out:
iput(inode);
return ERR_PTR(error);
}
/** /**
* d_lookup - search for a dentry * d_lookup - search for a dentry
@ -2254,6 +2355,7 @@ EXPORT_SYMBOL(d_path);
EXPORT_SYMBOL(d_prune_aliases); EXPORT_SYMBOL(d_prune_aliases);
EXPORT_SYMBOL(d_rehash); EXPORT_SYMBOL(d_rehash);
EXPORT_SYMBOL(d_splice_alias); EXPORT_SYMBOL(d_splice_alias);
EXPORT_SYMBOL(d_add_ci);
EXPORT_SYMBOL(d_validate); EXPORT_SYMBOL(d_validate);
EXPORT_SYMBOL(dget_locked); EXPORT_SYMBOL(dget_locked);
EXPORT_SYMBOL(dput); EXPORT_SYMBOL(dput);

View File

@ -106,7 +106,8 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \
xfs_iops.o \ xfs_iops.o \
xfs_lrw.o \ xfs_lrw.o \
xfs_super.o \ xfs_super.o \
xfs_vnode.o) xfs_vnode.o \
xfs_xattr.o)
# Objects in support/ # Objects in support/
xfs-y += $(addprefix support/, \ xfs-y += $(addprefix support/, \

View File

@ -90,7 +90,7 @@ kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize,
} }
void void
kmem_free(void *ptr, size_t size) kmem_free(const void *ptr)
{ {
if (!is_vmalloc_addr(ptr)) { if (!is_vmalloc_addr(ptr)) {
kfree(ptr); kfree(ptr);
@ -100,7 +100,7 @@ kmem_free(void *ptr, size_t size)
} }
void * void *
kmem_realloc(void *ptr, size_t newsize, size_t oldsize, kmem_realloc(const void *ptr, size_t newsize, size_t oldsize,
unsigned int __nocast flags) unsigned int __nocast flags)
{ {
void *new; void *new;
@ -110,7 +110,7 @@ kmem_realloc(void *ptr, size_t newsize, size_t oldsize,
if (new) if (new)
memcpy(new, ptr, memcpy(new, ptr,
((oldsize < newsize) ? oldsize : newsize)); ((oldsize < newsize) ? oldsize : newsize));
kmem_free(ptr, oldsize); kmem_free(ptr);
} }
return new; return new;
} }

View File

@ -57,8 +57,8 @@ kmem_flags_convert(unsigned int __nocast flags)
extern void *kmem_alloc(size_t, unsigned int __nocast); extern void *kmem_alloc(size_t, unsigned int __nocast);
extern void *kmem_zalloc(size_t, unsigned int __nocast); extern void *kmem_zalloc(size_t, unsigned int __nocast);
extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast); extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast);
extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast); extern void *kmem_realloc(const void *, size_t, size_t, unsigned int __nocast);
extern void kmem_free(void *, size_t); extern void kmem_free(const void *);
/* /*
* Zone interfaces * Zone interfaces

View File

@ -409,7 +409,6 @@ xfs_start_buffer_writeback(
STATIC void STATIC void
xfs_start_page_writeback( xfs_start_page_writeback(
struct page *page, struct page *page,
struct writeback_control *wbc,
int clear_dirty, int clear_dirty,
int buffers) int buffers)
{ {
@ -858,7 +857,7 @@ xfs_convert_page(
done = 1; done = 1;
} }
} }
xfs_start_page_writeback(page, wbc, !page_dirty, count); xfs_start_page_writeback(page, !page_dirty, count);
} }
return done; return done;
@ -1130,7 +1129,7 @@ xfs_page_state_convert(
SetPageUptodate(page); SetPageUptodate(page);
if (startio) if (startio)
xfs_start_page_writeback(page, wbc, 1, count); xfs_start_page_writeback(page, 1, count);
if (ioend && iomap_valid) { if (ioend && iomap_valid) {
offset = (iomap.iomap_offset + iomap.iomap_bsize - 1) >> offset = (iomap.iomap_offset + iomap.iomap_bsize - 1) >>

View File

@ -310,8 +310,7 @@ _xfs_buf_free_pages(
xfs_buf_t *bp) xfs_buf_t *bp)
{ {
if (bp->b_pages != bp->b_page_array) { if (bp->b_pages != bp->b_page_array) {
kmem_free(bp->b_pages, kmem_free(bp->b_pages);
bp->b_page_count * sizeof(struct page *));
} }
} }
@ -1398,7 +1397,7 @@ STATIC void
xfs_free_bufhash( xfs_free_bufhash(
xfs_buftarg_t *btp) xfs_buftarg_t *btp)
{ {
kmem_free(btp->bt_hash, (1<<btp->bt_hashshift) * sizeof(xfs_bufhash_t)); kmem_free(btp->bt_hash);
btp->bt_hash = NULL; btp->bt_hash = NULL;
} }
@ -1428,13 +1427,10 @@ xfs_unregister_buftarg(
void void
xfs_free_buftarg( xfs_free_buftarg(
xfs_buftarg_t *btp, xfs_buftarg_t *btp)
int external)
{ {
xfs_flush_buftarg(btp, 1); xfs_flush_buftarg(btp, 1);
xfs_blkdev_issue_flush(btp); xfs_blkdev_issue_flush(btp);
if (external)
xfs_blkdev_put(btp->bt_bdev);
xfs_free_bufhash(btp); xfs_free_bufhash(btp);
iput(btp->bt_mapping->host); iput(btp->bt_mapping->host);
@ -1444,7 +1440,7 @@ xfs_free_buftarg(
xfs_unregister_buftarg(btp); xfs_unregister_buftarg(btp);
kthread_stop(btp->bt_task); kthread_stop(btp->bt_task);
kmem_free(btp, sizeof(*btp)); kmem_free(btp);
} }
STATIC int STATIC int
@ -1575,7 +1571,7 @@ xfs_alloc_buftarg(
return btp; return btp;
error: error:
kmem_free(btp, sizeof(*btp)); kmem_free(btp);
return NULL; return NULL;
} }

View File

@ -429,7 +429,7 @@ static inline void xfs_bdwrite(void *mp, xfs_buf_t *bp)
* Handling of buftargs. * Handling of buftargs.
*/ */
extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int); extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int);
extern void xfs_free_buftarg(xfs_buftarg_t *, int); extern void xfs_free_buftarg(xfs_buftarg_t *);
extern void xfs_wait_buftarg(xfs_buftarg_t *); extern void xfs_wait_buftarg(xfs_buftarg_t *);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
extern int xfs_flush_buftarg(xfs_buftarg_t *, int); extern int xfs_flush_buftarg(xfs_buftarg_t *, int);

View File

@ -215,7 +215,7 @@ xfs_fs_get_parent(
struct xfs_inode *cip; struct xfs_inode *cip;
struct dentry *parent; struct dentry *parent;
error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip); error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL);
if (unlikely(error)) if (unlikely(error))
return ERR_PTR(-error); return ERR_PTR(-error);

View File

@ -48,6 +48,8 @@
#include "xfs_dfrag.h" #include "xfs_dfrag.h"
#include "xfs_fsops.h" #include "xfs_fsops.h"
#include "xfs_vnodeops.h" #include "xfs_vnodeops.h"
#include "xfs_quota.h"
#include "xfs_inode_item.h"
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/dcache.h> #include <linux/dcache.h>
@ -468,6 +470,12 @@ xfs_attrlist_by_handle(
if (al_hreq.buflen > XATTR_LIST_MAX) if (al_hreq.buflen > XATTR_LIST_MAX)
return -XFS_ERROR(EINVAL); 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(mp, parinode, &al_hreq.hreq, &inode); error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode);
if (error) if (error)
goto out; goto out;
@ -587,7 +595,7 @@ xfs_attrmulti_by_handle(
goto out; goto out;
error = E2BIG; error = E2BIG;
size = am_hreq.opcount * sizeof(attr_multiop_t); size = am_hreq.opcount * sizeof(xfs_attr_multiop_t);
if (!size || size > 16 * PAGE_SIZE) if (!size || size > 16 * PAGE_SIZE)
goto out_vn_rele; goto out_vn_rele;
@ -680,9 +688,9 @@ xfs_ioc_space(
return -XFS_ERROR(EFAULT); return -XFS_ERROR(EFAULT);
if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
attr_flags |= ATTR_NONBLOCK; attr_flags |= XFS_ATTR_NONBLOCK;
if (ioflags & IO_INVIS) if (ioflags & IO_INVIS)
attr_flags |= ATTR_DMI; attr_flags |= XFS_ATTR_DMI;
error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos, error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos,
NULL, attr_flags); NULL, attr_flags);
@ -873,6 +881,322 @@ xfs_ioc_fsgetxattr(
return 0; return 0;
} }
STATIC void
xfs_set_diflags(
struct xfs_inode *ip,
unsigned int xflags)
{
unsigned int di_flags;
/* can't set PREALLOC this way, just preserve it */
di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
if (xflags & XFS_XFLAG_IMMUTABLE)
di_flags |= XFS_DIFLAG_IMMUTABLE;
if (xflags & XFS_XFLAG_APPEND)
di_flags |= XFS_DIFLAG_APPEND;
if (xflags & XFS_XFLAG_SYNC)
di_flags |= XFS_DIFLAG_SYNC;
if (xflags & XFS_XFLAG_NOATIME)
di_flags |= XFS_DIFLAG_NOATIME;
if (xflags & XFS_XFLAG_NODUMP)
di_flags |= XFS_DIFLAG_NODUMP;
if (xflags & XFS_XFLAG_PROJINHERIT)
di_flags |= XFS_DIFLAG_PROJINHERIT;
if (xflags & XFS_XFLAG_NODEFRAG)
di_flags |= XFS_DIFLAG_NODEFRAG;
if (xflags & XFS_XFLAG_FILESTREAM)
di_flags |= XFS_DIFLAG_FILESTREAM;
if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
if (xflags & XFS_XFLAG_RTINHERIT)
di_flags |= XFS_DIFLAG_RTINHERIT;
if (xflags & XFS_XFLAG_NOSYMLINKS)
di_flags |= XFS_DIFLAG_NOSYMLINKS;
if (xflags & XFS_XFLAG_EXTSZINHERIT)
di_flags |= XFS_DIFLAG_EXTSZINHERIT;
} else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
if (xflags & XFS_XFLAG_REALTIME)
di_flags |= XFS_DIFLAG_REALTIME;
if (xflags & XFS_XFLAG_EXTSIZE)
di_flags |= XFS_DIFLAG_EXTSIZE;
}
ip->i_d.di_flags = di_flags;
}
STATIC void
xfs_diflags_to_linux(
struct xfs_inode *ip)
{
struct inode *inode = XFS_ITOV(ip);
unsigned int xflags = xfs_ip2xflags(ip);
if (xflags & XFS_XFLAG_IMMUTABLE)
inode->i_flags |= S_IMMUTABLE;
else
inode->i_flags &= ~S_IMMUTABLE;
if (xflags & XFS_XFLAG_APPEND)
inode->i_flags |= S_APPEND;
else
inode->i_flags &= ~S_APPEND;
if (xflags & XFS_XFLAG_SYNC)
inode->i_flags |= S_SYNC;
else
inode->i_flags &= ~S_SYNC;
if (xflags & XFS_XFLAG_NOATIME)
inode->i_flags |= S_NOATIME;
else
inode->i_flags &= ~S_NOATIME;
}
#define FSX_PROJID 1
#define FSX_EXTSIZE 2
#define FSX_XFLAGS 4
#define FSX_NONBLOCK 8
STATIC int
xfs_ioctl_setattr(
xfs_inode_t *ip,
struct fsxattr *fa,
int mask)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_trans *tp;
unsigned int lock_flags = 0;
struct xfs_dquot *udqp = NULL, *gdqp = NULL;
struct xfs_dquot *olddquot = NULL;
int code;
xfs_itrace_entry(ip);
if (mp->m_flags & XFS_MOUNT_RDONLY)
return XFS_ERROR(EROFS);
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
/*
* If disk quotas is on, we make sure that the dquots do exist on disk,
* before we start any other transactions. Trying to do this later
* is messy. We don't care to take a readlock to look at the ids
* in inode here, because we can't hold it across the trans_reserve.
* If the IDs do change before we take the ilock, we're covered
* because the i_*dquot fields will get updated anyway.
*/
if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
code = XFS_QM_DQVOPALLOC(mp, ip, ip->i_d.di_uid,
ip->i_d.di_gid, fa->fsx_projid,
XFS_QMOPT_PQUOTA, &udqp, &gdqp);
if (code)
return code;
}
/*
* For the other attributes, we acquire the inode lock and
* first do an error checking pass.
*/
tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
if (code)
goto error_return;
lock_flags = XFS_ILOCK_EXCL;
xfs_ilock(ip, lock_flags);
/*
* CAP_FOWNER overrides the following restrictions:
*
* The user ID of the calling process must be equal
* to the file owner ID, except in cases where the
* CAP_FSETID capability is applicable.
*/
if (current->fsuid != ip->i_d.di_uid && !capable(CAP_FOWNER)) {
code = XFS_ERROR(EPERM);
goto error_return;
}
/*
* Do a quota reservation only if projid is actually going to change.
*/
if (mask & FSX_PROJID) {
if (XFS_IS_PQUOTA_ON(mp) &&
ip->i_d.di_projid != fa->fsx_projid) {
ASSERT(tp);
code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
capable(CAP_FOWNER) ?
XFS_QMOPT_FORCE_RES : 0);
if (code) /* out of quota */
goto error_return;
}
}
if (mask & FSX_EXTSIZE) {
/*
* Can't change extent size if any extents are allocated.
*/
if (ip->i_d.di_nextents &&
((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
fa->fsx_extsize)) {
code = XFS_ERROR(EINVAL); /* EFBIG? */
goto error_return;
}
/*
* Extent size must be a multiple of the appropriate block
* size, if set at all.
*/
if (fa->fsx_extsize != 0) {
xfs_extlen_t size;
if (XFS_IS_REALTIME_INODE(ip) ||
((mask & FSX_XFLAGS) &&
(fa->fsx_xflags & XFS_XFLAG_REALTIME))) {
size = mp->m_sb.sb_rextsize <<
mp->m_sb.sb_blocklog;
} else {
size = mp->m_sb.sb_blocksize;
}
if (fa->fsx_extsize % size) {
code = XFS_ERROR(EINVAL);
goto error_return;
}
}
}
if (mask & FSX_XFLAGS) {
/*
* Can't change realtime flag if any extents are allocated.
*/
if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
(XFS_IS_REALTIME_INODE(ip)) !=
(fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
code = XFS_ERROR(EINVAL); /* EFBIG? */
goto error_return;
}
/*
* If realtime flag is set then must have realtime data.
*/
if ((fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
if ((mp->m_sb.sb_rblocks == 0) ||
(mp->m_sb.sb_rextsize == 0) ||
(ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) {
code = XFS_ERROR(EINVAL);
goto error_return;
}
}
/*
* Can't modify an immutable/append-only file unless
* we have appropriate permission.
*/
if ((ip->i_d.di_flags &
(XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) ||
(fa->fsx_xflags &
(XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) &&
!capable(CAP_LINUX_IMMUTABLE)) {
code = XFS_ERROR(EPERM);
goto error_return;
}
}
xfs_trans_ijoin(tp, ip, lock_flags);
xfs_trans_ihold(tp, ip);
/*
* 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) {
/*
* CAP_FSETID overrides the following restrictions:
*
* The set-user-ID and set-group-ID bits of a file will be
* cleared upon successful return from chown()
*/
if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
!capable(CAP_FSETID))
ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
/*
* Change the ownerships and register quota modifications
* in the transaction.
*/
if (ip->i_d.di_projid != fa->fsx_projid) {
if (XFS_IS_PQUOTA_ON(mp)) {
olddquot = XFS_QM_DQVOPCHOWN(mp, tp, ip,
&ip->i_gdquot, gdqp);
}
ip->i_d.di_projid = fa->fsx_projid;
/*
* We may have to rev the inode as well as
* 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)
xfs_bump_ino_vers2(tp, ip);
}
}
if (mask & FSX_EXTSIZE)
ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog;
if (mask & FSX_XFLAGS) {
xfs_set_diflags(ip, fa->fsx_xflags);
xfs_diflags_to_linux(ip);
}
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
XFS_STATS_INC(xs_ig_attrchg);
/*
* If this is a synchronous mount, make sure that the
* transaction goes to disk before returning to the user.
* This is slightly sub-optimal in that truncates require
* two sync transactions instead of one for wsync filesystems.
* One for the truncate and one for the timestamps since we
* don't want to change the timestamps unless we're sure the
* truncate worked. Truncates are less than 1% of the laddis
* mix so this probably isn't worth the trouble to optimize.
*/
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(tp);
code = xfs_trans_commit(tp, 0);
xfs_iunlock(ip, lock_flags);
/*
* Release any dquot(s) the inode had kept before chown.
*/
XFS_QM_DQRELE(mp, olddquot);
XFS_QM_DQRELE(mp, udqp);
XFS_QM_DQRELE(mp, gdqp);
if (code)
return code;
if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE)) {
XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0,
(mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0);
}
return 0;
error_return:
XFS_QM_DQRELE(mp, udqp);
XFS_QM_DQRELE(mp, gdqp);
xfs_trans_cancel(tp, 0);
if (lock_flags)
xfs_iunlock(ip, lock_flags);
return code;
}
STATIC int STATIC int
xfs_ioc_fssetxattr( xfs_ioc_fssetxattr(
xfs_inode_t *ip, xfs_inode_t *ip,
@ -880,31 +1204,16 @@ xfs_ioc_fssetxattr(
void __user *arg) void __user *arg)
{ {
struct fsxattr fa; struct fsxattr fa;
struct bhv_vattr *vattr; unsigned int mask;
int error;
int attr_flags;
if (copy_from_user(&fa, arg, sizeof(fa))) if (copy_from_user(&fa, arg, sizeof(fa)))
return -EFAULT; return -EFAULT;
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID;
if (unlikely(!vattr))
return -ENOMEM;
attr_flags = 0;
if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
attr_flags |= ATTR_NONBLOCK; mask |= FSX_NONBLOCK;
vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; return -xfs_ioctl_setattr(ip, &fa, mask);
vattr->va_xflags = fa.fsx_xflags;
vattr->va_extsize = fa.fsx_extsize;
vattr->va_projid = fa.fsx_projid;
error = -xfs_setattr(ip, vattr, attr_flags, NULL);
if (!error)
vn_revalidate(XFS_ITOV(ip)); /* update flags */
kfree(vattr);
return 0;
} }
STATIC int STATIC int
@ -926,10 +1235,9 @@ xfs_ioc_setxflags(
struct file *filp, struct file *filp,
void __user *arg) void __user *arg)
{ {
struct bhv_vattr *vattr; struct fsxattr fa;
unsigned int flags; unsigned int flags;
int attr_flags; unsigned int mask;
int error;
if (copy_from_user(&flags, arg, sizeof(flags))) if (copy_from_user(&flags, arg, sizeof(flags)))
return -EFAULT; return -EFAULT;
@ -939,22 +1247,12 @@ xfs_ioc_setxflags(
FS_SYNC_FL)) FS_SYNC_FL))
return -EOPNOTSUPP; return -EOPNOTSUPP;
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); mask = FSX_XFLAGS;
if (unlikely(!vattr))
return -ENOMEM;
attr_flags = 0;
if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
attr_flags |= ATTR_NONBLOCK; mask |= FSX_NONBLOCK;
fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
vattr->va_mask = XFS_AT_XFLAGS; return -xfs_ioctl_setattr(ip, &fa, mask);
vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
error = -xfs_setattr(ip, vattr, attr_flags, NULL);
if (likely(!error))
vn_revalidate(XFS_ITOV(ip)); /* update flags */
kfree(vattr);
return error;
} }
STATIC int STATIC int

View File

@ -181,23 +181,6 @@ xfs_ichgtime_fast(
mark_inode_dirty_sync(inode); mark_inode_dirty_sync(inode);
} }
/*
* Pull the link count and size up from the xfs inode to the linux inode
*/
STATIC void
xfs_validate_fields(
struct inode *inode)
{
struct xfs_inode *ip = XFS_I(inode);
loff_t size;
/* we're under i_sem so i_size can't change under us */
size = XFS_ISIZE(ip);
if (i_size_read(inode) != size)
i_size_write(inode, size);
}
/* /*
* Hook in SELinux. This is not quite correct yet, what we really need * Hook in SELinux. This is not quite correct yet, what we really need
* here (as we do for default ACLs) is a mechanism by which creation of * here (as we do for default ACLs) is a mechanism by which creation of
@ -245,8 +228,7 @@ STATIC void
xfs_cleanup_inode( xfs_cleanup_inode(
struct inode *dir, struct inode *dir,
struct inode *inode, struct inode *inode,
struct dentry *dentry, struct dentry *dentry)
int mode)
{ {
struct xfs_name teardown; struct xfs_name teardown;
@ -257,10 +239,7 @@ xfs_cleanup_inode(
*/ */
xfs_dentry_to_name(&teardown, dentry); xfs_dentry_to_name(&teardown, dentry);
if (S_ISDIR(mode)) xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
xfs_rmdir(XFS_I(dir), &teardown, XFS_I(inode));
else
xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
iput(inode); iput(inode);
} }
@ -275,7 +254,7 @@ xfs_vn_mknod(
struct xfs_inode *ip = NULL; struct xfs_inode *ip = NULL;
xfs_acl_t *default_acl = NULL; xfs_acl_t *default_acl = NULL;
struct xfs_name name; struct xfs_name name;
attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS;
int error; int error;
/* /*
@ -335,14 +314,11 @@ xfs_vn_mknod(
} }
if (S_ISDIR(mode))
xfs_validate_fields(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
xfs_validate_fields(dir);
return -error; return -error;
out_cleanup_inode: out_cleanup_inode:
xfs_cleanup_inode(dir, inode, dentry, mode); xfs_cleanup_inode(dir, inode, dentry);
out_free_acl: out_free_acl:
if (default_acl) if (default_acl)
_ACL_FREE(default_acl); _ACL_FREE(default_acl);
@ -382,7 +358,7 @@ xfs_vn_lookup(
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
xfs_dentry_to_name(&name, dentry); xfs_dentry_to_name(&name, dentry);
error = xfs_lookup(XFS_I(dir), &name, &cip); error = xfs_lookup(XFS_I(dir), &name, &cip, NULL);
if (unlikely(error)) { if (unlikely(error)) {
if (unlikely(error != ENOENT)) if (unlikely(error != ENOENT))
return ERR_PTR(-error); return ERR_PTR(-error);
@ -393,6 +369,46 @@ xfs_vn_lookup(
return d_splice_alias(cip->i_vnode, dentry); return d_splice_alias(cip->i_vnode, dentry);
} }
STATIC struct dentry *
xfs_vn_ci_lookup(
struct inode *dir,
struct dentry *dentry,
struct nameidata *nd)
{
struct xfs_inode *ip;
struct xfs_name xname;
struct xfs_name ci_name;
struct qstr dname;
int error;
if (dentry->d_name.len >= MAXNAMELEN)
return ERR_PTR(-ENAMETOOLONG);
xfs_dentry_to_name(&xname, dentry);
error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name);
if (unlikely(error)) {
if (unlikely(error != ENOENT))
return ERR_PTR(-error);
/*
* call d_add(dentry, NULL) here when d_drop_negative_children
* is called in xfs_vn_mknod (ie. allow negative dentries
* with CI filesystems).
*/
return NULL;
}
/* if exact match, just splice and exit */
if (!ci_name.name)
return d_splice_alias(ip->i_vnode, dentry);
/* else case-insensitive match... */
dname.name = ci_name.name;
dname.len = ci_name.len;
dentry = d_add_ci(ip->i_vnode, dentry, &dname);
kmem_free(ci_name.name);
return dentry;
}
STATIC int STATIC int
xfs_vn_link( xfs_vn_link(
struct dentry *old_dentry, struct dentry *old_dentry,
@ -414,7 +430,6 @@ xfs_vn_link(
} }
xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED); xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED);
xfs_validate_fields(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
return 0; return 0;
} }
@ -424,19 +439,23 @@ xfs_vn_unlink(
struct inode *dir, struct inode *dir,
struct dentry *dentry) struct dentry *dentry)
{ {
struct inode *inode;
struct xfs_name name; struct xfs_name name;
int error; int error;
inode = dentry->d_inode;
xfs_dentry_to_name(&name, dentry); xfs_dentry_to_name(&name, dentry);
error = xfs_remove(XFS_I(dir), &name, XFS_I(inode)); error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode));
if (likely(!error)) { if (error)
xfs_validate_fields(dir); /* size needs update */ return error;
xfs_validate_fields(inode);
} /*
return -error; * With unlink, the VFS makes the dentry "negative": no inode,
* but still hashed. This is incompatible with case-insensitive
* mode, so invalidate (unhash) the dentry in CI-mode.
*/
if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb))
d_invalidate(dentry);
return 0;
} }
STATIC int STATIC int
@ -466,35 +485,14 @@ xfs_vn_symlink(
goto out_cleanup_inode; goto out_cleanup_inode;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
xfs_validate_fields(dir);
xfs_validate_fields(inode);
return 0; return 0;
out_cleanup_inode: out_cleanup_inode:
xfs_cleanup_inode(dir, inode, dentry, 0); xfs_cleanup_inode(dir, inode, dentry);
out: out:
return -error; return -error;
} }
STATIC int
xfs_vn_rmdir(
struct inode *dir,
struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct xfs_name name;
int error;
xfs_dentry_to_name(&name, dentry);
error = xfs_rmdir(XFS_I(dir), &name, XFS_I(inode));
if (likely(!error)) {
xfs_validate_fields(inode);
xfs_validate_fields(dir);
}
return -error;
}
STATIC int STATIC int
xfs_vn_rename( xfs_vn_rename(
struct inode *odir, struct inode *odir,
@ -505,22 +503,13 @@ xfs_vn_rename(
struct inode *new_inode = ndentry->d_inode; struct inode *new_inode = ndentry->d_inode;
struct xfs_name oname; struct xfs_name oname;
struct xfs_name nname; struct xfs_name nname;
int error;
xfs_dentry_to_name(&oname, odentry); xfs_dentry_to_name(&oname, odentry);
xfs_dentry_to_name(&nname, ndentry); xfs_dentry_to_name(&nname, ndentry);
error = xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), return -xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode),
XFS_I(ndir), &nname, new_inode ? XFS_I(ndir), &nname, new_inode ?
XFS_I(new_inode) : NULL); XFS_I(new_inode) : NULL);
if (likely(!error)) {
if (new_inode)
xfs_validate_fields(new_inode);
xfs_validate_fields(odir);
if (ndir != odir)
xfs_validate_fields(ndir);
}
return -error;
} }
/* /*
@ -659,57 +648,9 @@ xfs_vn_getattr(
STATIC int STATIC int
xfs_vn_setattr( xfs_vn_setattr(
struct dentry *dentry, struct dentry *dentry,
struct iattr *attr) struct iattr *iattr)
{ {
struct inode *inode = dentry->d_inode; return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0, NULL);
unsigned int ia_valid = attr->ia_valid;
bhv_vattr_t vattr = { 0 };
int flags = 0;
int error;
if (ia_valid & ATTR_UID) {
vattr.va_mask |= XFS_AT_UID;
vattr.va_uid = attr->ia_uid;
}
if (ia_valid & ATTR_GID) {
vattr.va_mask |= XFS_AT_GID;
vattr.va_gid = attr->ia_gid;
}
if (ia_valid & ATTR_SIZE) {
vattr.va_mask |= XFS_AT_SIZE;
vattr.va_size = attr->ia_size;
}
if (ia_valid & ATTR_ATIME) {
vattr.va_mask |= XFS_AT_ATIME;
vattr.va_atime = attr->ia_atime;
inode->i_atime = attr->ia_atime;
}
if (ia_valid & ATTR_MTIME) {
vattr.va_mask |= XFS_AT_MTIME;
vattr.va_mtime = attr->ia_mtime;
}
if (ia_valid & ATTR_CTIME) {
vattr.va_mask |= XFS_AT_CTIME;
vattr.va_ctime = attr->ia_ctime;
}
if (ia_valid & ATTR_MODE) {
vattr.va_mask |= XFS_AT_MODE;
vattr.va_mode = attr->ia_mode;
if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
inode->i_mode &= ~S_ISGID;
}
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET))
flags |= ATTR_UTIME;
#ifdef ATTR_NO_BLOCK
if ((ia_valid & ATTR_NO_BLOCK))
flags |= ATTR_NONBLOCK;
#endif
error = xfs_setattr(XFS_I(inode), &vattr, flags, NULL);
if (likely(!error))
vn_revalidate(vn_from_inode(inode));
return -error;
} }
/* /*
@ -727,109 +668,6 @@ xfs_vn_truncate(
WARN_ON(error); WARN_ON(error);
} }
STATIC int
xfs_vn_setxattr(
struct dentry *dentry,
const char *name,
const void *data,
size_t size,
int flags)
{
bhv_vnode_t *vp = vn_from_inode(dentry->d_inode);
char *attr = (char *)name;
attrnames_t *namesp;
int xflags = 0;
int error;
namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
if (!namesp)
return -EOPNOTSUPP;
attr += namesp->attr_namelen;
error = namesp->attr_capable(vp, NULL);
if (error)
return error;
/* Convert Linux syscall to XFS internal ATTR flags */
if (flags & XATTR_CREATE)
xflags |= ATTR_CREATE;
if (flags & XATTR_REPLACE)
xflags |= ATTR_REPLACE;
xflags |= namesp->attr_flag;
return namesp->attr_set(vp, attr, (void *)data, size, xflags);
}
STATIC ssize_t
xfs_vn_getxattr(
struct dentry *dentry,
const char *name,
void *data,
size_t size)
{
bhv_vnode_t *vp = vn_from_inode(dentry->d_inode);
char *attr = (char *)name;
attrnames_t *namesp;
int xflags = 0;
ssize_t error;
namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
if (!namesp)
return -EOPNOTSUPP;
attr += namesp->attr_namelen;
error = namesp->attr_capable(vp, NULL);
if (error)
return error;
/* Convert Linux syscall to XFS internal ATTR flags */
if (!size) {
xflags |= ATTR_KERNOVAL;
data = NULL;
}
xflags |= namesp->attr_flag;
return namesp->attr_get(vp, attr, (void *)data, size, xflags);
}
STATIC ssize_t
xfs_vn_listxattr(
struct dentry *dentry,
char *data,
size_t size)
{
bhv_vnode_t *vp = vn_from_inode(dentry->d_inode);
int error, xflags = ATTR_KERNAMELS;
ssize_t result;
if (!size)
xflags |= ATTR_KERNOVAL;
xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS;
error = attr_generic_list(vp, data, size, xflags, &result);
if (error < 0)
return error;
return result;
}
STATIC int
xfs_vn_removexattr(
struct dentry *dentry,
const char *name)
{
bhv_vnode_t *vp = vn_from_inode(dentry->d_inode);
char *attr = (char *)name;
attrnames_t *namesp;
int xflags = 0;
int error;
namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
if (!namesp)
return -EOPNOTSUPP;
attr += namesp->attr_namelen;
error = namesp->attr_capable(vp, NULL);
if (error)
return error;
xflags |= namesp->attr_flag;
return namesp->attr_remove(vp, attr, xflags);
}
STATIC long STATIC long
xfs_vn_fallocate( xfs_vn_fallocate(
struct inode *inode, struct inode *inode,
@ -853,18 +691,18 @@ xfs_vn_fallocate(
xfs_ilock(ip, XFS_IOLOCK_EXCL); xfs_ilock(ip, XFS_IOLOCK_EXCL);
error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf,
0, NULL, ATTR_NOLOCK); 0, NULL, XFS_ATTR_NOLOCK);
if (!error && !(mode & FALLOC_FL_KEEP_SIZE) && if (!error && !(mode & FALLOC_FL_KEEP_SIZE) &&
offset + len > i_size_read(inode)) offset + len > i_size_read(inode))
new_size = offset + len; new_size = offset + len;
/* Change file size if needed */ /* Change file size if needed */
if (new_size) { if (new_size) {
bhv_vattr_t va; struct iattr iattr;
va.va_mask = XFS_AT_SIZE; iattr.ia_valid = ATTR_SIZE;
va.va_size = new_size; iattr.ia_size = new_size;
error = xfs_setattr(ip, &va, ATTR_NOLOCK, NULL); error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK, NULL);
} }
xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(ip, XFS_IOLOCK_EXCL);
@ -877,10 +715,10 @@ const struct inode_operations xfs_inode_operations = {
.truncate = xfs_vn_truncate, .truncate = xfs_vn_truncate,
.getattr = xfs_vn_getattr, .getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr, .setattr = xfs_vn_setattr,
.setxattr = xfs_vn_setxattr, .setxattr = generic_setxattr,
.getxattr = xfs_vn_getxattr, .getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr, .listxattr = xfs_vn_listxattr,
.removexattr = xfs_vn_removexattr,
.fallocate = xfs_vn_fallocate, .fallocate = xfs_vn_fallocate,
}; };
@ -891,16 +729,47 @@ const struct inode_operations xfs_dir_inode_operations = {
.unlink = xfs_vn_unlink, .unlink = xfs_vn_unlink,
.symlink = xfs_vn_symlink, .symlink = xfs_vn_symlink,
.mkdir = xfs_vn_mkdir, .mkdir = xfs_vn_mkdir,
.rmdir = xfs_vn_rmdir, /*
* Yes, XFS uses the same method for rmdir and unlink.
*
* There are some subtile differences deeper in the code,
* but we use S_ISDIR to check for those.
*/
.rmdir = xfs_vn_unlink,
.mknod = xfs_vn_mknod, .mknod = xfs_vn_mknod,
.rename = xfs_vn_rename, .rename = xfs_vn_rename,
.permission = xfs_vn_permission, .permission = xfs_vn_permission,
.getattr = xfs_vn_getattr, .getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr, .setattr = xfs_vn_setattr,
.setxattr = xfs_vn_setxattr, .setxattr = generic_setxattr,
.getxattr = xfs_vn_getxattr, .getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
};
const struct inode_operations xfs_dir_ci_inode_operations = {
.create = xfs_vn_create,
.lookup = xfs_vn_ci_lookup,
.link = xfs_vn_link,
.unlink = xfs_vn_unlink,
.symlink = xfs_vn_symlink,
.mkdir = xfs_vn_mkdir,
/*
* Yes, XFS uses the same method for rmdir and unlink.
*
* There are some subtile differences deeper in the code,
* but we use S_ISDIR to check for those.
*/
.rmdir = xfs_vn_unlink,
.mknod = xfs_vn_mknod,
.rename = xfs_vn_rename,
.permission = xfs_vn_permission,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr, .listxattr = xfs_vn_listxattr,
.removexattr = xfs_vn_removexattr,
}; };
const struct inode_operations xfs_symlink_inode_operations = { const struct inode_operations xfs_symlink_inode_operations = {
@ -910,8 +779,8 @@ const struct inode_operations xfs_symlink_inode_operations = {
.permission = xfs_vn_permission, .permission = xfs_vn_permission,
.getattr = xfs_vn_getattr, .getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr, .setattr = xfs_vn_setattr,
.setxattr = xfs_vn_setxattr, .setxattr = generic_setxattr,
.getxattr = xfs_vn_getxattr, .getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr, .listxattr = xfs_vn_listxattr,
.removexattr = xfs_vn_removexattr,
}; };

View File

@ -20,12 +20,14 @@
extern const struct inode_operations xfs_inode_operations; extern const struct inode_operations xfs_inode_operations;
extern const struct inode_operations xfs_dir_inode_operations; extern const struct inode_operations xfs_dir_inode_operations;
extern const struct inode_operations xfs_dir_ci_inode_operations;
extern const struct inode_operations xfs_symlink_inode_operations; extern const struct inode_operations xfs_symlink_inode_operations;
extern const struct file_operations xfs_file_operations; extern const struct file_operations xfs_file_operations;
extern const struct file_operations xfs_dir_file_operations; extern const struct file_operations xfs_dir_file_operations;
extern const struct file_operations xfs_invis_file_operations; extern const struct file_operations xfs_invis_file_operations;
extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
struct xfs_inode; struct xfs_inode;
extern void xfs_ichgtime(struct xfs_inode *, int); extern void xfs_ichgtime(struct xfs_inode *, int);

View File

@ -76,6 +76,7 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/ctype.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/div64.h> #include <asm/div64.h>
@ -299,4 +300,11 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y)
return x; return x;
} }
/* ARM old ABI has some weird alignment/padding */
#if defined(__arm__) && !defined(__ARM_EABI__)
#define __arch_pack __attribute__((packed))
#else
#define __arch_pack
#endif
#endif /* __XFS_LINUX__ */ #endif /* __XFS_LINUX__ */

View File

@ -98,12 +98,21 @@ xfs_read_xfsstats(
return len; return len;
} }
void int
xfs_init_procfs(void) xfs_init_procfs(void)
{ {
if (!proc_mkdir("fs/xfs", NULL)) if (!proc_mkdir("fs/xfs", NULL))
return; goto out;
create_proc_read_entry("fs/xfs/stat", 0, NULL, xfs_read_xfsstats, NULL);
if (!create_proc_read_entry("fs/xfs/stat", 0, NULL,
xfs_read_xfsstats, NULL))
goto out_remove_entry;
return 0;
out_remove_entry:
remove_proc_entry("fs/xfs", NULL);
out:
return -ENOMEM;
} }
void void

View File

@ -134,7 +134,7 @@ DECLARE_PER_CPU(struct xfsstats, xfsstats);
#define XFS_STATS_DEC(v) (per_cpu(xfsstats, current_cpu()).v--) #define XFS_STATS_DEC(v) (per_cpu(xfsstats, current_cpu()).v--)
#define XFS_STATS_ADD(v, inc) (per_cpu(xfsstats, current_cpu()).v += (inc)) #define XFS_STATS_ADD(v, inc) (per_cpu(xfsstats, current_cpu()).v += (inc))
extern void xfs_init_procfs(void); extern int xfs_init_procfs(void);
extern void xfs_cleanup_procfs(void); extern void xfs_cleanup_procfs(void);
@ -144,8 +144,14 @@ extern void xfs_cleanup_procfs(void);
# define XFS_STATS_DEC(count) # define XFS_STATS_DEC(count)
# define XFS_STATS_ADD(count, inc) # define XFS_STATS_ADD(count, inc)
static inline void xfs_init_procfs(void) { }; static inline int xfs_init_procfs(void)
static inline void xfs_cleanup_procfs(void) { }; {
return 0;
}
static inline void xfs_cleanup_procfs(void)
{
}
#endif /* !CONFIG_PROC_FS */ #endif /* !CONFIG_PROC_FS */

File diff suppressed because it is too large Load Diff

View File

@ -107,12 +107,10 @@ extern void xfs_initialize_vnode(struct xfs_mount *mp, bhv_vnode_t *vp,
extern void xfs_flush_inode(struct xfs_inode *); extern void xfs_flush_inode(struct xfs_inode *);
extern void xfs_flush_device(struct xfs_inode *); extern void xfs_flush_device(struct xfs_inode *);
extern int xfs_blkdev_get(struct xfs_mount *, const char *,
struct block_device **);
extern void xfs_blkdev_put(struct block_device *);
extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
extern const struct export_operations xfs_export_operations; extern const struct export_operations xfs_export_operations;
extern struct xattr_handler *xfs_xattr_handlers[];
#define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) #define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info))

View File

@ -259,15 +259,17 @@ static ctl_table xfs_root_table[] = {
{} {}
}; };
void int
xfs_sysctl_register(void) xfs_sysctl_register(void)
{ {
xfs_table_header = register_sysctl_table(xfs_root_table); xfs_table_header = register_sysctl_table(xfs_root_table);
if (!xfs_table_header)
return -ENOMEM;
return 0;
} }
void void
xfs_sysctl_unregister(void) xfs_sysctl_unregister(void)
{ {
if (xfs_table_header) unregister_sysctl_table(xfs_table_header);
unregister_sysctl_table(xfs_table_header);
} }

View File

@ -93,10 +93,10 @@ enum {
extern xfs_param_t xfs_params; extern xfs_param_t xfs_params;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
extern void xfs_sysctl_register(void); extern int xfs_sysctl_register(void);
extern void xfs_sysctl_unregister(void); extern void xfs_sysctl_unregister(void);
#else #else
# define xfs_sysctl_register() do { } while (0) # define xfs_sysctl_register() (0)
# define xfs_sysctl_unregister() do { } while (0) # define xfs_sysctl_unregister() do { } while (0)
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */

View File

@ -82,56 +82,6 @@ vn_ioerror(
xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ, f, l); xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ, f, l);
} }
/*
* Revalidate the Linux inode from the XFS inode.
* Note: i_size _not_ updated; we must hold the inode
* semaphore when doing that - callers responsibility.
*/
int
vn_revalidate(
bhv_vnode_t *vp)
{
struct inode *inode = vn_to_inode(vp);
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
unsigned long xflags;
xfs_itrace_entry(ip);
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
xfs_ilock(ip, XFS_ILOCK_SHARED);
inode->i_mode = ip->i_d.di_mode;
inode->i_uid = ip->i_d.di_uid;
inode->i_gid = ip->i_d.di_gid;
inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec;
inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec;
inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec;
inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec;
xflags = xfs_ip2xflags(ip);
if (xflags & XFS_XFLAG_IMMUTABLE)
inode->i_flags |= S_IMMUTABLE;
else
inode->i_flags &= ~S_IMMUTABLE;
if (xflags & XFS_XFLAG_APPEND)
inode->i_flags |= S_APPEND;
else
inode->i_flags &= ~S_APPEND;
if (xflags & XFS_XFLAG_SYNC)
inode->i_flags |= S_SYNC;
else
inode->i_flags &= ~S_SYNC;
if (xflags & XFS_XFLAG_NOATIME)
inode->i_flags |= S_NOATIME;
else
inode->i_flags &= ~S_NOATIME;
xfs_iunlock(ip, XFS_ILOCK_SHARED);
xfs_iflags_clear(ip, XFS_IMODIFIED);
return 0;
}
/* /*
* Add a reference to a referenced vnode. * Add a reference to a referenced vnode.

View File

@ -19,7 +19,6 @@
#define __XFS_VNODE_H__ #define __XFS_VNODE_H__
struct file; struct file;
struct bhv_vattr;
struct xfs_iomap; struct xfs_iomap;
struct attrlist_cursor_kern; struct attrlist_cursor_kern;
@ -66,87 +65,8 @@ static inline struct inode *vn_to_inode(bhv_vnode_t *vnode)
Prevent VM access to the pages until Prevent VM access to the pages until
the operation completes. */ the operation completes. */
/*
* Vnode attributes. va_mask indicates those attributes the caller
* wants to set or extract.
*/
typedef struct bhv_vattr {
int va_mask; /* bit-mask of attributes present */
mode_t va_mode; /* file access mode and type */
xfs_nlink_t va_nlink; /* number of references to file */
uid_t va_uid; /* owner user id */
gid_t va_gid; /* owner group id */
xfs_ino_t va_nodeid; /* file id */
xfs_off_t va_size; /* file size in bytes */
u_long va_blocksize; /* blocksize preferred for i/o */
struct timespec va_atime; /* time of last access */
struct timespec va_mtime; /* time of last modification */
struct timespec va_ctime; /* time file changed */
u_int va_gen; /* generation number of file */
xfs_dev_t va_rdev; /* device the special file represents */
__int64_t va_nblocks; /* number of blocks allocated */
u_long va_xflags; /* random extended file flags */
u_long va_extsize; /* file extent size */
u_long va_nextents; /* number of extents in file */
u_long va_anextents; /* number of attr extents in file */
prid_t va_projid; /* project id */
} bhv_vattr_t;
/*
* setattr or getattr attributes
*/
#define XFS_AT_TYPE 0x00000001
#define XFS_AT_MODE 0x00000002
#define XFS_AT_UID 0x00000004
#define XFS_AT_GID 0x00000008
#define XFS_AT_FSID 0x00000010
#define XFS_AT_NODEID 0x00000020
#define XFS_AT_NLINK 0x00000040
#define XFS_AT_SIZE 0x00000080
#define XFS_AT_ATIME 0x00000100
#define XFS_AT_MTIME 0x00000200
#define XFS_AT_CTIME 0x00000400
#define XFS_AT_RDEV 0x00000800
#define XFS_AT_BLKSIZE 0x00001000
#define XFS_AT_NBLOCKS 0x00002000
#define XFS_AT_VCODE 0x00004000
#define XFS_AT_MAC 0x00008000
#define XFS_AT_UPDATIME 0x00010000
#define XFS_AT_UPDMTIME 0x00020000
#define XFS_AT_UPDCTIME 0x00040000
#define XFS_AT_ACL 0x00080000
#define XFS_AT_CAP 0x00100000
#define XFS_AT_INF 0x00200000
#define XFS_AT_XFLAGS 0x00400000
#define XFS_AT_EXTSIZE 0x00800000
#define XFS_AT_NEXTENTS 0x01000000
#define XFS_AT_ANEXTENTS 0x02000000
#define XFS_AT_PROJID 0x04000000
#define XFS_AT_SIZE_NOPERM 0x08000000
#define XFS_AT_GENCOUNT 0x10000000
#define XFS_AT_ALL (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\
XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\
XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\
XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|XFS_AT_MAC|\
XFS_AT_ACL|XFS_AT_CAP|XFS_AT_INF|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|\
XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_PROJID|XFS_AT_GENCOUNT)
#define XFS_AT_STAT (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\
XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\
XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\
XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_PROJID)
#define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME)
#define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME)
#define XFS_AT_NOSET (XFS_AT_NLINK|XFS_AT_RDEV|XFS_AT_FSID|XFS_AT_NODEID|\
XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\
XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT)
extern void vn_init(void); extern void vn_init(void);
extern int vn_revalidate(bhv_vnode_t *);
/* /*
* Yeah, these don't take vnode anymore at all, all this should be * Yeah, these don't take vnode anymore at all, all this should be
@ -219,15 +139,6 @@ static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt)
#define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \ #define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \
PAGECACHE_TAG_DIRTY) PAGECACHE_TAG_DIRTY)
/*
* Flags to vop_setattr/getattr.
*/
#define ATTR_UTIME 0x01 /* non-default utime(2) request */
#define ATTR_DMI 0x08 /* invocation from a DMI function */
#define ATTR_LAZY 0x80 /* set/get attributes lazily */
#define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */
#define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */
#define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */
/* /*
* Tracking vnode activity. * Tracking vnode activity.

View File

@ -0,0 +1,330 @@
/*
* Copyright (C) 2008 Christoph Hellwig.
* Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
*
* 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_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
#include "xfs_acl.h"
#include "xfs_vnodeops.h"
#include <linux/posix_acl_xattr.h>
#include <linux/xattr.h>
/*
* ACL handling. Should eventually be moved into xfs_acl.c
*/
static int
xfs_decode_acl(const char *name)
{
if (strcmp(name, "posix_acl_access") == 0)
return _ACL_TYPE_ACCESS;
else if (strcmp(name, "posix_acl_default") == 0)
return _ACL_TYPE_DEFAULT;
return -EINVAL;
}
/*
* Get system extended attributes which at the moment only
* includes Posix ACLs.
*/
static int
xfs_xattr_system_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
int acl;
acl = xfs_decode_acl(name);
if (acl < 0)
return acl;
return xfs_acl_vget(inode, buffer, size, acl);
}
static int
xfs_xattr_system_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
int acl;
acl = xfs_decode_acl(name);
if (acl < 0)
return acl;
if (flags & XATTR_CREATE)
return -EINVAL;
if (!value)
return xfs_acl_vremove(inode, acl);
return xfs_acl_vset(inode, (void *)value, size, acl);
}
static struct xattr_handler xfs_xattr_system_handler = {
.prefix = XATTR_SYSTEM_PREFIX,
.get = xfs_xattr_system_get,
.set = xfs_xattr_system_set,
};
/*
* Real xattr handling. The only difference between the namespaces is
* a flag passed to the low-level attr code.
*/
static int
__xfs_xattr_get(struct inode *inode, const char *name,
void *value, size_t size, int xflags)
{
struct xfs_inode *ip = XFS_I(inode);
int error, asize = size;
if (strcmp(name, "") == 0)
return -EINVAL;
/* Convert Linux syscall to XFS internal ATTR flags */
if (!size) {
xflags |= ATTR_KERNOVAL;
value = NULL;
}
error = -xfs_attr_get(ip, name, value, &asize, xflags);
if (error)
return error;
return asize;
}
static int
__xfs_xattr_set(struct inode *inode, const char *name, const void *value,
size_t size, int flags, int xflags)
{
struct xfs_inode *ip = XFS_I(inode);
if (strcmp(name, "") == 0)
return -EINVAL;
/* Convert Linux syscall to XFS internal ATTR flags */
if (flags & XATTR_CREATE)
xflags |= ATTR_CREATE;
if (flags & XATTR_REPLACE)
xflags |= ATTR_REPLACE;
if (!value)
return -xfs_attr_remove(ip, name, xflags);
return -xfs_attr_set(ip, name, (void *)value, size, xflags);
}
static int
xfs_xattr_user_get(struct inode *inode, const char *name,
void *value, size_t size)
{
return __xfs_xattr_get(inode, name, value, size, 0);
}
static int
xfs_xattr_user_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
return __xfs_xattr_set(inode, name, value, size, flags, 0);
}
static struct xattr_handler xfs_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
.get = xfs_xattr_user_get,
.set = xfs_xattr_user_set,
};
static int
xfs_xattr_trusted_get(struct inode *inode, const char *name,
void *value, size_t size)
{
return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT);
}
static int
xfs_xattr_trusted_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT);
}
static struct xattr_handler xfs_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.get = xfs_xattr_trusted_get,
.set = xfs_xattr_trusted_set,
};
static int
xfs_xattr_secure_get(struct inode *inode, const char *name,
void *value, size_t size)
{
return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE);
}
static int
xfs_xattr_secure_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE);
}
static struct xattr_handler xfs_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.get = xfs_xattr_secure_get,
.set = xfs_xattr_secure_set,
};
struct xattr_handler *xfs_xattr_handlers[] = {
&xfs_xattr_user_handler,
&xfs_xattr_trusted_handler,
&xfs_xattr_security_handler,
&xfs_xattr_system_handler,
NULL
};
static unsigned int xfs_xattr_prefix_len(int flags)
{
if (flags & XFS_ATTR_SECURE)
return sizeof("security");
else if (flags & XFS_ATTR_ROOT)
return sizeof("trusted");
else
return sizeof("user");
}
static const char *xfs_xattr_prefix(int flags)
{
if (flags & XFS_ATTR_SECURE)
return xfs_xattr_security_handler.prefix;
else if (flags & XFS_ATTR_ROOT)
return xfs_xattr_trusted_handler.prefix;
else
return xfs_xattr_user_handler.prefix;
}
static int
xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags,
char *name, int namelen, int valuelen, char *value)
{
unsigned int prefix_len = xfs_xattr_prefix_len(flags);
char *offset;
int arraytop;
ASSERT(context->count >= 0);
/*
* Only show root namespace entries if we are actually allowed to
* see them.
*/
if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
return 0;
arraytop = context->count + prefix_len + namelen + 1;
if (arraytop > context->firstu) {
context->count = -1; /* insufficient space */
return 1;
}
offset = (char *)context->alist + context->count;
strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
offset += prefix_len;
strncpy(offset, name, namelen); /* real name */
offset += namelen;
*offset = '\0';
context->count += prefix_len + namelen + 1;
return 0;
}
static int
xfs_xattr_put_listent_sizes(struct xfs_attr_list_context *context, int flags,
char *name, int namelen, int valuelen, char *value)
{
context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
return 0;
}
static int
list_one_attr(const char *name, const size_t len, void *data,
size_t size, ssize_t *result)
{
char *p = data + *result;
*result += len;
if (!size)
return 0;
if (*result > size)
return -ERANGE;
strcpy(p, name);
return 0;
}
ssize_t
xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
{
struct xfs_attr_list_context context;
struct attrlist_cursor_kern cursor = { 0 };
struct inode *inode = dentry->d_inode;
int error;
/*
* First read the regular on-disk attributes.
*/
memset(&context, 0, sizeof(context));
context.dp = XFS_I(inode);
context.cursor = &cursor;
context.resynch = 1;
context.alist = data;
context.bufsize = size;
context.firstu = context.bufsize;
if (size)
context.put_listent = xfs_xattr_put_listent;
else
context.put_listent = xfs_xattr_put_listent_sizes;
xfs_attr_list_int(&context);
if (context.count < 0)
return -ERANGE;
/*
* Then add the two synthetic ACL attributes.
*/
if (xfs_acl_vhasacl_access(inode)) {
error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS) + 1,
data, size, &context.count);
if (error)
return error;
}
if (xfs_acl_vhasacl_default(inode)) {
error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
data, size, &context.count);
if (error)
return error;
}
return context.count;
}

View File

@ -1435,8 +1435,7 @@ xfs_dqlock2(
/* ARGSUSED */ /* ARGSUSED */
int int
xfs_qm_dqpurge( xfs_qm_dqpurge(
xfs_dquot_t *dqp, xfs_dquot_t *dqp)
uint flags)
{ {
xfs_dqhash_t *thishash; xfs_dqhash_t *thishash;
xfs_mount_t *mp = dqp->q_mount; xfs_mount_t *mp = dqp->q_mount;

View File

@ -164,7 +164,7 @@ extern void xfs_qm_dqprint(xfs_dquot_t *);
extern void xfs_qm_dqdestroy(xfs_dquot_t *); extern void xfs_qm_dqdestroy(xfs_dquot_t *);
extern int xfs_qm_dqflush(xfs_dquot_t *, uint); extern int xfs_qm_dqflush(xfs_dquot_t *, uint);
extern int xfs_qm_dqpurge(xfs_dquot_t *, uint); extern int xfs_qm_dqpurge(xfs_dquot_t *);
extern void xfs_qm_dqunpin_wait(xfs_dquot_t *); extern void xfs_qm_dqunpin_wait(xfs_dquot_t *);
extern int xfs_qm_dqlock_nowait(xfs_dquot_t *); extern int xfs_qm_dqlock_nowait(xfs_dquot_t *);
extern int xfs_qm_dqflock_nowait(xfs_dquot_t *); extern int xfs_qm_dqflock_nowait(xfs_dquot_t *);

View File

@ -576,8 +576,8 @@ xfs_qm_qoffend_logitem_committed(
* xfs_trans_delete_ail() drops the AIL lock. * xfs_trans_delete_ail() drops the AIL lock.
*/ */
xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs); xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs);
kmem_free(qfs, sizeof(xfs_qoff_logitem_t)); kmem_free(qfs);
kmem_free(qfe, sizeof(xfs_qoff_logitem_t)); kmem_free(qfe);
return (xfs_lsn_t)-1; return (xfs_lsn_t)-1;
} }

View File

@ -192,8 +192,8 @@ xfs_qm_destroy(
xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i])); xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
} }
kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t)); kmem_free(xqm->qm_usr_dqhtable);
kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t)); kmem_free(xqm->qm_grp_dqhtable);
xqm->qm_usr_dqhtable = NULL; xqm->qm_usr_dqhtable = NULL;
xqm->qm_grp_dqhtable = NULL; xqm->qm_grp_dqhtable = NULL;
xqm->qm_dqhashmask = 0; xqm->qm_dqhashmask = 0;
@ -201,7 +201,7 @@ xfs_qm_destroy(
#ifdef DEBUG #ifdef DEBUG
mutex_destroy(&qcheck_lock); mutex_destroy(&qcheck_lock);
#endif #endif
kmem_free(xqm, sizeof(xfs_qm_t)); kmem_free(xqm);
} }
/* /*
@ -445,11 +445,11 @@ xfs_qm_unmount_quotas(
} }
} }
if (uqp) { if (uqp) {
XFS_PURGE_INODE(uqp); IRELE(uqp);
mp->m_quotainfo->qi_uquotaip = NULL; mp->m_quotainfo->qi_uquotaip = NULL;
} }
if (gqp) { if (gqp) {
XFS_PURGE_INODE(gqp); IRELE(gqp);
mp->m_quotainfo->qi_gquotaip = NULL; mp->m_quotainfo->qi_gquotaip = NULL;
} }
out: out:
@ -631,7 +631,7 @@ xfs_qm_dqpurge_int(
* freelist in INACTIVE state. * freelist in INACTIVE state.
*/ */
nextdqp = dqp->MPL_NEXT; nextdqp = dqp->MPL_NEXT;
nmisses += xfs_qm_dqpurge(dqp, flags); nmisses += xfs_qm_dqpurge(dqp);
dqp = nextdqp; dqp = nextdqp;
} }
xfs_qm_mplist_unlock(mp); xfs_qm_mplist_unlock(mp);
@ -1134,7 +1134,7 @@ xfs_qm_init_quotainfo(
* and change the superblock accordingly. * and change the superblock accordingly.
*/ */
if ((error = xfs_qm_init_quotainos(mp))) { if ((error = xfs_qm_init_quotainos(mp))) {
kmem_free(qinf, sizeof(xfs_quotainfo_t)); kmem_free(qinf);
mp->m_quotainfo = NULL; mp->m_quotainfo = NULL;
return error; return error;
} }
@ -1240,15 +1240,15 @@ xfs_qm_destroy_quotainfo(
xfs_qm_list_destroy(&qi->qi_dqlist); xfs_qm_list_destroy(&qi->qi_dqlist);
if (qi->qi_uquotaip) { if (qi->qi_uquotaip) {
XFS_PURGE_INODE(qi->qi_uquotaip); IRELE(qi->qi_uquotaip);
qi->qi_uquotaip = NULL; /* paranoia */ qi->qi_uquotaip = NULL; /* paranoia */
} }
if (qi->qi_gquotaip) { if (qi->qi_gquotaip) {
XFS_PURGE_INODE(qi->qi_gquotaip); IRELE(qi->qi_gquotaip);
qi->qi_gquotaip = NULL; qi->qi_gquotaip = NULL;
} }
mutex_destroy(&qi->qi_quotaofflock); mutex_destroy(&qi->qi_quotaofflock);
kmem_free(qi, sizeof(xfs_quotainfo_t)); kmem_free(qi);
mp->m_quotainfo = NULL; mp->m_quotainfo = NULL;
} }
@ -1394,7 +1394,7 @@ xfs_qm_qino_alloc(
* locked exclusively and joined to the transaction already. * locked exclusively and joined to the transaction already.
*/ */
ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL)); ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL));
VN_HOLD(XFS_ITOV((*ip))); IHOLD(*ip);
/* /*
* Make the changes in the superblock, and log those too. * Make the changes in the superblock, and log those too.
@ -1623,7 +1623,7 @@ xfs_qm_dqiterate(
break; break;
} while (nmaps > 0); } while (nmaps > 0);
kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map)); kmem_free(map);
return error; return error;
} }

View File

@ -362,11 +362,11 @@ xfs_qm_scall_quotaoff(
* if we don't need them anymore. * if we don't need them anymore.
*/ */
if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) { if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) {
XFS_PURGE_INODE(XFS_QI_UQIP(mp)); IRELE(XFS_QI_UQIP(mp));
XFS_QI_UQIP(mp) = NULL; XFS_QI_UQIP(mp) = NULL;
} }
if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && XFS_QI_GQIP(mp)) { if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && XFS_QI_GQIP(mp)) {
XFS_PURGE_INODE(XFS_QI_GQIP(mp)); IRELE(XFS_QI_GQIP(mp));
XFS_QI_GQIP(mp) = NULL; XFS_QI_GQIP(mp) = NULL;
} }
out_error: out_error:
@ -1449,14 +1449,14 @@ xfs_qm_internalqcheck(
for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
xfs_dqtest_cmp(d); xfs_dqtest_cmp(d);
e = (xfs_dqtest_t *) d->HL_NEXT; e = (xfs_dqtest_t *) d->HL_NEXT;
kmem_free(d, sizeof(xfs_dqtest_t)); kmem_free(d);
d = e; d = e;
} }
h1 = &qmtest_gdqtab[i]; h1 = &qmtest_gdqtab[i];
for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
xfs_dqtest_cmp(d); xfs_dqtest_cmp(d);
e = (xfs_dqtest_t *) d->HL_NEXT; e = (xfs_dqtest_t *) d->HL_NEXT;
kmem_free(d, sizeof(xfs_dqtest_t)); kmem_free(d);
d = e; d = e;
} }
} }
@ -1467,8 +1467,8 @@ xfs_qm_internalqcheck(
} else { } else {
cmn_err(CE_DEBUG, "******** quotacheck successful! ********"); cmn_err(CE_DEBUG, "******** quotacheck successful! ********");
} }
kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); kmem_free(qmtest_udqtab);
kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); kmem_free(qmtest_gdqtab);
mutex_unlock(&qcheck_lock); mutex_unlock(&qcheck_lock);
return (qmtest_nfails); return (qmtest_nfails);
} }

View File

@ -158,9 +158,6 @@ for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
#define XFS_IS_SUSER_DQUOT(dqp) \ #define XFS_IS_SUSER_DQUOT(dqp) \
(!((dqp)->q_core.d_id)) (!((dqp)->q_core.d_id))
#define XFS_PURGE_INODE(ip) \
IRELE(ip);
#define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ #define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
(((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \ (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \
(((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???"))) (((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???")))

View File

@ -89,7 +89,7 @@ ktrace_alloc(int nentries, unsigned int __nocast sleep)
if (sleep & KM_SLEEP) if (sleep & KM_SLEEP)
panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); panic("ktrace_alloc: NULL memory on KM_SLEEP request!");
kmem_free(ktp, sizeof(*ktp)); kmem_free(ktp);
return NULL; return NULL;
} }
@ -126,7 +126,7 @@ ktrace_free(ktrace_t *ktp)
} else { } else {
entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t)); entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t));
kmem_free(ktp->kt_entries, entries_size); kmem_free(ktp->kt_entries);
} }
kmem_zone_free(ktrace_hdr_zone, ktp); kmem_zone_free(ktrace_hdr_zone, ktp);

View File

@ -17,7 +17,7 @@
*/ */
#include <xfs.h> #include <xfs.h>
static mutex_t uuid_monitor; static DEFINE_MUTEX(uuid_monitor);
static int uuid_table_size; static int uuid_table_size;
static uuid_t *uuid_table; static uuid_t *uuid_table;
@ -132,9 +132,3 @@ uuid_table_remove(uuid_t *uuid)
ASSERT(i < uuid_table_size); ASSERT(i < uuid_table_size);
mutex_unlock(&uuid_monitor); mutex_unlock(&uuid_monitor);
} }
void __init
uuid_init(void)
{
mutex_init(&uuid_monitor);
}

View File

@ -22,7 +22,6 @@ typedef struct {
unsigned char __u_bits[16]; unsigned char __u_bits[16];
} uuid_t; } uuid_t;
extern void uuid_init(void);
extern void uuid_create_nil(uuid_t *uuid); extern void uuid_create_nil(uuid_t *uuid);
extern int uuid_is_nil(uuid_t *uuid); extern int uuid_is_nil(uuid_t *uuid);
extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2); extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2);

View File

@ -341,8 +341,7 @@ xfs_acl_iaccess(
/* If the file has no ACL return -1. */ /* If the file has no ACL return -1. */
rval = sizeof(xfs_acl_t); rval = sizeof(xfs_acl_t);
if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval, if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval, ATTR_ROOT)) {
ATTR_ROOT | ATTR_KERNACCESS)) {
_ACL_FREE(acl); _ACL_FREE(acl);
return -1; return -1;
} }
@ -720,7 +719,7 @@ xfs_acl_setmode(
xfs_acl_t *acl, xfs_acl_t *acl,
int *basicperms) int *basicperms)
{ {
bhv_vattr_t va; struct iattr iattr;
xfs_acl_entry_t *ap; xfs_acl_entry_t *ap;
xfs_acl_entry_t *gap = NULL; xfs_acl_entry_t *gap = NULL;
int i, nomask = 1; int i, nomask = 1;
@ -734,25 +733,25 @@ xfs_acl_setmode(
* Copy the u::, g::, o::, and m:: bits from the ACL into the * Copy the u::, g::, o::, and m:: bits from the ACL into the
* mode. The m:: bits take precedence over the g:: bits. * mode. The m:: bits take precedence over the g:: bits.
*/ */
va.va_mask = XFS_AT_MODE; iattr.ia_valid = ATTR_MODE;
va.va_mode = xfs_vtoi(vp)->i_d.di_mode; iattr.ia_mode = xfs_vtoi(vp)->i_d.di_mode;
va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); iattr.ia_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
ap = acl->acl_entry; ap = acl->acl_entry;
for (i = 0; i < acl->acl_cnt; ++i) { for (i = 0; i < acl->acl_cnt; ++i) {
switch (ap->ae_tag) { switch (ap->ae_tag) {
case ACL_USER_OBJ: case ACL_USER_OBJ:
va.va_mode |= ap->ae_perm << 6; iattr.ia_mode |= ap->ae_perm << 6;
break; break;
case ACL_GROUP_OBJ: case ACL_GROUP_OBJ:
gap = ap; gap = ap;
break; break;
case ACL_MASK: /* more than just standard modes */ case ACL_MASK: /* more than just standard modes */
nomask = 0; nomask = 0;
va.va_mode |= ap->ae_perm << 3; iattr.ia_mode |= ap->ae_perm << 3;
*basicperms = 0; *basicperms = 0;
break; break;
case ACL_OTHER: case ACL_OTHER:
va.va_mode |= ap->ae_perm; iattr.ia_mode |= ap->ae_perm;
break; break;
default: /* more than just standard modes */ default: /* more than just standard modes */
*basicperms = 0; *basicperms = 0;
@ -763,9 +762,9 @@ xfs_acl_setmode(
/* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */ /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */
if (gap && nomask) if (gap && nomask)
va.va_mode |= gap->ae_perm << 3; iattr.ia_mode |= gap->ae_perm << 3;
return xfs_setattr(xfs_vtoi(vp), &va, 0, sys_cred); return xfs_setattr(xfs_vtoi(vp), &iattr, 0, sys_cred);
} }
/* /*

View File

@ -46,6 +46,8 @@ typedef struct xfs_acl {
#define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) #define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1)
#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1)
#define _ACL_TYPE_ACCESS 1
#define _ACL_TYPE_DEFAULT 2
#ifdef CONFIG_XFS_POSIX_ACL #ifdef CONFIG_XFS_POSIX_ACL
@ -66,8 +68,6 @@ extern int xfs_acl_vset(bhv_vnode_t *, void *, size_t, int);
extern int xfs_acl_vget(bhv_vnode_t *, void *, size_t, int); extern int xfs_acl_vget(bhv_vnode_t *, void *, size_t, int);
extern int xfs_acl_vremove(bhv_vnode_t *, int); extern int xfs_acl_vremove(bhv_vnode_t *, int);
#define _ACL_TYPE_ACCESS 1
#define _ACL_TYPE_DEFAULT 2
#define _ACL_PERM_INVALID(perm) ((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) #define _ACL_PERM_INVALID(perm) ((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
#define _ACL_INHERIT(c,m,d) (xfs_acl_inherit(c,m,d)) #define _ACL_INHERIT(c,m,d) (xfs_acl_inherit(c,m,d))

View File

@ -16,8 +16,6 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <linux/capability.h>
#include "xfs.h" #include "xfs.h"
#include "xfs_fs.h" #include "xfs_fs.h"
#include "xfs_types.h" #include "xfs_types.h"
@ -57,11 +55,6 @@
* Provide the external interfaces to manage attribute lists. * Provide the external interfaces to manage attribute lists.
*/ */
#define ATTR_SYSCOUNT 2
static struct attrnames posix_acl_access;
static struct attrnames posix_acl_default;
static struct attrnames *attr_system_names[ATTR_SYSCOUNT];
/*======================================================================== /*========================================================================
* Function prototypes for the kernel. * Function prototypes for the kernel.
*========================================================================*/ *========================================================================*/
@ -116,6 +109,17 @@ xfs_attr_name_to_xname(
return 0; return 0;
} }
STATIC int
xfs_inode_hasattr(
struct xfs_inode *ip)
{
if (!XFS_IFORK_Q(ip) ||
(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
ip->i_d.di_anextents == 0))
return 0;
return 1;
}
/*======================================================================== /*========================================================================
* Overall external interface routines. * Overall external interface routines.
*========================================================================*/ *========================================================================*/
@ -127,10 +131,8 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name,
xfs_da_args_t args; xfs_da_args_t args;
int error; int error;
if ((XFS_IFORK_Q(ip) == 0) || if (!xfs_inode_hasattr(ip))
(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && return ENOATTR;
ip->i_d.di_anextents == 0))
return(ENOATTR);
/* /*
* Fill in the arg structure for this request. * Fill in the arg structure for this request.
@ -148,11 +150,7 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name,
/* /*
* Decide on what work routines to call based on the inode size. * Decide on what work routines to call based on the inode size.
*/ */
if (XFS_IFORK_Q(ip) == 0 || if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
ip->i_d.di_anextents == 0)) {
error = XFS_ERROR(ENOATTR);
} else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
error = xfs_attr_shortform_getvalue(&args); error = xfs_attr_shortform_getvalue(&args);
} else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
error = xfs_attr_leaf_get(&args); error = xfs_attr_leaf_get(&args);
@ -241,8 +239,7 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name,
args.firstblock = &firstblock; args.firstblock = &firstblock;
args.flist = &flist; args.flist = &flist;
args.whichfork = XFS_ATTR_FORK; args.whichfork = XFS_ATTR_FORK;
args.addname = 1; args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
args.oknoent = 1;
/* /*
* Determine space new attribute will use, and if it would be * Determine space new attribute will use, and if it would be
@ -529,9 +526,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
/* /*
* Decide on what work routines to call based on the inode size. * Decide on what work routines to call based on the inode size.
*/ */
if (XFS_IFORK_Q(dp) == 0 || if (!xfs_inode_hasattr(dp)) {
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
dp->i_d.di_anextents == 0)) {
error = XFS_ERROR(ENOATTR); error = XFS_ERROR(ENOATTR);
goto out; goto out;
} }
@ -601,29 +596,33 @@ xfs_attr_remove(
return error; return error;
xfs_ilock(dp, XFS_ILOCK_SHARED); xfs_ilock(dp, XFS_ILOCK_SHARED);
if (XFS_IFORK_Q(dp) == 0 || if (!xfs_inode_hasattr(dp)) {
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
dp->i_d.di_anextents == 0)) {
xfs_iunlock(dp, XFS_ILOCK_SHARED); xfs_iunlock(dp, XFS_ILOCK_SHARED);
return(XFS_ERROR(ENOATTR)); return XFS_ERROR(ENOATTR);
} }
xfs_iunlock(dp, XFS_ILOCK_SHARED); xfs_iunlock(dp, XFS_ILOCK_SHARED);
return xfs_attr_remove_int(dp, &xname, flags); return xfs_attr_remove_int(dp, &xname, flags);
} }
STATIC int int
xfs_attr_list_int(xfs_attr_list_context_t *context) xfs_attr_list_int(xfs_attr_list_context_t *context)
{ {
int error; int error;
xfs_inode_t *dp = context->dp; xfs_inode_t *dp = context->dp;
XFS_STATS_INC(xs_attr_list);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return EIO;
xfs_ilock(dp, XFS_ILOCK_SHARED);
xfs_attr_trace_l_c("syscall start", context);
/* /*
* Decide on what work routines to call based on the inode size. * Decide on what work routines to call based on the inode size.
*/ */
if (XFS_IFORK_Q(dp) == 0 || if (!xfs_inode_hasattr(dp)) {
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
dp->i_d.di_anextents == 0)) {
error = 0; error = 0;
} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
error = xfs_attr_shortform_list(context); error = xfs_attr_shortform_list(context);
@ -632,6 +631,10 @@ xfs_attr_list_int(xfs_attr_list_context_t *context)
} else { } else {
error = xfs_attr_node_list(context); error = xfs_attr_node_list(context);
} }
xfs_iunlock(dp, XFS_ILOCK_SHARED);
xfs_attr_trace_l_c("syscall end", context);
return error; return error;
} }
@ -648,74 +651,50 @@ xfs_attr_list_int(xfs_attr_list_context_t *context)
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
STATIC int STATIC int
xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp, xfs_attr_put_listent(xfs_attr_list_context_t *context, int flags,
char *name, int namelen, char *name, int namelen,
int valuelen, char *value) int valuelen, char *value)
{ {
struct attrlist *alist = (struct attrlist *)context->alist;
attrlist_ent_t *aep; attrlist_ent_t *aep;
int arraytop; int arraytop;
ASSERT(!(context->flags & ATTR_KERNOVAL)); ASSERT(!(context->flags & ATTR_KERNOVAL));
ASSERT(context->count >= 0); ASSERT(context->count >= 0);
ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
ASSERT(context->firstu >= sizeof(*context->alist)); ASSERT(context->firstu >= sizeof(*alist));
ASSERT(context->firstu <= context->bufsize); ASSERT(context->firstu <= context->bufsize);
arraytop = sizeof(*context->alist) + /*
context->count * sizeof(context->alist->al_offset[0]); * Only list entries in the right namespace.
*/
if (((context->flags & ATTR_SECURE) == 0) !=
((flags & XFS_ATTR_SECURE) == 0))
return 0;
if (((context->flags & ATTR_ROOT) == 0) !=
((flags & XFS_ATTR_ROOT) == 0))
return 0;
arraytop = sizeof(*alist) +
context->count * sizeof(alist->al_offset[0]);
context->firstu -= ATTR_ENTSIZE(namelen); context->firstu -= ATTR_ENTSIZE(namelen);
if (context->firstu < arraytop) { if (context->firstu < arraytop) {
xfs_attr_trace_l_c("buffer full", context); xfs_attr_trace_l_c("buffer full", context);
context->alist->al_more = 1; alist->al_more = 1;
context->seen_enough = 1; context->seen_enough = 1;
return 1; return 1;
} }
aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); aep = (attrlist_ent_t *)&context->alist[context->firstu];
aep->a_valuelen = valuelen; aep->a_valuelen = valuelen;
memcpy(aep->a_name, name, namelen); memcpy(aep->a_name, name, namelen);
aep->a_name[ namelen ] = 0; aep->a_name[namelen] = 0;
context->alist->al_offset[ context->count++ ] = context->firstu; alist->al_offset[context->count++] = context->firstu;
context->alist->al_count = context->count; alist->al_count = context->count;
xfs_attr_trace_l_c("add", context); xfs_attr_trace_l_c("add", context);
return 0; return 0;
} }
STATIC int
xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp,
char *name, int namelen,
int valuelen, char *value)
{
char *offset;
int arraytop;
ASSERT(context->count >= 0);
arraytop = context->count + namesp->attr_namelen + namelen + 1;
if (arraytop > context->firstu) {
context->count = -1; /* insufficient space */
return 1;
}
offset = (char *)context->alist + context->count;
strncpy(offset, namesp->attr_name, namesp->attr_namelen);
offset += namesp->attr_namelen;
strncpy(offset, name, namelen); /* real name */
offset += namelen;
*offset = '\0';
context->count += namesp->attr_namelen + namelen + 1;
return 0;
}
/*ARGSUSED*/
STATIC int
xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp,
char *name, int namelen,
int valuelen, char *value)
{
context->count += namesp->attr_namelen + namelen + 1;
return 0;
}
/* /*
* Generate a list of extended attribute names and optionally * Generate a list of extended attribute names and optionally
* also value lengths. Positive return value follows the XFS * also value lengths. Positive return value follows the XFS
@ -732,10 +711,9 @@ xfs_attr_list(
attrlist_cursor_kern_t *cursor) attrlist_cursor_kern_t *cursor)
{ {
xfs_attr_list_context_t context; xfs_attr_list_context_t context;
struct attrlist *alist;
int error; int error;
XFS_STATS_INC(xs_attr_list);
/* /*
* Validate the cursor. * Validate the cursor.
*/ */
@ -756,52 +734,23 @@ xfs_attr_list(
/* /*
* Initialize the output buffer. * Initialize the output buffer.
*/ */
memset(&context, 0, sizeof(context));
context.dp = dp; context.dp = dp;
context.cursor = cursor; context.cursor = cursor;
context.count = 0;
context.dupcnt = 0;
context.resynch = 1; context.resynch = 1;
context.flags = flags; context.flags = flags;
context.seen_enough = 0; context.alist = buffer;
context.alist = (attrlist_t *)buffer; context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
context.put_value = 0; context.firstu = context.bufsize;
context.put_listent = xfs_attr_put_listent;
if (flags & ATTR_KERNAMELS) { alist = (struct attrlist *)context.alist;
context.bufsize = bufsize; alist->al_count = 0;
context.firstu = context.bufsize; alist->al_more = 0;
if (flags & ATTR_KERNOVAL) alist->al_offset[0] = context.bufsize;
context.put_listent = xfs_attr_kern_list_sizes;
else
context.put_listent = xfs_attr_kern_list;
} else {
context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
context.firstu = context.bufsize;
context.alist->al_count = 0;
context.alist->al_more = 0;
context.alist->al_offset[0] = context.bufsize;
context.put_listent = xfs_attr_put_listent;
}
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return EIO;
xfs_ilock(dp, XFS_ILOCK_SHARED);
xfs_attr_trace_l_c("syscall start", &context);
error = xfs_attr_list_int(&context); error = xfs_attr_list_int(&context);
ASSERT(error >= 0);
xfs_iunlock(dp, XFS_ILOCK_SHARED);
xfs_attr_trace_l_c("syscall end", &context);
if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) {
/* must return negated buffer size or the error */
if (context.count < 0)
error = XFS_ERROR(ERANGE);
else
error = -context.count;
} else
ASSERT(error >= 0);
return error; return error;
} }
@ -816,12 +765,10 @@ xfs_attr_inactive(xfs_inode_t *dp)
ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
xfs_ilock(dp, XFS_ILOCK_SHARED); xfs_ilock(dp, XFS_ILOCK_SHARED);
if ((XFS_IFORK_Q(dp) == 0) || if (!xfs_inode_hasattr(dp) ||
(dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
dp->i_d.di_anextents == 0)) {
xfs_iunlock(dp, XFS_ILOCK_SHARED); xfs_iunlock(dp, XFS_ILOCK_SHARED);
return(0); return 0;
} }
xfs_iunlock(dp, XFS_ILOCK_SHARED); xfs_iunlock(dp, XFS_ILOCK_SHARED);
@ -854,10 +801,8 @@ xfs_attr_inactive(xfs_inode_t *dp)
/* /*
* Decide on what work routines to call based on the inode size. * Decide on what work routines to call based on the inode size.
*/ */
if ((XFS_IFORK_Q(dp) == 0) || if (!xfs_inode_hasattr(dp) ||
(dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
dp->i_d.di_anextents == 0)) {
error = 0; error = 0;
goto out; goto out;
} }
@ -974,7 +919,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
xfs_da_brelse(args->trans, bp); xfs_da_brelse(args->trans, bp);
return(retval); return(retval);
} }
args->rename = 1; /* an atomic rename */ args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */
args->blkno2 = args->blkno; /* set 2nd entry info*/ args->blkno2 = args->blkno; /* set 2nd entry info*/
args->index2 = args->index; args->index2 = args->index;
args->rmtblkno2 = args->rmtblkno; args->rmtblkno2 = args->rmtblkno;
@ -1054,7 +999,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
* so that one disappears and one appears atomically. Then we * so that one disappears and one appears atomically. Then we
* must remove the "old" attribute/value pair. * must remove the "old" attribute/value pair.
*/ */
if (args->rename) { if (args->op_flags & XFS_DA_OP_RENAME) {
/* /*
* In a separate transaction, set the incomplete flag on the * In a separate transaction, set the incomplete flag on the
* "old" attr and clear the incomplete flag on the "new" attr. * "old" attr and clear the incomplete flag on the "new" attr.
@ -1307,7 +1252,7 @@ restart:
} else if (retval == EEXIST) { } else if (retval == EEXIST) {
if (args->flags & ATTR_CREATE) if (args->flags & ATTR_CREATE)
goto out; goto out;
args->rename = 1; /* atomic rename op */ args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */
args->blkno2 = args->blkno; /* set 2nd entry info*/ args->blkno2 = args->blkno; /* set 2nd entry info*/
args->index2 = args->index; args->index2 = args->index;
args->rmtblkno2 = args->rmtblkno; args->rmtblkno2 = args->rmtblkno;
@ -1425,7 +1370,7 @@ restart:
* so that one disappears and one appears atomically. Then we * so that one disappears and one appears atomically. Then we
* must remove the "old" attribute/value pair. * must remove the "old" attribute/value pair.
*/ */
if (args->rename) { if (args->op_flags & XFS_DA_OP_RENAME) {
/* /*
* In a separate transaction, set the incomplete flag on the * In a separate transaction, set the incomplete flag on the
* "old" attr and clear the incomplete flag on the "new" attr. * "old" attr and clear the incomplete flag on the "new" attr.
@ -2300,23 +2245,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
void void
xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context)
{ {
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, context,
(__psunsigned_t)context->dp,
(__psunsigned_t)context->cursor->hashval,
(__psunsigned_t)context->cursor->blkno,
(__psunsigned_t)context->cursor->offset,
(__psunsigned_t)context->alist,
(__psunsigned_t)context->bufsize,
(__psunsigned_t)context->count,
(__psunsigned_t)context->firstu,
(__psunsigned_t)
((context->count > 0) &&
!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
? (ATTR_ENTRY(context->alist,
context->count-1)->a_valuelen)
: 0,
(__psunsigned_t)context->dupcnt,
(__psunsigned_t)context->flags,
(__psunsigned_t)NULL, (__psunsigned_t)NULL,
(__psunsigned_t)NULL, (__psunsigned_t)NULL,
(__psunsigned_t)NULL); (__psunsigned_t)NULL);
@ -2329,23 +2258,7 @@ void
xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context,
struct xfs_da_intnode *node) struct xfs_da_intnode *node)
{ {
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, context,
(__psunsigned_t)context->dp,
(__psunsigned_t)context->cursor->hashval,
(__psunsigned_t)context->cursor->blkno,
(__psunsigned_t)context->cursor->offset,
(__psunsigned_t)context->alist,
(__psunsigned_t)context->bufsize,
(__psunsigned_t)context->count,
(__psunsigned_t)context->firstu,
(__psunsigned_t)
((context->count > 0) &&
!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
? (ATTR_ENTRY(context->alist,
context->count-1)->a_valuelen)
: 0,
(__psunsigned_t)context->dupcnt,
(__psunsigned_t)context->flags,
(__psunsigned_t)be16_to_cpu(node->hdr.count), (__psunsigned_t)be16_to_cpu(node->hdr.count),
(__psunsigned_t)be32_to_cpu(node->btree[0].hashval), (__psunsigned_t)be32_to_cpu(node->btree[0].hashval),
(__psunsigned_t)be32_to_cpu(node->btree[ (__psunsigned_t)be32_to_cpu(node->btree[
@ -2359,23 +2272,7 @@ void
xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context,
struct xfs_da_node_entry *btree) struct xfs_da_node_entry *btree)
{ {
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, context,
(__psunsigned_t)context->dp,
(__psunsigned_t)context->cursor->hashval,
(__psunsigned_t)context->cursor->blkno,
(__psunsigned_t)context->cursor->offset,
(__psunsigned_t)context->alist,
(__psunsigned_t)context->bufsize,
(__psunsigned_t)context->count,
(__psunsigned_t)context->firstu,
(__psunsigned_t)
((context->count > 0) &&
!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
? (ATTR_ENTRY(context->alist,
context->count-1)->a_valuelen)
: 0,
(__psunsigned_t)context->dupcnt,
(__psunsigned_t)context->flags,
(__psunsigned_t)be32_to_cpu(btree->hashval), (__psunsigned_t)be32_to_cpu(btree->hashval),
(__psunsigned_t)be32_to_cpu(btree->before), (__psunsigned_t)be32_to_cpu(btree->before),
(__psunsigned_t)NULL); (__psunsigned_t)NULL);
@ -2388,23 +2285,7 @@ void
xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
struct xfs_attr_leafblock *leaf) struct xfs_attr_leafblock *leaf)
{ {
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, context,
(__psunsigned_t)context->dp,
(__psunsigned_t)context->cursor->hashval,
(__psunsigned_t)context->cursor->blkno,
(__psunsigned_t)context->cursor->offset,
(__psunsigned_t)context->alist,
(__psunsigned_t)context->bufsize,
(__psunsigned_t)context->count,
(__psunsigned_t)context->firstu,
(__psunsigned_t)
((context->count > 0) &&
!(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
? (ATTR_ENTRY(context->alist,
context->count-1)->a_valuelen)
: 0,
(__psunsigned_t)context->dupcnt,
(__psunsigned_t)context->flags,
(__psunsigned_t)be16_to_cpu(leaf->hdr.count), (__psunsigned_t)be16_to_cpu(leaf->hdr.count),
(__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval),
(__psunsigned_t)be32_to_cpu(leaf->entries[ (__psunsigned_t)be32_to_cpu(leaf->entries[
@ -2417,329 +2298,24 @@ xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
*/ */
void void
xfs_attr_trace_enter(int type, char *where, xfs_attr_trace_enter(int type, char *where,
__psunsigned_t a2, __psunsigned_t a3, struct xfs_attr_list_context *context,
__psunsigned_t a4, __psunsigned_t a5, __psunsigned_t a13, __psunsigned_t a14,
__psunsigned_t a6, __psunsigned_t a7, __psunsigned_t a15)
__psunsigned_t a8, __psunsigned_t a9,
__psunsigned_t a10, __psunsigned_t a11,
__psunsigned_t a12, __psunsigned_t a13,
__psunsigned_t a14, __psunsigned_t a15)
{ {
ASSERT(xfs_attr_trace_buf); ASSERT(xfs_attr_trace_buf);
ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type),
(void *)where, (void *)((__psunsigned_t)where),
(void *)a2, (void *)a3, (void *)a4, (void *)((__psunsigned_t)context->dp),
(void *)a5, (void *)a6, (void *)a7, (void *)((__psunsigned_t)context->cursor->hashval),
(void *)a8, (void *)a9, (void *)a10, (void *)((__psunsigned_t)context->cursor->blkno),
(void *)a11, (void *)a12, (void *)a13, (void *)((__psunsigned_t)context->cursor->offset),
(void *)a14, (void *)a15); (void *)((__psunsigned_t)context->alist),
(void *)((__psunsigned_t)context->bufsize),
(void *)((__psunsigned_t)context->count),
(void *)((__psunsigned_t)context->firstu),
NULL,
(void *)((__psunsigned_t)context->dupcnt),
(void *)((__psunsigned_t)context->flags),
(void *)a13, (void *)a14, (void *)a15);
} }
#endif /* XFS_ATTR_TRACE */ #endif /* XFS_ATTR_TRACE */
/*========================================================================
* System (pseudo) namespace attribute interface routines.
*========================================================================*/
STATIC int
posix_acl_access_set(
bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
}
STATIC int
posix_acl_access_remove(
bhv_vnode_t *vp, char *name, int xflags)
{
return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
}
STATIC int
posix_acl_access_get(
bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
}
STATIC int
posix_acl_access_exists(
bhv_vnode_t *vp)
{
return xfs_acl_vhasacl_access(vp);
}
STATIC int
posix_acl_default_set(
bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
}
STATIC int
posix_acl_default_get(
bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
}
STATIC int
posix_acl_default_remove(
bhv_vnode_t *vp, char *name, int xflags)
{
return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
}
STATIC int
posix_acl_default_exists(
bhv_vnode_t *vp)
{
return xfs_acl_vhasacl_default(vp);
}
static struct attrnames posix_acl_access = {
.attr_name = "posix_acl_access",
.attr_namelen = sizeof("posix_acl_access") - 1,
.attr_get = posix_acl_access_get,
.attr_set = posix_acl_access_set,
.attr_remove = posix_acl_access_remove,
.attr_exists = posix_acl_access_exists,
};
static struct attrnames posix_acl_default = {
.attr_name = "posix_acl_default",
.attr_namelen = sizeof("posix_acl_default") - 1,
.attr_get = posix_acl_default_get,
.attr_set = posix_acl_default_set,
.attr_remove = posix_acl_default_remove,
.attr_exists = posix_acl_default_exists,
};
static struct attrnames *attr_system_names[] =
{ &posix_acl_access, &posix_acl_default };
/*========================================================================
* Namespace-prefix-style attribute name interface routines.
*========================================================================*/
STATIC int
attr_generic_set(
bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
return -xfs_attr_set(xfs_vtoi(vp), name, data, size, xflags);
}
STATIC int
attr_generic_get(
bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
int error, asize = size;
error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags);
if (!error)
return asize;
return -error;
}
STATIC int
attr_generic_remove(
bhv_vnode_t *vp, char *name, int xflags)
{
return -xfs_attr_remove(xfs_vtoi(vp), name, xflags);
}
STATIC int
attr_generic_listadd(
attrnames_t *prefix,
attrnames_t *namesp,
void *data,
size_t size,
ssize_t *result)
{
char *p = data + *result;
*result += prefix->attr_namelen;
*result += namesp->attr_namelen + 1;
if (!size)
return 0;
if (*result > size)
return -ERANGE;
strcpy(p, prefix->attr_name);
p += prefix->attr_namelen;
strcpy(p, namesp->attr_name);
p += namesp->attr_namelen + 1;
return 0;
}
STATIC int
attr_system_list(
bhv_vnode_t *vp,
void *data,
size_t size,
ssize_t *result)
{
attrnames_t *namesp;
int i, error = 0;
for (i = 0; i < ATTR_SYSCOUNT; i++) {
namesp = attr_system_names[i];
if (!namesp->attr_exists || !namesp->attr_exists(vp))
continue;
error = attr_generic_listadd(&attr_system, namesp,
data, size, result);
if (error)
break;
}
return error;
}
int
attr_generic_list(
bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result)
{
attrlist_cursor_kern_t cursor = { 0 };
int error;
error = xfs_attr_list(xfs_vtoi(vp), data, size, xflags, &cursor);
if (error > 0)
return -error;
*result = -error;
return attr_system_list(vp, data, size, result);
}
attrnames_t *
attr_lookup_namespace(
char *name,
struct attrnames **names,
int nnames)
{
int i;
for (i = 0; i < nnames; i++)
if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen))
return names[i];
return NULL;
}
/*
* Some checks to prevent people abusing EAs to get over quota:
* - Don't allow modifying user EAs on devices/symlinks;
* - Don't allow modifying user EAs if sticky bit set;
*/
STATIC int
attr_user_capable(
bhv_vnode_t *vp,
cred_t *cred)
{
struct inode *inode = vn_to_inode(vp);
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
(current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
return 0;
}
STATIC int
attr_trusted_capable(
bhv_vnode_t *vp,
cred_t *cred)
{
struct inode *inode = vn_to_inode(vp);
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
STATIC int
attr_system_set(
bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
attrnames_t *namesp;
int error;
if (xflags & ATTR_CREATE)
return -EINVAL;
namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
if (!namesp)
return -EOPNOTSUPP;
error = namesp->attr_set(vp, name, data, size, xflags);
if (!error)
error = vn_revalidate(vp);
return error;
}
STATIC int
attr_system_get(
bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
{
attrnames_t *namesp;
namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
if (!namesp)
return -EOPNOTSUPP;
return namesp->attr_get(vp, name, data, size, xflags);
}
STATIC int
attr_system_remove(
bhv_vnode_t *vp, char *name, int xflags)
{
attrnames_t *namesp;
namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
if (!namesp)
return -EOPNOTSUPP;
return namesp->attr_remove(vp, name, xflags);
}
struct attrnames attr_system = {
.attr_name = "system.",
.attr_namelen = sizeof("system.") - 1,
.attr_flag = ATTR_SYSTEM,
.attr_get = attr_system_get,
.attr_set = attr_system_set,
.attr_remove = attr_system_remove,
.attr_capable = (attrcapable_t)fs_noerr,
};
struct attrnames attr_trusted = {
.attr_name = "trusted.",
.attr_namelen = sizeof("trusted.") - 1,
.attr_flag = ATTR_ROOT,
.attr_get = attr_generic_get,
.attr_set = attr_generic_set,
.attr_remove = attr_generic_remove,
.attr_capable = attr_trusted_capable,
};
struct attrnames attr_secure = {
.attr_name = "security.",
.attr_namelen = sizeof("security.") - 1,
.attr_flag = ATTR_SECURE,
.attr_get = attr_generic_get,
.attr_set = attr_generic_set,
.attr_remove = attr_generic_remove,
.attr_capable = (attrcapable_t)fs_noerr,
};
struct attrnames attr_user = {
.attr_name = "user.",
.attr_namelen = sizeof("user.") - 1,
.attr_get = attr_generic_get,
.attr_set = attr_generic_set,
.attr_remove = attr_generic_remove,
.attr_capable = attr_user_capable,
};
struct attrnames *attr_namespaces[] =
{ &attr_system, &attr_trusted, &attr_secure, &attr_user };

View File

@ -18,9 +18,11 @@
#ifndef __XFS_ATTR_H__ #ifndef __XFS_ATTR_H__
#define __XFS_ATTR_H__ #define __XFS_ATTR_H__
struct xfs_inode;
struct xfs_da_args;
struct xfs_attr_list_context;
/* /*
* xfs_attr.h
*
* Large attribute lists are structured around Btrees where all the data * Large attribute lists are structured around Btrees where all the data
* elements are in the leaf nodes. Attribute names are hashed into an int, * elements are in the leaf nodes. Attribute names are hashed into an int,
* then that int is used as the index into the Btree. Since the hashval * then that int is used as the index into the Btree. Since the hashval
@ -35,35 +37,6 @@
* External interfaces * External interfaces
*========================================================================*/ *========================================================================*/
struct cred;
struct xfs_attr_list_context;
typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int);
typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
typedef int (*attrexists_t)(bhv_vnode_t *);
typedef int (*attrcapable_t)(bhv_vnode_t *, struct cred *);
typedef struct attrnames {
char * attr_name;
unsigned int attr_namelen;
unsigned int attr_flag;
attrget_t attr_get;
attrset_t attr_set;
attrremove_t attr_remove;
attrexists_t attr_exists;
attrcapable_t attr_capable;
} attrnames_t;
#define ATTR_NAMECOUNT 4
extern struct attrnames attr_user;
extern struct attrnames attr_secure;
extern struct attrnames attr_system;
extern struct attrnames attr_trusted;
extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *);
#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ #define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */
#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */
@ -71,16 +44,9 @@ extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *);
#define ATTR_SECURE 0x0008 /* use attrs in security namespace */ #define ATTR_SECURE 0x0008 /* use attrs in security namespace */
#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */ #define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */ #define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
#define ATTR_SYSTEM 0x0100 /* use attrs in system (pseudo) namespace */
#define ATTR_KERNACCESS 0x0400 /* [kernel] iaccess, inode held io-locked */
#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */ #define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */ #define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
#define ATTR_KERNAMELS 0x4000 /* [kernel] list attr names (simple list) */
#define ATTR_KERNORMALS 0x0800 /* [kernel] normal attr list: user+secure */
#define ATTR_KERNROOTLS 0x8000 /* [kernel] include root in the attr list */
#define ATTR_KERNFULLS (ATTR_KERNORMALS|ATTR_KERNROOTLS)
/* /*
* The maximum size (into the kernel or returned from the kernel) of an * The maximum size (into the kernel or returned from the kernel) of an
@ -118,22 +84,6 @@ typedef struct attrlist_ent { /* data from attr_list() */
((attrlist_ent_t *) \ ((attrlist_ent_t *) \
&((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ]) &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
/*
* Multi-attribute operation vector.
*/
typedef struct attr_multiop {
int am_opcode; /* operation to perform (ATTR_OP_GET, etc.) */
int am_error; /* [out arg] result of this sub-op (an errno) */
char *am_attrname; /* attribute name to work with */
char *am_attrvalue; /* [in/out arg] attribute value (raw bytes) */
int am_length; /* [in/out arg] length of value */
int am_flags; /* bitwise OR of attr API flags defined above */
} attr_multiop_t;
#define ATTR_OP_GET 1 /* return the indicated attr's value */
#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
/* /*
* Kernel-internal version of the attrlist cursor. * Kernel-internal version of the attrlist cursor.
*/ */
@ -148,20 +98,40 @@ typedef struct attrlist_cursor_kern {
/*======================================================================== /*========================================================================
* Function prototypes for the kernel. * Structure used to pass context around among the routines.
*========================================================================*/ *========================================================================*/
struct xfs_inode;
struct attrlist_cursor_kern; typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int,
struct xfs_da_args; char *, int, int, char *);
typedef struct xfs_attr_list_context {
struct xfs_inode *dp; /* inode */
struct attrlist_cursor_kern *cursor; /* position in list */
char *alist; /* output buffer */
int seen_enough; /* T/F: seen enough of list? */
ssize_t count; /* num used entries */
int dupcnt; /* count dup hashvals seen */
int bufsize; /* total buffer size */
int firstu; /* first used byte in buffer */
int flags; /* from VOP call */
int resynch; /* T/F: resynch with cursor */
int put_value; /* T/F: need value for listent */
put_listent_func_t put_listent; /* list output fmt function */
int index; /* index into output buffer */
} xfs_attr_list_context_t;
/*========================================================================
* Function prototypes for the kernel.
*========================================================================*/
/* /*
* Overall external interface routines. * Overall external interface routines.
*/ */
int xfs_attr_inactive(struct xfs_inode *dp); int xfs_attr_inactive(struct xfs_inode *dp);
int xfs_attr_shortform_getvalue(struct xfs_da_args *);
int xfs_attr_fetch(struct xfs_inode *, struct xfs_name *, char *, int *, int); int xfs_attr_fetch(struct xfs_inode *, struct xfs_name *, char *, int *, int);
int xfs_attr_rmtval_get(struct xfs_da_args *args); int xfs_attr_rmtval_get(struct xfs_da_args *args);
int xfs_attr_list_int(struct xfs_attr_list_context *);
#endif /* __XFS_ATTR_H__ */ #endif /* __XFS_ATTR_H__ */

View File

@ -94,13 +94,6 @@ STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
* Namespace helper routines * Namespace helper routines
*========================================================================*/ *========================================================================*/
STATIC_INLINE attrnames_t *
xfs_attr_flags_namesp(int flags)
{
return ((flags & XFS_ATTR_SECURE) ? &attr_secure:
((flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user));
}
/* /*
* If namespace bits don't match return 0. * If namespace bits don't match return 0.
* If all match then return 1. * If all match then return 1.
@ -111,25 +104,6 @@ xfs_attr_namesp_match(int arg_flags, int ondisk_flags)
return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags); return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags);
} }
/*
* If namespace bits don't match and we don't have an override for it
* then return 0.
* If all match or are overridable then return 1.
*/
STATIC_INLINE int
xfs_attr_namesp_match_overrides(int arg_flags, int ondisk_flags)
{
if (((arg_flags & ATTR_SECURE) == 0) !=
((ondisk_flags & XFS_ATTR_SECURE) == 0) &&
!(arg_flags & ATTR_KERNORMALS))
return 0;
if (((arg_flags & ATTR_ROOT) == 0) !=
((ondisk_flags & XFS_ATTR_ROOT) == 0) &&
!(arg_flags & ATTR_KERNROOTLS))
return 0;
return 1;
}
/*======================================================================== /*========================================================================
* External routines when attribute fork size < XFS_LITINO(mp). * External routines when attribute fork size < XFS_LITINO(mp).
@ -369,9 +343,10 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
* Fix up the start offset of the attribute fork * Fix up the start offset of the attribute fork
*/ */
totsize -= size; totsize -= size;
if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname && if (totsize == sizeof(xfs_attr_sf_hdr_t) &&
(mp->m_flags & XFS_MOUNT_ATTR2) && !(args->op_flags & XFS_DA_OP_ADDNAME) &&
(dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) { (mp->m_flags & XFS_MOUNT_ATTR2) &&
(dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) {
/* /*
* Last attribute now removed, revert to original * Last attribute now removed, revert to original
* inode format making all literal area available * inode format making all literal area available
@ -389,9 +364,10 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);
ASSERT(dp->i_d.di_forkoff); ASSERT(dp->i_d.di_forkoff);
ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname || ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) ||
!(mp->m_flags & XFS_MOUNT_ATTR2) || (args->op_flags & XFS_DA_OP_ADDNAME) ||
dp->i_d.di_format == XFS_DINODE_FMT_BTREE); !(mp->m_flags & XFS_MOUNT_ATTR2) ||
dp->i_d.di_format == XFS_DINODE_FMT_BTREE);
dp->i_afp->if_ext_max = dp->i_afp->if_ext_max =
XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
dp->i_df.if_ext_max = dp->i_df.if_ext_max =
@ -531,7 +507,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
nargs.total = args->total; nargs.total = args->total;
nargs.whichfork = XFS_ATTR_FORK; nargs.whichfork = XFS_ATTR_FORK;
nargs.trans = args->trans; nargs.trans = args->trans;
nargs.oknoent = 1; nargs.op_flags = XFS_DA_OP_OKNOENT;
sfe = &sf->list[0]; sfe = &sf->list[0];
for (i = 0; i < sf->hdr.count; i++) { for (i = 0; i < sf->hdr.count; i++) {
@ -555,7 +531,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
out: out:
if(bp) if(bp)
xfs_da_buf_done(bp); xfs_da_buf_done(bp);
kmem_free(tmpbuffer, size); kmem_free(tmpbuffer);
return(error); return(error);
} }
@ -624,15 +600,8 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
(XFS_ISRESET_CURSOR(cursor) && (XFS_ISRESET_CURSOR(cursor) &&
(dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) { (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
attrnames_t *namesp;
if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
continue;
}
namesp = xfs_attr_flags_namesp(sfe->flags);
error = context->put_listent(context, error = context->put_listent(context,
namesp, sfe->flags,
(char *)sfe->nameval, (char *)sfe->nameval,
(int)sfe->namelen, (int)sfe->namelen,
(int)sfe->valuelen, (int)sfe->valuelen,
@ -676,13 +645,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
XFS_ERRLEVEL_LOW, XFS_ERRLEVEL_LOW,
context->dp->i_mount, sfe); context->dp->i_mount, sfe);
xfs_attr_trace_l_c("sf corrupted", context); xfs_attr_trace_l_c("sf corrupted", context);
kmem_free(sbuf, sbsize); kmem_free(sbuf);
return XFS_ERROR(EFSCORRUPTED); return XFS_ERROR(EFSCORRUPTED);
} }
if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
continue;
}
sbp->entno = i; sbp->entno = i;
sbp->hash = xfs_da_hashname((char *)sfe->nameval, sfe->namelen); sbp->hash = xfs_da_hashname((char *)sfe->nameval, sfe->namelen);
sbp->name = (char *)sfe->nameval; sbp->name = (char *)sfe->nameval;
@ -717,7 +683,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
} }
} }
if (i == nsbuf) { if (i == nsbuf) {
kmem_free(sbuf, sbsize); kmem_free(sbuf);
xfs_attr_trace_l_c("blk end", context); xfs_attr_trace_l_c("blk end", context);
return(0); return(0);
} }
@ -726,16 +692,12 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
* Loop putting entries into the user buffer. * Loop putting entries into the user buffer.
*/ */
for ( ; i < nsbuf; i++, sbp++) { for ( ; i < nsbuf; i++, sbp++) {
attrnames_t *namesp;
namesp = xfs_attr_flags_namesp(sbp->flags);
if (cursor->hashval != sbp->hash) { if (cursor->hashval != sbp->hash) {
cursor->hashval = sbp->hash; cursor->hashval = sbp->hash;
cursor->offset = 0; cursor->offset = 0;
} }
error = context->put_listent(context, error = context->put_listent(context,
namesp, sbp->flags,
sbp->name, sbp->name,
sbp->namelen, sbp->namelen,
sbp->valuelen, sbp->valuelen,
@ -747,7 +709,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
cursor->offset++; cursor->offset++;
} }
kmem_free(sbuf, sbsize); kmem_free(sbuf);
xfs_attr_trace_l_c("sf E-O-F", context); xfs_attr_trace_l_c("sf E-O-F", context);
return(0); return(0);
} }
@ -853,7 +815,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
nargs.total = args->total; nargs.total = args->total;
nargs.whichfork = XFS_ATTR_FORK; nargs.whichfork = XFS_ATTR_FORK;
nargs.trans = args->trans; nargs.trans = args->trans;
nargs.oknoent = 1; nargs.op_flags = XFS_DA_OP_OKNOENT;
entry = &leaf->entries[0]; entry = &leaf->entries[0];
for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) { for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
if (entry->flags & XFS_ATTR_INCOMPLETE) if (entry->flags & XFS_ATTR_INCOMPLETE)
@ -873,7 +835,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
error = 0; error = 0;
out: out:
kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); kmem_free(tmpbuffer);
return(error); return(error);
} }
@ -1155,7 +1117,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
entry->hashval = cpu_to_be32(args->hashval); entry->hashval = cpu_to_be32(args->hashval);
entry->flags = tmp ? XFS_ATTR_LOCAL : 0; entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
if (args->rename) { if (args->op_flags & XFS_DA_OP_RENAME) {
entry->flags |= XFS_ATTR_INCOMPLETE; entry->flags |= XFS_ATTR_INCOMPLETE;
if ((args->blkno2 == args->blkno) && if ((args->blkno2 == args->blkno) &&
(args->index2 <= args->index)) { (args->index2 <= args->index)) {
@ -1271,7 +1233,7 @@ xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp)
be16_to_cpu(hdr_s->count), mp); be16_to_cpu(hdr_s->count), mp);
xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1); xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1);
kmem_free(tmpbuffer, XFS_LBSIZE(mp)); kmem_free(tmpbuffer);
} }
/* /*
@ -1921,7 +1883,7 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
be16_to_cpu(drop_hdr->count), mp); be16_to_cpu(drop_hdr->count), mp);
} }
memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize); memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize);
kmem_free(tmpbuffer, state->blocksize); kmem_free(tmpbuffer);
} }
xfs_da_log_buf(state->args->trans, save_blk->bp, 0, xfs_da_log_buf(state->args->trans, save_blk->bp, 0,
@ -2400,8 +2362,6 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
*/ */
retval = 0; retval = 0;
for ( ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) { for ( ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) {
attrnames_t *namesp;
if (be32_to_cpu(entry->hashval) != cursor->hashval) { if (be32_to_cpu(entry->hashval) != cursor->hashval) {
cursor->hashval = be32_to_cpu(entry->hashval); cursor->hashval = be32_to_cpu(entry->hashval);
cursor->offset = 0; cursor->offset = 0;
@ -2409,17 +2369,13 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
if (entry->flags & XFS_ATTR_INCOMPLETE) if (entry->flags & XFS_ATTR_INCOMPLETE)
continue; /* skip incomplete entries */ continue; /* skip incomplete entries */
if (!xfs_attr_namesp_match_overrides(context->flags, entry->flags))
continue;
namesp = xfs_attr_flags_namesp(entry->flags);
if (entry->flags & XFS_ATTR_LOCAL) { if (entry->flags & XFS_ATTR_LOCAL) {
xfs_attr_leaf_name_local_t *name_loc = xfs_attr_leaf_name_local_t *name_loc =
XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
retval = context->put_listent(context, retval = context->put_listent(context,
namesp, entry->flags,
(char *)name_loc->nameval, (char *)name_loc->nameval,
(int)name_loc->namelen, (int)name_loc->namelen,
be16_to_cpu(name_loc->valuelen), be16_to_cpu(name_loc->valuelen),
@ -2446,16 +2402,15 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
if (retval) if (retval)
return retval; return retval;
retval = context->put_listent(context, retval = context->put_listent(context,
namesp, entry->flags,
(char *)name_rmt->name, (char *)name_rmt->name,
(int)name_rmt->namelen, (int)name_rmt->namelen,
valuelen, valuelen,
(char*)args.value); (char*)args.value);
kmem_free(args.value, valuelen); kmem_free(args.value);
} } else {
else {
retval = context->put_listent(context, retval = context->put_listent(context,
namesp, entry->flags,
(char *)name_rmt->name, (char *)name_rmt->name,
(int)name_rmt->namelen, (int)name_rmt->namelen,
valuelen, valuelen,
@ -2954,7 +2909,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp)
error = tmp; /* save only the 1st errno */ error = tmp; /* save only the 1st errno */
} }
kmem_free((xfs_caddr_t)list, size); kmem_free((xfs_caddr_t)list);
return(error); return(error);
} }

View File

@ -30,7 +30,7 @@
struct attrlist; struct attrlist;
struct attrlist_cursor_kern; struct attrlist_cursor_kern;
struct attrnames; struct xfs_attr_list_context;
struct xfs_dabuf; struct xfs_dabuf;
struct xfs_da_args; struct xfs_da_args;
struct xfs_da_state; struct xfs_da_state;
@ -204,33 +204,6 @@ static inline int xfs_attr_leaf_entsize_local_max(int bsize)
return (((bsize) >> 1) + ((bsize) >> 2)); return (((bsize) >> 1) + ((bsize) >> 2));
} }
/*========================================================================
* Structure used to pass context around among the routines.
*========================================================================*/
struct xfs_attr_list_context;
typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, struct attrnames *,
char *, int, int, char *);
typedef struct xfs_attr_list_context {
struct xfs_inode *dp; /* inode */
struct attrlist_cursor_kern *cursor; /* position in list */
struct attrlist *alist; /* output buffer */
int seen_enough; /* T/F: seen enough of list? */
int count; /* num used entries */
int dupcnt; /* count dup hashvals seen */
int bufsize; /* total buffer size */
int firstu; /* first used byte in buffer */
int flags; /* from VOP call */
int resynch; /* T/F: resynch with cursor */
int put_value; /* T/F: need value for listent */
put_listent_func_t put_listent; /* list output fmt function */
int index; /* index into output buffer */
} xfs_attr_list_context_t;
/* /*
* Used to keep a list of "remote value" extents when unlinking an inode. * Used to keep a list of "remote value" extents when unlinking an inode.
*/ */

View File

@ -97,13 +97,9 @@ void xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context,
void xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, void xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
struct xfs_attr_leafblock *leaf); struct xfs_attr_leafblock *leaf);
void xfs_attr_trace_enter(int type, char *where, void xfs_attr_trace_enter(int type, char *where,
__psunsigned_t a2, __psunsigned_t a3, struct xfs_attr_list_context *context,
__psunsigned_t a4, __psunsigned_t a5, __psunsigned_t a13, __psunsigned_t a14,
__psunsigned_t a6, __psunsigned_t a7, __psunsigned_t a15);
__psunsigned_t a8, __psunsigned_t a9,
__psunsigned_t a10, __psunsigned_t a11,
__psunsigned_t a12, __psunsigned_t a13,
__psunsigned_t a14, __psunsigned_t a15);
#else #else
#define xfs_attr_trace_l_c(w,c) #define xfs_attr_trace_l_c(w,c)
#define xfs_attr_trace_l_cn(w,c,n) #define xfs_attr_trace_l_cn(w,c,n)

View File

@ -428,7 +428,8 @@ xfs_bmap_add_attrfork_btree(
cur->bc_private.b.firstblock = *firstblock; cur->bc_private.b.firstblock = *firstblock;
if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat))) if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat)))
goto error0; goto error0;
ASSERT(stat == 1); /* must be at least one entry */ /* must be at least one entry */
XFS_WANT_CORRUPTED_GOTO(stat == 1, error0);
if ((error = xfs_bmbt_newroot(cur, flags, &stat))) if ((error = xfs_bmbt_newroot(cur, flags, &stat)))
goto error0; goto error0;
if (stat == 0) { if (stat == 0) {
@ -816,13 +817,13 @@ xfs_bmap_add_extent_delay_real(
RIGHT.br_startblock, RIGHT.br_startblock,
RIGHT.br_blockcount, &i))) RIGHT.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i))) if ((error = xfs_bmbt_delete(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i))) if ((error = xfs_bmbt_decrement(cur, 0, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
LEFT.br_startblock, LEFT.br_startblock,
LEFT.br_blockcount + LEFT.br_blockcount +
@ -860,7 +861,7 @@ xfs_bmap_add_extent_delay_real(
LEFT.br_startblock, LEFT.br_blockcount, LEFT.br_startblock, LEFT.br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
LEFT.br_startblock, LEFT.br_startblock,
LEFT.br_blockcount + LEFT.br_blockcount +
@ -895,7 +896,7 @@ xfs_bmap_add_extent_delay_real(
RIGHT.br_startblock, RIGHT.br_startblock,
RIGHT.br_blockcount, &i))) RIGHT.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, PREV.br_startoff, if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
new->br_startblock, new->br_startblock,
PREV.br_blockcount + PREV.br_blockcount +
@ -928,11 +929,11 @@ xfs_bmap_add_extent_delay_real(
new->br_startblock, new->br_blockcount, new->br_startblock, new->br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 0); XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM; cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i))) if ((error = xfs_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
*dnew = 0; *dnew = 0;
/* DELTA: The in-core extent described by new changed type. */ /* DELTA: The in-core extent described by new changed type. */
@ -963,7 +964,7 @@ xfs_bmap_add_extent_delay_real(
LEFT.br_startblock, LEFT.br_blockcount, LEFT.br_startblock, LEFT.br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
LEFT.br_startblock, LEFT.br_startblock,
LEFT.br_blockcount + LEFT.br_blockcount +
@ -1004,11 +1005,11 @@ xfs_bmap_add_extent_delay_real(
new->br_startblock, new->br_blockcount, new->br_startblock, new->br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 0); XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM; cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i))) if ((error = xfs_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
ip->i_d.di_nextents > ip->i_df.if_ext_max) { ip->i_d.di_nextents > ip->i_df.if_ext_max) {
@ -1054,7 +1055,7 @@ xfs_bmap_add_extent_delay_real(
RIGHT.br_startblock, RIGHT.br_startblock,
RIGHT.br_blockcount, &i))) RIGHT.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, new->br_startoff, if ((error = xfs_bmbt_update(cur, new->br_startoff,
new->br_startblock, new->br_startblock,
new->br_blockcount + new->br_blockcount +
@ -1094,11 +1095,11 @@ xfs_bmap_add_extent_delay_real(
new->br_startblock, new->br_blockcount, new->br_startblock, new->br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 0); XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM; cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i))) if ((error = xfs_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
ip->i_d.di_nextents > ip->i_df.if_ext_max) { ip->i_d.di_nextents > ip->i_df.if_ext_max) {
@ -1149,11 +1150,11 @@ xfs_bmap_add_extent_delay_real(
new->br_startblock, new->br_blockcount, new->br_startblock, new->br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 0); XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM; cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i))) if ((error = xfs_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
ip->i_d.di_nextents > ip->i_df.if_ext_max) { ip->i_d.di_nextents > ip->i_df.if_ext_max) {
@ -1377,19 +1378,19 @@ xfs_bmap_add_extent_unwritten_real(
RIGHT.br_startblock, RIGHT.br_startblock,
RIGHT.br_blockcount, &i))) RIGHT.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i))) if ((error = xfs_bmbt_delete(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i))) if ((error = xfs_bmbt_decrement(cur, 0, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i))) if ((error = xfs_bmbt_delete(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i))) if ((error = xfs_bmbt_decrement(cur, 0, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
LEFT.br_startblock, LEFT.br_startblock,
LEFT.br_blockcount + PREV.br_blockcount + LEFT.br_blockcount + PREV.br_blockcount +
@ -1426,13 +1427,13 @@ xfs_bmap_add_extent_unwritten_real(
PREV.br_startblock, PREV.br_blockcount, PREV.br_startblock, PREV.br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i))) if ((error = xfs_bmbt_delete(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i))) if ((error = xfs_bmbt_decrement(cur, 0, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
LEFT.br_startblock, LEFT.br_startblock,
LEFT.br_blockcount + PREV.br_blockcount, LEFT.br_blockcount + PREV.br_blockcount,
@ -1469,13 +1470,13 @@ xfs_bmap_add_extent_unwritten_real(
RIGHT.br_startblock, RIGHT.br_startblock,
RIGHT.br_blockcount, &i))) RIGHT.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i))) if ((error = xfs_bmbt_delete(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i))) if ((error = xfs_bmbt_decrement(cur, 0, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, new->br_startoff, if ((error = xfs_bmbt_update(cur, new->br_startoff,
new->br_startblock, new->br_startblock,
new->br_blockcount + RIGHT.br_blockcount, new->br_blockcount + RIGHT.br_blockcount,
@ -1508,7 +1509,7 @@ xfs_bmap_add_extent_unwritten_real(
new->br_startblock, new->br_blockcount, new->br_startblock, new->br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, new->br_startoff, if ((error = xfs_bmbt_update(cur, new->br_startoff,
new->br_startblock, new->br_blockcount, new->br_startblock, new->br_blockcount,
newext))) newext)))
@ -1549,7 +1550,7 @@ xfs_bmap_add_extent_unwritten_real(
PREV.br_startblock, PREV.br_blockcount, PREV.br_startblock, PREV.br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, if ((error = xfs_bmbt_update(cur,
PREV.br_startoff + new->br_blockcount, PREV.br_startoff + new->br_blockcount,
PREV.br_startblock + new->br_blockcount, PREV.br_startblock + new->br_blockcount,
@ -1596,7 +1597,7 @@ xfs_bmap_add_extent_unwritten_real(
PREV.br_startblock, PREV.br_blockcount, PREV.br_startblock, PREV.br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, if ((error = xfs_bmbt_update(cur,
PREV.br_startoff + new->br_blockcount, PREV.br_startoff + new->br_blockcount,
PREV.br_startblock + new->br_blockcount, PREV.br_startblock + new->br_blockcount,
@ -1606,7 +1607,7 @@ xfs_bmap_add_extent_unwritten_real(
cur->bc_rec.b = *new; cur->bc_rec.b = *new;
if ((error = xfs_bmbt_insert(cur, &i))) if ((error = xfs_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
/* DELTA: One in-core extent is split in two. */ /* DELTA: One in-core extent is split in two. */
temp = PREV.br_startoff; temp = PREV.br_startoff;
@ -1640,7 +1641,7 @@ xfs_bmap_add_extent_unwritten_real(
PREV.br_startblock, PREV.br_startblock,
PREV.br_blockcount, &i))) PREV.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, PREV.br_startoff, if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
PREV.br_startblock, PREV.br_startblock,
PREV.br_blockcount - new->br_blockcount, PREV.br_blockcount - new->br_blockcount,
@ -1682,7 +1683,7 @@ xfs_bmap_add_extent_unwritten_real(
PREV.br_startblock, PREV.br_blockcount, PREV.br_startblock, PREV.br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, PREV.br_startoff, if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
PREV.br_startblock, PREV.br_startblock,
PREV.br_blockcount - new->br_blockcount, PREV.br_blockcount - new->br_blockcount,
@ -1692,11 +1693,11 @@ xfs_bmap_add_extent_unwritten_real(
new->br_startblock, new->br_blockcount, new->br_startblock, new->br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 0); XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = XFS_EXT_NORM; cur->bc_rec.b.br_state = XFS_EXT_NORM;
if ((error = xfs_bmbt_insert(cur, &i))) if ((error = xfs_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
/* DELTA: One in-core extent is split in two. */ /* DELTA: One in-core extent is split in two. */
temp = PREV.br_startoff; temp = PREV.br_startoff;
@ -1732,27 +1733,34 @@ xfs_bmap_add_extent_unwritten_real(
PREV.br_startblock, PREV.br_blockcount, PREV.br_startblock, PREV.br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
/* new right extent - oldext */ /* new right extent - oldext */
if ((error = xfs_bmbt_update(cur, r[1].br_startoff, if ((error = xfs_bmbt_update(cur, r[1].br_startoff,
r[1].br_startblock, r[1].br_blockcount, r[1].br_startblock, r[1].br_blockcount,
r[1].br_state))) r[1].br_state)))
goto done; goto done;
/* new left extent - oldext */ /* new left extent - oldext */
PREV.br_blockcount =
new->br_startoff - PREV.br_startoff;
cur->bc_rec.b = PREV; 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_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_increment(cur, 0, &i))) /*
* Reset the cursor to the position of the new extent
* we are about to insert as we can't trust it after
* the previous insert.
*/
if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
new->br_startblock, new->br_blockcount,
&i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 0, done);
/* new middle extent - newext */ /* new middle extent - newext */
cur->bc_rec.b = *new; cur->bc_rec.b.br_state = new->br_state;
if ((error = xfs_bmbt_insert(cur, &i))) if ((error = xfs_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
/* DELTA: One in-core extent is split in three. */ /* DELTA: One in-core extent is split in three. */
temp = PREV.br_startoff; temp = PREV.br_startoff;
@ -2097,13 +2105,13 @@ xfs_bmap_add_extent_hole_real(
right.br_startblock, right.br_startblock,
right.br_blockcount, &i))) right.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_delete(cur, &i))) if ((error = xfs_bmbt_delete(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_decrement(cur, 0, &i))) if ((error = xfs_bmbt_decrement(cur, 0, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, left.br_startoff, if ((error = xfs_bmbt_update(cur, left.br_startoff,
left.br_startblock, left.br_startblock,
left.br_blockcount + left.br_blockcount +
@ -2139,7 +2147,7 @@ xfs_bmap_add_extent_hole_real(
left.br_startblock, left.br_startblock,
left.br_blockcount, &i))) left.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, left.br_startoff, if ((error = xfs_bmbt_update(cur, left.br_startoff,
left.br_startblock, left.br_startblock,
left.br_blockcount + left.br_blockcount +
@ -2174,7 +2182,7 @@ xfs_bmap_add_extent_hole_real(
right.br_startblock, right.br_startblock,
right.br_blockcount, &i))) right.br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
if ((error = xfs_bmbt_update(cur, new->br_startoff, if ((error = xfs_bmbt_update(cur, new->br_startoff,
new->br_startblock, new->br_startblock,
new->br_blockcount + new->br_blockcount +
@ -2208,11 +2216,11 @@ xfs_bmap_add_extent_hole_real(
new->br_startblock, new->br_startblock,
new->br_blockcount, &i))) new->br_blockcount, &i)))
goto done; goto done;
ASSERT(i == 0); XFS_WANT_CORRUPTED_GOTO(i == 0, done);
cur->bc_rec.b.br_state = new->br_state; cur->bc_rec.b.br_state = new->br_state;
if ((error = xfs_bmbt_insert(cur, &i))) if ((error = xfs_bmbt_insert(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
/* DELTA: A new extent was added in a hole. */ /* DELTA: A new extent was added in a hole. */
temp = new->br_startoff; temp = new->br_startoff;
@ -3131,7 +3139,7 @@ xfs_bmap_del_extent(
got.br_startblock, got.br_blockcount, got.br_startblock, got.br_blockcount,
&i))) &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} }
da_old = da_new = 0; da_old = da_new = 0;
} else { } else {
@ -3164,7 +3172,7 @@ xfs_bmap_del_extent(
} }
if ((error = xfs_bmbt_delete(cur, &i))) if ((error = xfs_bmbt_delete(cur, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
break; break;
case 2: case 2:
@ -3268,7 +3276,7 @@ xfs_bmap_del_extent(
got.br_startblock, got.br_startblock,
temp, &i))) temp, &i)))
goto done; goto done;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
/* /*
* Update the btree record back * Update the btree record back
* to the original value. * to the original value.
@ -3289,7 +3297,7 @@ xfs_bmap_del_extent(
error = XFS_ERROR(ENOSPC); error = XFS_ERROR(ENOSPC);
goto done; goto done;
} }
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, done);
} else } else
flags |= XFS_ILOG_FEXT(whichfork); flags |= XFS_ILOG_FEXT(whichfork);
XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXT_SET(ip, whichfork,
@ -5970,7 +5978,7 @@ unlock_and_return:
xfs_iunlock_map_shared(ip, lock); xfs_iunlock_map_shared(ip, lock);
xfs_iunlock(ip, XFS_IOLOCK_SHARED); xfs_iunlock(ip, XFS_IOLOCK_SHARED);
kmem_free(map, subnex * sizeof(*map)); kmem_free(map);
return error; return error;
} }

View File

@ -54,12 +54,23 @@ typedef struct xfs_bmap_free_item
/* /*
* Header for free extent list. * Header for free extent list.
*
* xbf_low is used by the allocator to activate the lowspace algorithm -
* when free space is running low the extent allocator may choose to
* allocate an extent from an AG without leaving sufficient space for
* a btree split when inserting the new extent. In this case the allocator
* will enable the lowspace algorithm which is supposed to allow further
* allocations (such as btree splits and newroots) to allocate from
* sequential AGs. In order to avoid locking AGs out of order the lowspace
* algorithm will start searching for free space from AG 0. If the correct
* transaction reservations have been made then this algorithm will eventually
* find all the space it needs.
*/ */
typedef struct xfs_bmap_free typedef struct xfs_bmap_free
{ {
xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */ xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */
int xbf_count; /* count of items on list */ int xbf_count; /* count of items on list */
int xbf_low; /* kludge: alloc in low mode */ int xbf_low; /* alloc in low mode */
} xfs_bmap_free_t; } xfs_bmap_free_t;
#define XFS_BMAP_MAX_NMAP 4 #define XFS_BMAP_MAX_NMAP 4

View File

@ -1493,12 +1493,27 @@ xfs_bmbt_split(
left = XFS_BUF_TO_BMBT_BLOCK(lbp); left = XFS_BUF_TO_BMBT_BLOCK(lbp);
args.fsbno = cur->bc_private.b.firstblock; args.fsbno = cur->bc_private.b.firstblock;
args.firstblock = args.fsbno; args.firstblock = args.fsbno;
args.minleft = 0;
if (args.fsbno == NULLFSBLOCK) { if (args.fsbno == NULLFSBLOCK) {
args.fsbno = lbno; args.fsbno = lbno;
args.type = XFS_ALLOCTYPE_START_BNO; args.type = XFS_ALLOCTYPE_START_BNO;
} else /*
* Make sure there is sufficient room left in the AG to
* complete a full tree split for an extent insert. If
* we are converting the middle part of an extent then
* we may need space for two tree splits.
*
* We are relying on the caller to make the correct block
* reservation for this operation to succeed. If the
* reservation amount is insufficient then we may fail a
* block allocation here and corrupt the filesystem.
*/
args.minleft = xfs_trans_get_block_res(args.tp);
} else if (cur->bc_private.b.flist->xbf_low)
args.type = XFS_ALLOCTYPE_START_BNO;
else
args.type = XFS_ALLOCTYPE_NEAR_BNO; args.type = XFS_ALLOCTYPE_NEAR_BNO;
args.mod = args.minleft = args.alignment = args.total = args.isfl = args.mod = args.alignment = args.total = args.isfl =
args.userdata = args.minalignslop = 0; args.userdata = args.minalignslop = 0;
args.minlen = args.maxlen = args.prod = 1; args.minlen = args.maxlen = args.prod = 1;
args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL;
@ -1510,6 +1525,21 @@ xfs_bmbt_split(
XFS_BMBT_TRACE_CURSOR(cur, ERROR); XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error; return error;
} }
if (args.fsbno == NULLFSBLOCK && args.minleft) {
/*
* Could not find an AG with enough free space to satisfy
* a full btree split. Try again without minleft and if
* successful activate the lowspace algorithm.
*/
args.fsbno = 0;
args.type = XFS_ALLOCTYPE_FIRST_AG;
args.minleft = 0;
if ((error = xfs_alloc_vextent(&args))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
cur->bc_private.b.flist->xbf_low = 1;
}
if (args.fsbno == NULLFSBLOCK) { if (args.fsbno == NULLFSBLOCK) {
XFS_BMBT_TRACE_CURSOR(cur, EXIT); XFS_BMBT_TRACE_CURSOR(cur, EXIT);
*stat = 0; *stat = 0;
@ -2029,22 +2059,8 @@ xfs_bmbt_increment(
* Insert the current record at the point referenced by cur. * Insert the current record at the point referenced by cur.
* *
* A multi-level split of the tree on insert will invalidate the original * A multi-level split of the tree on insert will invalidate the original
* cursor. It appears, however, that some callers assume that the cursor is * cursor. All callers of this function should assume that the cursor is
* always valid. Hence if we do a multi-level split we need to revalidate the * no longer valid and revalidate it.
* cursor.
*
* When a split occurs, we will see a new cursor returned. Use that as a
* trigger to determine if we need to revalidate the original cursor. If we get
* a split, then use the original irec to lookup up the path of the record we
* just inserted.
*
* Note that the fact that the btree root is in the inode means that we can
* have the level of the tree change without a "split" occurring at the root
* level. What happens is that the root is migrated to an allocated block and
* the inode root is pointed to it. This means a single split can change the
* level of the tree (level 2 -> level 3) and invalidate the old cursor. Hence
* the level change should be accounted as a split so as to correctly trigger a
* revalidation of the old cursor.
*/ */
int /* error */ int /* error */
xfs_bmbt_insert( xfs_bmbt_insert(
@ -2057,14 +2073,11 @@ xfs_bmbt_insert(
xfs_fsblock_t nbno; xfs_fsblock_t nbno;
xfs_btree_cur_t *ncur; xfs_btree_cur_t *ncur;
xfs_bmbt_rec_t nrec; xfs_bmbt_rec_t nrec;
xfs_bmbt_irec_t oirec; /* original irec */
xfs_btree_cur_t *pcur; xfs_btree_cur_t *pcur;
int splits = 0;
XFS_BMBT_TRACE_CURSOR(cur, ENTRY); XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
level = 0; level = 0;
nbno = NULLFSBLOCK; nbno = NULLFSBLOCK;
oirec = cur->bc_rec.b;
xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b); xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b);
ncur = NULL; ncur = NULL;
pcur = cur; pcur = cur;
@ -2073,13 +2086,11 @@ xfs_bmbt_insert(
&i))) { &i))) {
if (pcur != cur) if (pcur != cur)
xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR);
goto error0; XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
} }
XFS_WANT_CORRUPTED_GOTO(i == 1, error0); XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) {
/* allocating a new root is effectively a split */
if (cur->bc_nlevels != pcur->bc_nlevels)
splits++;
cur->bc_nlevels = pcur->bc_nlevels; cur->bc_nlevels = pcur->bc_nlevels;
cur->bc_private.b.allocated += cur->bc_private.b.allocated +=
pcur->bc_private.b.allocated; pcur->bc_private.b.allocated;
@ -2093,21 +2104,10 @@ xfs_bmbt_insert(
xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR);
} }
if (ncur) { if (ncur) {
splits++;
pcur = ncur; pcur = ncur;
ncur = NULL; ncur = NULL;
} }
} while (nbno != NULLFSBLOCK); } while (nbno != NULLFSBLOCK);
if (splits > 1) {
/* revalidate the old cursor as we had a multi-level split */
error = xfs_bmbt_lookup_eq(cur, oirec.br_startoff,
oirec.br_startblock, oirec.br_blockcount, &i);
if (error)
goto error0;
ASSERT(i == 1);
}
XFS_BMBT_TRACE_CURSOR(cur, EXIT); XFS_BMBT_TRACE_CURSOR(cur, EXIT);
*stat = i; *stat = i;
return 0; return 0;
@ -2254,7 +2254,9 @@ xfs_bmbt_newroot(
#endif #endif
args.fsbno = be64_to_cpu(*pp); args.fsbno = be64_to_cpu(*pp);
args.type = XFS_ALLOCTYPE_START_BNO; args.type = XFS_ALLOCTYPE_START_BNO;
} else } else if (cur->bc_private.b.flist->xbf_low)
args.type = XFS_ALLOCTYPE_START_BNO;
else
args.type = XFS_ALLOCTYPE_NEAR_BNO; args.type = XFS_ALLOCTYPE_NEAR_BNO;
if ((error = xfs_alloc_vextent(&args))) { if ((error = xfs_alloc_vextent(&args))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR); XFS_BMBT_TRACE_CURSOR(cur, ERROR);

View File

@ -889,9 +889,9 @@ xfs_buf_item_relse(
} }
#ifdef XFS_TRANS_DEBUG #ifdef XFS_TRANS_DEBUG
kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); kmem_free(bip->bli_orig);
bip->bli_orig = NULL; bip->bli_orig = NULL;
kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); kmem_free(bip->bli_logged);
bip->bli_logged = NULL; bip->bli_logged = NULL;
#endif /* XFS_TRANS_DEBUG */ #endif /* XFS_TRANS_DEBUG */
@ -1138,9 +1138,9 @@ xfs_buf_iodone(
xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip); xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip);
#ifdef XFS_TRANS_DEBUG #ifdef XFS_TRANS_DEBUG
kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); kmem_free(bip->bli_orig);
bip->bli_orig = NULL; bip->bli_orig = NULL;
kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); kmem_free(bip->bli_logged);
bip->bli_logged = NULL; bip->bli_logged = NULL;
#endif /* XFS_TRANS_DEBUG */ #endif /* XFS_TRANS_DEBUG */

View File

@ -78,6 +78,7 @@ struct xfs_mount_args {
#define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */ #define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */
#define XFSMNT_OSYNCISOSYNC 0x00004000 /* o_sync is REALLY o_sync */ #define XFSMNT_OSYNCISOSYNC 0x00004000 /* o_sync is REALLY o_sync */
/* (osyncisdsync is default) */ /* (osyncisdsync is default) */
#define XFSMNT_NOATTR2 0x00008000 /* turn off ATTR2 EA format */
#define XFSMNT_32BITINODES 0x00200000 /* restrict inodes to 32 #define XFSMNT_32BITINODES 0x00200000 /* restrict inodes to 32
* bits of address space */ * bits of address space */
#define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */ #define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */

View File

@ -1431,7 +1431,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
} }
if (level < 0) { if (level < 0) {
*result = XFS_ERROR(ENOENT); /* we're out of our tree */ *result = XFS_ERROR(ENOENT); /* we're out of our tree */
ASSERT(args->oknoent); ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
return(0); return(0);
} }
@ -1530,6 +1530,28 @@ xfs_da_hashname(const uchar_t *name, int namelen)
} }
} }
enum xfs_dacmp
xfs_da_compname(
struct xfs_da_args *args,
const char *name,
int len)
{
return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
}
static xfs_dahash_t
xfs_default_hashname(
struct xfs_name *name)
{
return xfs_da_hashname(name->name, name->len);
}
const struct xfs_nameops xfs_default_nameops = {
.hashname = xfs_default_hashname,
.compname = xfs_da_compname
};
/* /*
* Add a block to the btree ahead of the file. * Add a block to the btree ahead of the file.
* Return the new block number to the caller. * Return the new block number to the caller.
@ -1598,7 +1620,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
args->firstblock, args->total, args->firstblock, args->total,
&mapp[mapi], &nmap, args->flist, &mapp[mapi], &nmap, args->flist,
NULL))) { NULL))) {
kmem_free(mapp, sizeof(*mapp) * count); kmem_free(mapp);
return error; return error;
} }
if (nmap < 1) if (nmap < 1)
@ -1620,11 +1642,11 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
bno + count) { bno + count) {
if (mapp != &map) if (mapp != &map)
kmem_free(mapp, sizeof(*mapp) * count); kmem_free(mapp);
return XFS_ERROR(ENOSPC); return XFS_ERROR(ENOSPC);
} }
if (mapp != &map) if (mapp != &map)
kmem_free(mapp, sizeof(*mapp) * count); kmem_free(mapp);
*new_blkno = (xfs_dablk_t)bno; *new_blkno = (xfs_dablk_t)bno;
return 0; return 0;
} }
@ -2090,10 +2112,10 @@ xfs_da_do_buf(
} }
} }
if (bplist) { if (bplist) {
kmem_free(bplist, sizeof(*bplist) * nmap); kmem_free(bplist);
} }
if (mapp != &map) { if (mapp != &map) {
kmem_free(mapp, sizeof(*mapp) * nfsb); kmem_free(mapp);
} }
if (bpp) if (bpp)
*bpp = rbp; *bpp = rbp;
@ -2102,11 +2124,11 @@ exit1:
if (bplist) { if (bplist) {
for (i = 0; i < nbplist; i++) for (i = 0; i < nbplist; i++)
xfs_trans_brelse(trans, bplist[i]); xfs_trans_brelse(trans, bplist[i]);
kmem_free(bplist, sizeof(*bplist) * nmap); kmem_free(bplist);
} }
exit0: exit0:
if (mapp != &map) if (mapp != &map)
kmem_free(mapp, sizeof(*mapp) * nfsb); kmem_free(mapp);
if (bpp) if (bpp)
*bpp = NULL; *bpp = NULL;
return error; return error;
@ -2218,7 +2240,7 @@ xfs_da_state_free(xfs_da_state_t *state)
#ifdef XFS_DABUF_DEBUG #ifdef XFS_DABUF_DEBUG
xfs_dabuf_t *xfs_dabuf_global_list; xfs_dabuf_t *xfs_dabuf_global_list;
spinlock_t xfs_dabuf_global_lock; static DEFINE_SPINLOCK(xfs_dabuf_global_lock);
#endif #endif
/* /*
@ -2315,7 +2337,7 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf)
if (dabuf->dirty) if (dabuf->dirty)
xfs_da_buf_clean(dabuf); xfs_da_buf_clean(dabuf);
if (dabuf->nbuf > 1) if (dabuf->nbuf > 1)
kmem_free(dabuf->data, BBTOB(dabuf->bbcount)); kmem_free(dabuf->data);
#ifdef XFS_DABUF_DEBUG #ifdef XFS_DABUF_DEBUG
{ {
spin_lock(&xfs_dabuf_global_lock); spin_lock(&xfs_dabuf_global_lock);
@ -2332,7 +2354,7 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf)
if (dabuf->nbuf == 1) if (dabuf->nbuf == 1)
kmem_zone_free(xfs_dabuf_zone, dabuf); kmem_zone_free(xfs_dabuf_zone, dabuf);
else else
kmem_free(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf)); kmem_free(dabuf);
} }
/* /*
@ -2403,7 +2425,7 @@ xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
for (i = 0; i < nbuf; i++) for (i = 0; i < nbuf; i++)
xfs_trans_brelse(tp, bplist[i]); xfs_trans_brelse(tp, bplist[i]);
if (bplist != &bp) if (bplist != &bp)
kmem_free(bplist, nbuf * sizeof(*bplist)); kmem_free(bplist);
} }
/* /*
@ -2429,7 +2451,7 @@ xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
for (i = 0; i < nbuf; i++) for (i = 0; i < nbuf; i++)
xfs_trans_binval(tp, bplist[i]); xfs_trans_binval(tp, bplist[i]);
if (bplist != &bp) if (bplist != &bp)
kmem_free(bplist, nbuf * sizeof(*bplist)); kmem_free(bplist);
} }
/* /*

View File

@ -98,6 +98,15 @@ typedef struct xfs_da_node_entry xfs_da_node_entry_t;
* Btree searching and modification structure definitions. * Btree searching and modification structure definitions.
*========================================================================*/ *========================================================================*/
/*
* Search comparison results
*/
enum xfs_dacmp {
XFS_CMP_DIFFERENT, /* names are completely different */
XFS_CMP_EXACT, /* names are exactly the same */
XFS_CMP_CASE /* names are same but differ in case */
};
/* /*
* Structure to ease passing around component names. * Structure to ease passing around component names.
*/ */
@ -123,12 +132,19 @@ typedef struct xfs_da_args {
int index2; /* index of 2nd attr in blk */ int index2; /* index of 2nd attr in blk */
xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */
int rmtblkcnt2; /* remote attr value block count */ int rmtblkcnt2; /* remote attr value block count */
unsigned char justcheck; /* T/F: check for ok with no space */ int op_flags; /* operation flags */
unsigned char rename; /* T/F: this is an atomic rename op */ enum xfs_dacmp cmpresult; /* name compare result for lookups */
unsigned char addname; /* T/F: this is an add operation */
unsigned char oknoent; /* T/F: ok to return ENOENT, else die */
} xfs_da_args_t; } xfs_da_args_t;
/*
* Operation flags:
*/
#define XFS_DA_OP_JUSTCHECK 0x0001 /* check for ok with no space */
#define XFS_DA_OP_RENAME 0x0002 /* this is an atomic rename op */
#define XFS_DA_OP_ADDNAME 0x0004 /* this is an add operation */
#define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */
#define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */
/* /*
* Structure to describe buffer(s) for a block. * Structure to describe buffer(s) for a block.
* This is needed in the directory version 2 format case, when * This is needed in the directory version 2 format case, when
@ -201,6 +217,14 @@ typedef struct xfs_da_state {
(uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \
(uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1)
/*
* Name ops for directory and/or attr name operations
*/
struct xfs_nameops {
xfs_dahash_t (*hashname)(struct xfs_name *);
enum xfs_dacmp (*compname)(struct xfs_da_args *, const char *, int);
};
#ifdef __KERNEL__ #ifdef __KERNEL__
/*======================================================================== /*========================================================================
@ -249,6 +273,10 @@ int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
xfs_dabuf_t *dead_buf); xfs_dabuf_t *dead_buf);
uint xfs_da_hashname(const uchar_t *name_string, int name_length); uint xfs_da_hashname(const uchar_t *name_string, int name_length);
enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args,
const char *name, int len);
xfs_da_state_t *xfs_da_state_alloc(void); xfs_da_state_t *xfs_da_state_alloc(void);
void xfs_da_state_free(xfs_da_state_t *state); void xfs_da_state_free(xfs_da_state_t *state);

View File

@ -116,7 +116,7 @@ xfs_swapext(
out_put_file: out_put_file:
fput(file); fput(file);
out_free_sxp: out_free_sxp:
kmem_free(sxp, sizeof(xfs_swapext_t)); kmem_free(sxp);
out: out:
return error; return error;
} }
@ -381,6 +381,6 @@ xfs_swap_extents(
xfs_iunlock(tip, lock_flags); xfs_iunlock(tip, lock_flags);
} }
if (tempifp != NULL) if (tempifp != NULL)
kmem_free(tempifp, sizeof(xfs_ifork_t)); kmem_free(tempifp);
return error; return error;
} }

View File

@ -46,6 +46,54 @@
struct xfs_name xfs_name_dotdot = {"..", 2}; struct xfs_name xfs_name_dotdot = {"..", 2};
extern const struct xfs_nameops xfs_default_nameops;
/*
* ASCII case-insensitive (ie. A-Z) support for directories that was
* used in IRIX.
*/
STATIC xfs_dahash_t
xfs_ascii_ci_hashname(
struct xfs_name *name)
{
xfs_dahash_t hash;
int i;
for (i = 0, hash = 0; i < name->len; i++)
hash = tolower(name->name[i]) ^ rol32(hash, 7);
return hash;
}
STATIC enum xfs_dacmp
xfs_ascii_ci_compname(
struct xfs_da_args *args,
const char *name,
int len)
{
enum xfs_dacmp result;
int i;
if (args->namelen != len)
return XFS_CMP_DIFFERENT;
result = XFS_CMP_EXACT;
for (i = 0; i < len; i++) {
if (args->name[i] == name[i])
continue;
if (tolower(args->name[i]) != tolower(name[i]))
return XFS_CMP_DIFFERENT;
result = XFS_CMP_CASE;
}
return result;
}
static struct xfs_nameops xfs_ascii_ci_nameops = {
.hashname = xfs_ascii_ci_hashname,
.compname = xfs_ascii_ci_compname,
};
void void
xfs_dir_mount( xfs_dir_mount(
xfs_mount_t *mp) xfs_mount_t *mp)
@ -65,6 +113,10 @@ xfs_dir_mount(
(mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
(uint)sizeof(xfs_da_node_entry_t); (uint)sizeof(xfs_da_node_entry_t);
mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
if (xfs_sb_version_hasasciici(&mp->m_sb))
mp->m_dirnameops = &xfs_ascii_ci_nameops;
else
mp->m_dirnameops = &xfs_default_nameops;
} }
/* /*
@ -162,9 +214,10 @@ xfs_dir_createname(
return rval; return rval;
XFS_STATS_INC(xs_dir_create); XFS_STATS_INC(xs_dir_create);
memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = inum; args.inumber = inum;
args.dp = dp; args.dp = dp;
args.firstblock = first; args.firstblock = first;
@ -172,8 +225,7 @@ xfs_dir_createname(
args.total = total; args.total = total;
args.whichfork = XFS_DATA_FORK; args.whichfork = XFS_DATA_FORK;
args.trans = tp; args.trans = tp;
args.justcheck = 0; args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
args.addname = args.oknoent = 1;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_addname(&args); rval = xfs_dir2_sf_addname(&args);
@ -191,14 +243,43 @@ xfs_dir_createname(
} }
/* /*
* Lookup a name in a directory, give back the inode number. * If doing a CI lookup and case-insensitive match, dup actual name into
* args.value. Return EEXIST for success (ie. name found) or an error.
*/ */
int int
xfs_dir_cilookup_result(
struct xfs_da_args *args,
const char *name,
int len)
{
if (args->cmpresult == XFS_CMP_DIFFERENT)
return ENOENT;
if (args->cmpresult != XFS_CMP_CASE ||
!(args->op_flags & XFS_DA_OP_CILOOKUP))
return EEXIST;
args->value = kmem_alloc(len, KM_MAYFAIL);
if (!args->value)
return ENOMEM;
memcpy(args->value, name, len);
args->valuelen = len;
return EEXIST;
}
/*
* Lookup a name in a directory, give back the inode number.
* If ci_name is not NULL, returns the actual name in ci_name if it differs
* to name, or ci_name->name is set to NULL for an exact match.
*/
int
xfs_dir_lookup( xfs_dir_lookup(
xfs_trans_t *tp, xfs_trans_t *tp,
xfs_inode_t *dp, xfs_inode_t *dp,
struct xfs_name *name, struct xfs_name *name,
xfs_ino_t *inum) /* out: inode number */ xfs_ino_t *inum, /* out: inode number */
struct xfs_name *ci_name) /* out: actual name if CI match */
{ {
xfs_da_args_t args; xfs_da_args_t args;
int rval; int rval;
@ -206,15 +287,17 @@ xfs_dir_lookup(
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
XFS_STATS_INC(xs_dir_lookup); XFS_STATS_INC(xs_dir_lookup);
memset(&args, 0, sizeof(xfs_da_args_t));
memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.dp = dp; args.dp = dp;
args.whichfork = XFS_DATA_FORK; args.whichfork = XFS_DATA_FORK;
args.trans = tp; args.trans = tp;
args.oknoent = 1; args.op_flags = XFS_DA_OP_OKNOENT;
if (ci_name)
args.op_flags |= XFS_DA_OP_CILOOKUP;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_lookup(&args); rval = xfs_dir2_sf_lookup(&args);
@ -230,8 +313,13 @@ xfs_dir_lookup(
rval = xfs_dir2_node_lookup(&args); rval = xfs_dir2_node_lookup(&args);
if (rval == EEXIST) if (rval == EEXIST)
rval = 0; rval = 0;
if (rval == 0) if (!rval) {
*inum = args.inumber; *inum = args.inumber;
if (ci_name) {
ci_name->name = args.value;
ci_name->len = args.valuelen;
}
}
return rval; return rval;
} }
@ -255,9 +343,10 @@ xfs_dir_removename(
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
XFS_STATS_INC(xs_dir_remove); XFS_STATS_INC(xs_dir_remove);
memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = ino; args.inumber = ino;
args.dp = dp; args.dp = dp;
args.firstblock = first; args.firstblock = first;
@ -265,7 +354,6 @@ xfs_dir_removename(
args.total = total; args.total = total;
args.whichfork = XFS_DATA_FORK; args.whichfork = XFS_DATA_FORK;
args.trans = tp; args.trans = tp;
args.justcheck = args.addname = args.oknoent = 0;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_removename(&args); rval = xfs_dir2_sf_removename(&args);
@ -338,9 +426,10 @@ xfs_dir_replace(
if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
return rval; return rval;
memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = inum; args.inumber = inum;
args.dp = dp; args.dp = dp;
args.firstblock = first; args.firstblock = first;
@ -348,7 +437,6 @@ xfs_dir_replace(
args.total = total; args.total = total;
args.whichfork = XFS_DATA_FORK; args.whichfork = XFS_DATA_FORK;
args.trans = tp; args.trans = tp;
args.justcheck = args.addname = args.oknoent = 0;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_replace(&args); rval = xfs_dir2_sf_replace(&args);
@ -384,15 +472,16 @@ xfs_dir_canenter(
return 0; return 0;
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
memset(&args, 0, sizeof(xfs_da_args_t));
memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.hashval = xfs_da_hashname(name->name, name->len); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.dp = dp; args.dp = dp;
args.whichfork = XFS_DATA_FORK; args.whichfork = XFS_DATA_FORK;
args.trans = tp; args.trans = tp;
args.justcheck = args.addname = args.oknoent = 1; args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
XFS_DA_OP_OKNOENT;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_addname(&args); rval = xfs_dir2_sf_addname(&args);
@ -493,7 +582,7 @@ xfs_dir2_grow_inode(
args->firstblock, args->total, args->firstblock, args->total,
&mapp[mapi], &nmap, args->flist, &mapp[mapi], &nmap, args->flist,
NULL))) { NULL))) {
kmem_free(mapp, sizeof(*mapp) * count); kmem_free(mapp);
return error; return error;
} }
if (nmap < 1) if (nmap < 1)
@ -525,14 +614,14 @@ xfs_dir2_grow_inode(
mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
bno + count) { bno + count) {
if (mapp != &map) if (mapp != &map)
kmem_free(mapp, sizeof(*mapp) * count); kmem_free(mapp);
return XFS_ERROR(ENOSPC); return XFS_ERROR(ENOSPC);
} }
/* /*
* Done with the temporary mapping table. * Done with the temporary mapping table.
*/ */
if (mapp != &map) if (mapp != &map)
kmem_free(mapp, sizeof(*mapp) * count); kmem_free(mapp);
*dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
/* /*
* Update file's size if this is the data space and it grew. * Update file's size if this is the data space and it grew.

View File

@ -74,7 +74,8 @@ extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_fsblock_t *first, xfs_fsblock_t *first,
struct xfs_bmap_free *flist, xfs_extlen_t tot); struct xfs_bmap_free *flist, xfs_extlen_t tot);
extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name, xfs_ino_t *inum); struct xfs_name *name, xfs_ino_t *inum,
struct xfs_name *ci_name);
extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name, xfs_ino_t ino, struct xfs_name *name, xfs_ino_t ino,
xfs_fsblock_t *first, xfs_fsblock_t *first,
@ -99,4 +100,7 @@ extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp,
extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
struct xfs_dabuf *bp); struct xfs_dabuf *bp);
extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const char *name,
int len);
#endif /* __XFS_DIR2_H__ */ #endif /* __XFS_DIR2_H__ */

View File

@ -215,7 +215,7 @@ xfs_dir2_block_addname(
/* /*
* If this isn't a real add, we're done with the buffer. * If this isn't a real add, we're done with the buffer.
*/ */
if (args->justcheck) if (args->op_flags & XFS_DA_OP_JUSTCHECK)
xfs_da_brelse(tp, bp); xfs_da_brelse(tp, bp);
/* /*
* If we don't have space for the new entry & leaf ... * If we don't have space for the new entry & leaf ...
@ -225,7 +225,7 @@ xfs_dir2_block_addname(
* Not trying to actually do anything, or don't have * Not trying to actually do anything, or don't have
* a space reservation: return no-space. * a space reservation: return no-space.
*/ */
if (args->justcheck || args->total == 0) if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
return XFS_ERROR(ENOSPC); return XFS_ERROR(ENOSPC);
/* /*
* Convert to the next larger format. * Convert to the next larger format.
@ -240,7 +240,7 @@ xfs_dir2_block_addname(
/* /*
* Just checking, and it would work, so say so. * Just checking, and it would work, so say so.
*/ */
if (args->justcheck) if (args->op_flags & XFS_DA_OP_JUSTCHECK)
return 0; return 0;
needlog = needscan = 0; needlog = needscan = 0;
/* /*
@ -610,14 +610,15 @@ xfs_dir2_block_lookup(
/* /*
* Get the offset from the leaf entry, to point to the data. * Get the offset from the leaf entry, to point to the data.
*/ */
dep = (xfs_dir2_data_entry_t *) dep = (xfs_dir2_data_entry_t *)((char *)block +
((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address))); xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
/* /*
* Fill in inode number, release the block. * Fill in inode number, CI name if appropriate, release the block.
*/ */
args->inumber = be64_to_cpu(dep->inumber); args->inumber = be64_to_cpu(dep->inumber);
error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
xfs_da_brelse(args->trans, bp); xfs_da_brelse(args->trans, bp);
return XFS_ERROR(EEXIST); return XFS_ERROR(error);
} }
/* /*
@ -643,6 +644,7 @@ xfs_dir2_block_lookup_int(
int mid; /* binary search current idx */ int mid; /* binary search current idx */
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_trans_t *tp; /* transaction pointer */ xfs_trans_t *tp; /* transaction pointer */
enum xfs_dacmp cmp; /* comparison result */
dp = args->dp; dp = args->dp;
tp = args->trans; tp = args->trans;
@ -673,7 +675,7 @@ xfs_dir2_block_lookup_int(
else else
high = mid - 1; high = mid - 1;
if (low > high) { if (low > high) {
ASSERT(args->oknoent); ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
xfs_da_brelse(tp, bp); xfs_da_brelse(tp, bp);
return XFS_ERROR(ENOENT); return XFS_ERROR(ENOENT);
} }
@ -697,20 +699,31 @@ xfs_dir2_block_lookup_int(
dep = (xfs_dir2_data_entry_t *) dep = (xfs_dir2_data_entry_t *)
((char *)block + xfs_dir2_dataptr_to_off(mp, addr)); ((char *)block + xfs_dir2_dataptr_to_off(mp, addr));
/* /*
* Compare, if it's right give back buffer & entry number. * Compare name and if it's an exact match, return the index
* and buffer. If it's the first case-insensitive match, store
* the index and buffer and continue looking for an exact match.
*/ */
if (dep->namelen == args->namelen && cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
dep->name[0] == args->name[0] && if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
memcmp(dep->name, args->name, args->namelen) == 0) { args->cmpresult = cmp;
*bpp = bp; *bpp = bp;
*entno = mid; *entno = mid;
return 0; if (cmp == XFS_CMP_EXACT)
return 0;
} }
} while (++mid < be32_to_cpu(btp->count) && be32_to_cpu(blp[mid].hashval) == hash); } while (++mid < be32_to_cpu(btp->count) &&
be32_to_cpu(blp[mid].hashval) == hash);
ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
/*
* Here, we can only be doing a lookup (not a rename or replace).
* If a case-insensitive match was found earlier, return success.
*/
if (args->cmpresult == XFS_CMP_CASE)
return 0;
/* /*
* No match, release the buffer and return ENOENT. * No match, release the buffer and return ENOENT.
*/ */
ASSERT(args->oknoent);
xfs_da_brelse(tp, bp); xfs_da_brelse(tp, bp);
return XFS_ERROR(ENOENT); return XFS_ERROR(ENOENT);
} }
@ -1033,6 +1046,7 @@ xfs_dir2_sf_to_block(
xfs_dir2_sf_t *sfp; /* shortform structure */ xfs_dir2_sf_t *sfp; /* shortform structure */
__be16 *tagp; /* end of data entry */ __be16 *tagp; /* end of data entry */
xfs_trans_t *tp; /* transaction pointer */ xfs_trans_t *tp; /* transaction pointer */
struct xfs_name name;
xfs_dir2_trace_args("sf_to_block", args); xfs_dir2_trace_args("sf_to_block", args);
dp = args->dp; dp = args->dp;
@ -1071,7 +1085,7 @@ xfs_dir2_sf_to_block(
*/ */
error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno);
if (error) { if (error) {
kmem_free(buf, buf_len); kmem_free(buf);
return error; return error;
} }
/* /*
@ -1079,7 +1093,7 @@ xfs_dir2_sf_to_block(
*/ */
error = xfs_dir2_data_init(args, blkno, &bp); error = xfs_dir2_data_init(args, blkno, &bp);
if (error) { if (error) {
kmem_free(buf, buf_len); kmem_free(buf);
return error; return error;
} }
block = bp->data; block = bp->data;
@ -1187,8 +1201,10 @@ xfs_dir2_sf_to_block(
tagp = xfs_dir2_data_entry_tag_p(dep); tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block); *tagp = cpu_to_be16((char *)dep - (char *)block);
xfs_dir2_data_log_entry(tp, bp, dep); xfs_dir2_data_log_entry(tp, bp, dep);
blp[2 + i].hashval = cpu_to_be32(xfs_da_hashname( name.name = sfep->name;
(char *)sfep->name, sfep->namelen)); name.len = sfep->namelen;
blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops->
hashname(&name));
blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block)); (char *)dep - (char *)block));
offset = (int)((char *)(tagp + 1) - (char *)block); offset = (int)((char *)(tagp + 1) - (char *)block);
@ -1198,7 +1214,7 @@ xfs_dir2_sf_to_block(
sfep = xfs_dir2_sf_nextentry(sfp, sfep); sfep = xfs_dir2_sf_nextentry(sfp, sfep);
} }
/* Done with the temporary buffer */ /* Done with the temporary buffer */
kmem_free(buf, buf_len); kmem_free(buf);
/* /*
* Sort the leaf entries by hash value. * Sort the leaf entries by hash value.
*/ */

View File

@ -65,6 +65,7 @@ xfs_dir2_data_check(
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
char *p; /* current data position */ char *p; /* current data position */
int stale; /* count of stale leaves */ int stale; /* count of stale leaves */
struct xfs_name name;
mp = dp->i_mount; mp = dp->i_mount;
d = bp->data; d = bp->data;
@ -140,7 +141,9 @@ xfs_dir2_data_check(
addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
(xfs_dir2_data_aoff_t) (xfs_dir2_data_aoff_t)
((char *)dep - (char *)d)); ((char *)dep - (char *)d));
hash = xfs_da_hashname((char *)dep->name, dep->namelen); name.name = dep->name;
name.len = dep->namelen;
hash = mp->m_dirnameops->hashname(&name);
for (i = 0; i < be32_to_cpu(btp->count); i++) { for (i = 0; i < be32_to_cpu(btp->count); i++) {
if (be32_to_cpu(lep[i].address) == addr && if (be32_to_cpu(lep[i].address) == addr &&
be32_to_cpu(lep[i].hashval) == hash) be32_to_cpu(lep[i].hashval) == hash)

View File

@ -263,20 +263,21 @@ xfs_dir2_leaf_addname(
* If we don't have enough free bytes but we can make enough * If we don't have enough free bytes but we can make enough
* by compacting out stale entries, we'll do that. * by compacting out stale entries, we'll do that.
*/ */
if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] < needbytes && if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <
be16_to_cpu(leaf->hdr.stale) > 1) { needbytes && be16_to_cpu(leaf->hdr.stale) > 1) {
compact = 1; compact = 1;
} }
/* /*
* Otherwise if we don't have enough free bytes we need to * Otherwise if we don't have enough free bytes we need to
* convert to node form. * convert to node form.
*/ */
else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] < else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(
needbytes) { leaf->hdr.count)] < needbytes) {
/* /*
* Just checking or no space reservation, give up. * Just checking or no space reservation, give up.
*/ */
if (args->justcheck || args->total == 0) { if ((args->op_flags & XFS_DA_OP_JUSTCHECK) ||
args->total == 0) {
xfs_da_brelse(tp, lbp); xfs_da_brelse(tp, lbp);
return XFS_ERROR(ENOSPC); return XFS_ERROR(ENOSPC);
} }
@ -301,7 +302,7 @@ xfs_dir2_leaf_addname(
* If just checking, then it will fit unless we needed to allocate * If just checking, then it will fit unless we needed to allocate
* a new data block. * a new data block.
*/ */
if (args->justcheck) { if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
xfs_da_brelse(tp, lbp); xfs_da_brelse(tp, lbp);
return use_block == -1 ? XFS_ERROR(ENOSPC) : 0; return use_block == -1 ? XFS_ERROR(ENOSPC) : 0;
} }
@ -1110,7 +1111,7 @@ xfs_dir2_leaf_getdents(
*offset = XFS_DIR2_MAX_DATAPTR; *offset = XFS_DIR2_MAX_DATAPTR;
else else
*offset = xfs_dir2_byte_to_dataptr(mp, curoff); *offset = xfs_dir2_byte_to_dataptr(mp, curoff);
kmem_free(map, map_size * sizeof(*map)); kmem_free(map);
if (bp) if (bp)
xfs_da_brelse(NULL, bp); xfs_da_brelse(NULL, bp);
return error; return error;
@ -1298,12 +1299,13 @@ xfs_dir2_leaf_lookup(
((char *)dbp->data + ((char *)dbp->data +
xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address))); xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
/* /*
* Return the found inode number. * Return the found inode number & CI name if appropriate
*/ */
args->inumber = be64_to_cpu(dep->inumber); args->inumber = be64_to_cpu(dep->inumber);
error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
xfs_da_brelse(tp, dbp); xfs_da_brelse(tp, dbp);
xfs_da_brelse(tp, lbp); xfs_da_brelse(tp, lbp);
return XFS_ERROR(EEXIST); return XFS_ERROR(error);
} }
/* /*
@ -1319,8 +1321,8 @@ xfs_dir2_leaf_lookup_int(
int *indexp, /* out: index in leaf block */ int *indexp, /* out: index in leaf block */
xfs_dabuf_t **dbpp) /* out: data buffer */ xfs_dabuf_t **dbpp) /* out: data buffer */
{ {
xfs_dir2_db_t curdb; /* current data block number */ xfs_dir2_db_t curdb = -1; /* current data block number */
xfs_dabuf_t *dbp; /* data buffer */ xfs_dabuf_t *dbp = NULL; /* data buffer */
xfs_dir2_data_entry_t *dep; /* data entry */ xfs_dir2_data_entry_t *dep; /* data entry */
xfs_inode_t *dp; /* incore directory inode */ xfs_inode_t *dp; /* incore directory inode */
int error; /* error return code */ int error; /* error return code */
@ -1331,6 +1333,8 @@ xfs_dir2_leaf_lookup_int(
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_db_t newdb; /* new data block number */ xfs_dir2_db_t newdb; /* new data block number */
xfs_trans_t *tp; /* transaction pointer */ xfs_trans_t *tp; /* transaction pointer */
xfs_dir2_db_t cidb = -1; /* case match data block no. */
enum xfs_dacmp cmp; /* name compare result */
dp = args->dp; dp = args->dp;
tp = args->trans; tp = args->trans;
@ -1338,11 +1342,10 @@ xfs_dir2_leaf_lookup_int(
/* /*
* Read the leaf block into the buffer. * Read the leaf block into the buffer.
*/ */
if ((error = error = xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp,
xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, XFS_DATA_FORK);
XFS_DATA_FORK))) { if (error)
return error; return error;
}
*lbpp = lbp; *lbpp = lbp;
leaf = lbp->data; leaf = lbp->data;
xfs_dir2_leaf_check(dp, lbp); xfs_dir2_leaf_check(dp, lbp);
@ -1354,9 +1357,9 @@ xfs_dir2_leaf_lookup_int(
* Loop over all the entries with the right hash value * Loop over all the entries with the right hash value
* looking to match the name. * looking to match the name.
*/ */
for (lep = &leaf->ents[index], dbp = NULL, curdb = -1; for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) &&
index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval; be32_to_cpu(lep->hashval) == args->hashval;
lep++, index++) { lep++, index++) {
/* /*
* Skip over stale leaf entries. * Skip over stale leaf entries.
*/ */
@ -1373,10 +1376,10 @@ xfs_dir2_leaf_lookup_int(
if (newdb != curdb) { if (newdb != curdb) {
if (dbp) if (dbp)
xfs_da_brelse(tp, dbp); xfs_da_brelse(tp, dbp);
if ((error = error = xfs_da_read_buf(tp, dp,
xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, newdb),
xfs_dir2_db_to_da(mp, newdb), -1, &dbp, -1, &dbp, XFS_DATA_FORK);
XFS_DATA_FORK))) { if (error) {
xfs_da_brelse(tp, lbp); xfs_da_brelse(tp, lbp);
return error; return error;
} }
@ -1386,24 +1389,50 @@ xfs_dir2_leaf_lookup_int(
/* /*
* Point to the data entry. * Point to the data entry.
*/ */
dep = (xfs_dir2_data_entry_t *) dep = (xfs_dir2_data_entry_t *)((char *)dbp->data +
((char *)dbp->data + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/* /*
* If it matches then return it. * Compare name and if it's an exact match, return the index
* and buffer. If it's the first case-insensitive match, store
* the index and buffer and continue looking for an exact match.
*/ */
if (dep->namelen == args->namelen && cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
dep->name[0] == args->name[0] && if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
memcmp(dep->name, args->name, args->namelen) == 0) { args->cmpresult = cmp;
*dbpp = dbp;
*indexp = index; *indexp = index;
return 0; /* case exact match: return the current buffer. */
if (cmp == XFS_CMP_EXACT) {
*dbpp = dbp;
return 0;
}
cidb = curdb;
} }
} }
ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
/*
* Here, we can only be doing a lookup (not a rename or remove).
* If a case-insensitive match was found earlier, re-read the
* appropriate data block if required and return it.
*/
if (args->cmpresult == XFS_CMP_CASE) {
ASSERT(cidb != -1);
if (cidb != curdb) {
xfs_da_brelse(tp, dbp);
error = xfs_da_read_buf(tp, dp,
xfs_dir2_db_to_da(mp, cidb),
-1, &dbp, XFS_DATA_FORK);
if (error) {
xfs_da_brelse(tp, lbp);
return error;
}
}
*dbpp = dbp;
return 0;
}
/* /*
* No match found, return ENOENT. * No match found, return ENOENT.
*/ */
ASSERT(args->oknoent); ASSERT(cidb == -1);
if (dbp) if (dbp)
xfs_da_brelse(tp, dbp); xfs_da_brelse(tp, dbp);
xfs_da_brelse(tp, lbp); xfs_da_brelse(tp, lbp);

View File

@ -226,7 +226,7 @@ xfs_dir2_leafn_add(
ASSERT(index == be16_to_cpu(leaf->hdr.count) || ASSERT(index == be16_to_cpu(leaf->hdr.count) ||
be32_to_cpu(leaf->ents[index].hashval) >= args->hashval); be32_to_cpu(leaf->ents[index].hashval) >= args->hashval);
if (args->justcheck) if (args->op_flags & XFS_DA_OP_JUSTCHECK)
return 0; return 0;
/* /*
@ -387,28 +387,26 @@ xfs_dir2_leafn_lasthash(
} }
/* /*
* Look up a leaf entry in a node-format leaf block. * Look up a leaf entry for space to add a name in a node-format leaf block.
* If this is an addname then the extrablk in state is a freespace block, * The extrablk in state is a freespace block.
* otherwise it's a data block.
*/ */
int STATIC int
xfs_dir2_leafn_lookup_int( xfs_dir2_leafn_lookup_for_addname(
xfs_dabuf_t *bp, /* leaf buffer */ xfs_dabuf_t *bp, /* leaf buffer */
xfs_da_args_t *args, /* operation arguments */ xfs_da_args_t *args, /* operation arguments */
int *indexp, /* out: leaf entry index */ int *indexp, /* out: leaf entry index */
xfs_da_state_t *state) /* state to fill in */ xfs_da_state_t *state) /* state to fill in */
{ {
xfs_dabuf_t *curbp; /* current data/free buffer */ xfs_dabuf_t *curbp = NULL; /* current data/free buffer */
xfs_dir2_db_t curdb; /* current data block number */ xfs_dir2_db_t curdb = -1; /* current data block number */
xfs_dir2_db_t curfdb; /* current free block number */ xfs_dir2_db_t curfdb = -1; /* current free block number */
xfs_dir2_data_entry_t *dep; /* data block entry */
xfs_inode_t *dp; /* incore directory inode */ xfs_inode_t *dp; /* incore directory inode */
int error; /* error return value */ int error; /* error return value */
int fi; /* free entry index */ int fi; /* free entry index */
xfs_dir2_free_t *free=NULL; /* free block structure */ xfs_dir2_free_t *free = NULL; /* free block structure */
int index; /* leaf entry index */ int index; /* leaf entry index */
xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_t *leaf; /* leaf structure */
int length=0; /* length of new data entry */ int length; /* length of new data entry */
xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_db_t newdb; /* new data block number */ xfs_dir2_db_t newdb; /* new data block number */
@ -431,33 +429,20 @@ xfs_dir2_leafn_lookup_int(
/* /*
* Do we have a buffer coming in? * Do we have a buffer coming in?
*/ */
if (state->extravalid) if (state->extravalid) {
/* If so, it's a free block buffer, get the block number. */
curbp = state->extrablk.bp; curbp = state->extrablk.bp;
else curfdb = state->extrablk.blkno;
curbp = NULL; free = curbp->data;
/* ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
* For addname, it's a free block buffer, get the block number.
*/
if (args->addname) {
curfdb = curbp ? state->extrablk.blkno : -1;
curdb = -1;
length = xfs_dir2_data_entsize(args->namelen);
if ((free = (curbp ? curbp->data : NULL)))
ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
}
/*
* For others, it's a data block buffer, get the block number.
*/
else {
curfdb = -1;
curdb = curbp ? state->extrablk.blkno : -1;
} }
length = xfs_dir2_data_entsize(args->namelen);
/* /*
* Loop over leaf entries with the right hash value. * Loop over leaf entries with the right hash value.
*/ */
for (lep = &leaf->ents[index]; for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) &&
index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval; be32_to_cpu(lep->hashval) == args->hashval;
lep++, index++) { lep++, index++) {
/* /*
* Skip stale leaf entries. * Skip stale leaf entries.
*/ */
@ -471,160 +456,243 @@ xfs_dir2_leafn_lookup_int(
* For addname, we're looking for a place to put the new entry. * For addname, we're looking for a place to put the new entry.
* We want to use a data block with an entry of equal * We want to use a data block with an entry of equal
* hash value to ours if there is one with room. * hash value to ours if there is one with room.
*
* If this block isn't the data block we already have
* in hand, take a look at it.
*/ */
if (args->addname) { if (newdb != curdb) {
curdb = newdb;
/* /*
* If this block isn't the data block we already have * Convert the data block to the free block
* in hand, take a look at it. * holding its freespace information.
*/ */
if (newdb != curdb) { newfdb = xfs_dir2_db_to_fdb(mp, newdb);
curdb = newdb;
/*
* Convert the data block to the free block
* holding its freespace information.
*/
newfdb = xfs_dir2_db_to_fdb(mp, newdb);
/*
* If it's not the one we have in hand,
* read it in.
*/
if (newfdb != curfdb) {
/*
* If we had one before, drop it.
*/
if (curbp)
xfs_da_brelse(tp, curbp);
/*
* Read the free block.
*/
if ((error = xfs_da_read_buf(tp, dp,
xfs_dir2_db_to_da(mp,
newfdb),
-1, &curbp,
XFS_DATA_FORK))) {
return error;
}
free = curbp->data;
ASSERT(be32_to_cpu(free->hdr.magic) ==
XFS_DIR2_FREE_MAGIC);
ASSERT((be32_to_cpu(free->hdr.firstdb) %
XFS_DIR2_MAX_FREE_BESTS(mp)) ==
0);
ASSERT(be32_to_cpu(free->hdr.firstdb) <= curdb);
ASSERT(curdb <
be32_to_cpu(free->hdr.firstdb) +
be32_to_cpu(free->hdr.nvalid));
}
/*
* Get the index for our entry.
*/
fi = xfs_dir2_db_to_fdindex(mp, curdb);
/*
* If it has room, return it.
*/
if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) {
XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int",
XFS_ERRLEVEL_LOW, mp);
if (curfdb != newfdb)
xfs_da_brelse(tp, curbp);
return XFS_ERROR(EFSCORRUPTED);
}
curfdb = newfdb;
if (be16_to_cpu(free->bests[fi]) >= length) {
*indexp = index;
state->extravalid = 1;
state->extrablk.bp = curbp;
state->extrablk.blkno = curfdb;
state->extrablk.index = fi;
state->extrablk.magic =
XFS_DIR2_FREE_MAGIC;
ASSERT(args->oknoent);
return XFS_ERROR(ENOENT);
}
}
}
/*
* Not adding a new entry, so we really want to find
* the name given to us.
*/
else {
/* /*
* If it's a different data block, go get it. * If it's not the one we have in hand, read it in.
*/ */
if (newdb != curdb) { if (newfdb != curfdb) {
/* /*
* If we had a block before, drop it. * If we had one before, drop it.
*/ */
if (curbp) if (curbp)
xfs_da_brelse(tp, curbp); xfs_da_brelse(tp, curbp);
/* /*
* Read the data block. * Read the free block.
*/ */
if ((error = error = xfs_da_read_buf(tp, dp,
xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, newfdb),
xfs_dir2_db_to_da(mp, newdb), -1, -1, &curbp, XFS_DATA_FORK);
&curbp, XFS_DATA_FORK))) { if (error)
return error; return error;
} free = curbp->data;
xfs_dir2_data_check(dp, curbp); ASSERT(be32_to_cpu(free->hdr.magic) ==
curdb = newdb; XFS_DIR2_FREE_MAGIC);
ASSERT((be32_to_cpu(free->hdr.firstdb) %
XFS_DIR2_MAX_FREE_BESTS(mp)) == 0);
ASSERT(be32_to_cpu(free->hdr.firstdb) <= curdb);
ASSERT(curdb < be32_to_cpu(free->hdr.firstdb) +
be32_to_cpu(free->hdr.nvalid));
} }
/* /*
* Point to the data entry. * Get the index for our entry.
*/ */
dep = (xfs_dir2_data_entry_t *) fi = xfs_dir2_db_to_fdindex(mp, curdb);
((char *)curbp->data +
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/* /*
* Compare the entry, return it if it matches. * If it has room, return it.
*/ */
if (dep->namelen == args->namelen && if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) {
dep->name[0] == args->name[0] && XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int",
memcmp(dep->name, args->name, args->namelen) == 0) { XFS_ERRLEVEL_LOW, mp);
args->inumber = be64_to_cpu(dep->inumber); if (curfdb != newfdb)
*indexp = index; xfs_da_brelse(tp, curbp);
state->extravalid = 1; return XFS_ERROR(EFSCORRUPTED);
state->extrablk.bp = curbp;
state->extrablk.blkno = curdb;
state->extrablk.index =
(int)((char *)dep -
(char *)curbp->data);
state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
return XFS_ERROR(EEXIST);
} }
curfdb = newfdb;
if (be16_to_cpu(free->bests[fi]) >= length)
goto out;
} }
} }
/* /* Didn't find any space */
* Didn't find a match. fi = -1;
* If we are holding a buffer, give it back in case our caller out:
* finds it useful. ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
*/ if (curbp) {
if ((state->extravalid = (curbp != NULL))) { /* Giving back a free block. */
state->extravalid = 1;
state->extrablk.bp = curbp; state->extrablk.bp = curbp;
state->extrablk.index = -1; state->extrablk.index = fi;
/* state->extrablk.blkno = curfdb;
* For addname, giving back a free block. state->extrablk.magic = XFS_DIR2_FREE_MAGIC;
*/ } else {
if (args->addname) { state->extravalid = 0;
state->extrablk.blkno = curfdb;
state->extrablk.magic = XFS_DIR2_FREE_MAGIC;
}
/*
* For other callers, giving back a data block.
*/
else {
state->extrablk.blkno = curdb;
state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
}
} }
/* /*
* Return the final index, that will be the insertion point. * Return the index, that will be the insertion point.
*/ */
*indexp = index; *indexp = index;
ASSERT(index == be16_to_cpu(leaf->hdr.count) || args->oknoent);
return XFS_ERROR(ENOENT); return XFS_ERROR(ENOENT);
} }
/*
* Look up a leaf entry in a node-format leaf block.
* The extrablk in state a data block.
*/
STATIC int
xfs_dir2_leafn_lookup_for_entry(
xfs_dabuf_t *bp, /* leaf buffer */
xfs_da_args_t *args, /* operation arguments */
int *indexp, /* out: leaf entry index */
xfs_da_state_t *state) /* state to fill in */
{
xfs_dabuf_t *curbp = NULL; /* current data/free buffer */
xfs_dir2_db_t curdb = -1; /* current data block number */
xfs_dir2_data_entry_t *dep; /* data block entry */
xfs_inode_t *dp; /* incore directory inode */
int error; /* error return value */
int index; /* leaf entry index */
xfs_dir2_leaf_t *leaf; /* leaf structure */
xfs_dir2_leaf_entry_t *lep; /* leaf entry */
xfs_mount_t *mp; /* filesystem mount point */
xfs_dir2_db_t newdb; /* new data block number */
xfs_trans_t *tp; /* transaction pointer */
enum xfs_dacmp cmp; /* comparison result */
dp = args->dp;
tp = args->trans;
mp = dp->i_mount;
leaf = bp->data;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
#ifdef __KERNEL__
ASSERT(be16_to_cpu(leaf->hdr.count) > 0);
#endif
xfs_dir2_leafn_check(dp, bp);
/*
* Look up the hash value in the leaf entries.
*/
index = xfs_dir2_leaf_search_hash(args, bp);
/*
* Do we have a buffer coming in?
*/
if (state->extravalid) {
curbp = state->extrablk.bp;
curdb = state->extrablk.blkno;
}
/*
* Loop over leaf entries with the right hash value.
*/
for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) &&
be32_to_cpu(lep->hashval) == args->hashval;
lep++, index++) {
/*
* Skip stale leaf entries.
*/
if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
continue;
/*
* Pull the data block number from the entry.
*/
newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
/*
* Not adding a new entry, so we really want to find
* the name given to us.
*
* If it's a different data block, go get it.
*/
if (newdb != curdb) {
/*
* If we had a block before that we aren't saving
* for a CI name, drop it
*/
if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT ||
curdb != state->extrablk.blkno))
xfs_da_brelse(tp, curbp);
/*
* If needing the block that is saved with a CI match,
* use it otherwise read in the new data block.
*/
if (args->cmpresult != XFS_CMP_DIFFERENT &&
newdb == state->extrablk.blkno) {
ASSERT(state->extravalid);
curbp = state->extrablk.bp;
} else {
error = xfs_da_read_buf(tp, dp,
xfs_dir2_db_to_da(mp, newdb),
-1, &curbp, XFS_DATA_FORK);
if (error)
return error;
}
xfs_dir2_data_check(dp, curbp);
curdb = newdb;
}
/*
* Point to the data entry.
*/
dep = (xfs_dir2_data_entry_t *)((char *)curbp->data +
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/*
* Compare the entry and if it's an exact match, return
* EEXIST immediately. If it's the first case-insensitive
* match, store the block & inode number and continue looking.
*/
cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
/* If there is a CI match block, drop it */
if (args->cmpresult != XFS_CMP_DIFFERENT &&
curdb != state->extrablk.blkno)
xfs_da_brelse(tp, state->extrablk.bp);
args->cmpresult = cmp;
args->inumber = be64_to_cpu(dep->inumber);
*indexp = index;
state->extravalid = 1;
state->extrablk.bp = curbp;
state->extrablk.blkno = curdb;
state->extrablk.index = (int)((char *)dep -
(char *)curbp->data);
state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
if (cmp == XFS_CMP_EXACT)
return XFS_ERROR(EEXIST);
}
}
ASSERT(index == be16_to_cpu(leaf->hdr.count) ||
(args->op_flags & XFS_DA_OP_OKNOENT));
if (curbp) {
if (args->cmpresult == XFS_CMP_DIFFERENT) {
/* Giving back last used data block. */
state->extravalid = 1;
state->extrablk.bp = curbp;
state->extrablk.index = -1;
state->extrablk.blkno = curdb;
state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
} else {
/* If the curbp is not the CI match block, drop it */
if (state->extrablk.bp != curbp)
xfs_da_brelse(tp, curbp);
}
} else {
state->extravalid = 0;
}
*indexp = index;
return XFS_ERROR(ENOENT);
}
/*
* Look up a leaf entry in a node-format leaf block.
* If this is an addname then the extrablk in state is a freespace block,
* otherwise it's a data block.
*/
int
xfs_dir2_leafn_lookup_int(
xfs_dabuf_t *bp, /* leaf buffer */
xfs_da_args_t *args, /* operation arguments */
int *indexp, /* out: leaf entry index */
xfs_da_state_t *state) /* state to fill in */
{
if (args->op_flags & XFS_DA_OP_ADDNAME)
return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp,
state);
return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state);
}
/* /*
* Move count leaf entries from source to destination leaf. * Move count leaf entries from source to destination leaf.
* Log entries and headers. Stale entries are preserved. * Log entries and headers. Stale entries are preserved.
@ -825,7 +893,8 @@ xfs_dir2_leafn_rebalance(
blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count); blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count);
/* /*
* Finally sanity check just to make sure we are not returning a negative index * Finally sanity check just to make sure we are not returning a
* negative index
*/ */
if(blk2->index < 0) { if(blk2->index < 0) {
state->inleaf = 1; state->inleaf = 1;
@ -1332,7 +1401,7 @@ xfs_dir2_node_addname(
/* /*
* It worked, fix the hash values up the btree. * It worked, fix the hash values up the btree.
*/ */
if (!args->justcheck) if (!(args->op_flags & XFS_DA_OP_JUSTCHECK))
xfs_da_fixhashpath(state, &state->path); xfs_da_fixhashpath(state, &state->path);
} else { } else {
/* /*
@ -1515,7 +1584,8 @@ xfs_dir2_node_addname_int(
/* /*
* Not allowed to allocate, return failure. * Not allowed to allocate, return failure.
*/ */
if (args->justcheck || args->total == 0) { if ((args->op_flags & XFS_DA_OP_JUSTCHECK) ||
args->total == 0) {
/* /*
* Drop the freespace buffer unless it came from our * Drop the freespace buffer unless it came from our
* caller. * caller.
@ -1661,7 +1731,7 @@ xfs_dir2_node_addname_int(
/* /*
* If just checking, we succeeded. * If just checking, we succeeded.
*/ */
if (args->justcheck) { if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL) if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
xfs_da_buf_done(fbp); xfs_da_buf_done(fbp);
return 0; return 0;
@ -1767,6 +1837,14 @@ xfs_dir2_node_lookup(
error = xfs_da_node_lookup_int(state, &rval); error = xfs_da_node_lookup_int(state, &rval);
if (error) if (error)
rval = error; rval = error;
else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) {
/* If a CI match, dup the actual name and return EEXIST */
xfs_dir2_data_entry_t *dep;
dep = (xfs_dir2_data_entry_t *)((char *)state->extrablk.bp->
data + state->extrablk.index);
rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
}
/* /*
* Release the btree blocks and leaf block. * Release the btree blocks and leaf block.
*/ */
@ -1810,9 +1888,8 @@ xfs_dir2_node_removename(
* Look up the entry we're deleting, set up the cursor. * Look up the entry we're deleting, set up the cursor.
*/ */
error = xfs_da_node_lookup_int(state, &rval); error = xfs_da_node_lookup_int(state, &rval);
if (error) { if (error)
rval = error; rval = error;
}
/* /*
* Didn't find it, upper layer screwed up. * Didn't find it, upper layer screwed up.
*/ */
@ -1829,9 +1906,8 @@ xfs_dir2_node_removename(
*/ */
error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, error = xfs_dir2_leafn_remove(args, blk->bp, blk->index,
&state->extrablk, &rval); &state->extrablk, &rval);
if (error) { if (error)
return error; return error;
}
/* /*
* Fix the hash values up the btree. * Fix the hash values up the btree.
*/ */

View File

@ -255,7 +255,7 @@ xfs_dir2_block_to_sf(
xfs_dir2_sf_check(args); xfs_dir2_sf_check(args);
out: out:
xfs_trans_log_inode(args->trans, dp, logflags); xfs_trans_log_inode(args->trans, dp, logflags);
kmem_free(block, mp->m_dirblksize); kmem_free(block);
return error; return error;
} }
@ -332,7 +332,7 @@ xfs_dir2_sf_addname(
/* /*
* Just checking or no space reservation, it doesn't fit. * Just checking or no space reservation, it doesn't fit.
*/ */
if (args->justcheck || args->total == 0) if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
return XFS_ERROR(ENOSPC); return XFS_ERROR(ENOSPC);
/* /*
* Convert to block form then add the name. * Convert to block form then add the name.
@ -345,7 +345,7 @@ xfs_dir2_sf_addname(
/* /*
* Just checking, it fits. * Just checking, it fits.
*/ */
if (args->justcheck) if (args->op_flags & XFS_DA_OP_JUSTCHECK)
return 0; return 0;
/* /*
* Do it the easy way - just add it at the end. * Do it the easy way - just add it at the end.
@ -512,7 +512,7 @@ xfs_dir2_sf_addname_hard(
sfep = xfs_dir2_sf_nextentry(sfp, sfep); sfep = xfs_dir2_sf_nextentry(sfp, sfep);
memcpy(sfep, oldsfep, old_isize - nbytes); memcpy(sfep, oldsfep, old_isize - nbytes);
} }
kmem_free(buf, old_isize); kmem_free(buf);
dp->i_d.di_size = new_isize; dp->i_d.di_size = new_isize;
xfs_dir2_sf_check(args); xfs_dir2_sf_check(args);
} }
@ -812,8 +812,11 @@ xfs_dir2_sf_lookup(
{ {
xfs_inode_t *dp; /* incore directory inode */ xfs_inode_t *dp; /* incore directory inode */
int i; /* entry index */ int i; /* entry index */
int error;
xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
xfs_dir2_sf_t *sfp; /* shortform structure */ xfs_dir2_sf_t *sfp; /* shortform structure */
enum xfs_dacmp cmp; /* comparison result */
xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */
xfs_dir2_trace_args("sf_lookup", args); xfs_dir2_trace_args("sf_lookup", args);
xfs_dir2_sf_check(args); xfs_dir2_sf_check(args);
@ -836,6 +839,7 @@ xfs_dir2_sf_lookup(
*/ */
if (args->namelen == 1 && args->name[0] == '.') { if (args->namelen == 1 && args->name[0] == '.') {
args->inumber = dp->i_ino; args->inumber = dp->i_ino;
args->cmpresult = XFS_CMP_EXACT;
return XFS_ERROR(EEXIST); return XFS_ERROR(EEXIST);
} }
/* /*
@ -844,28 +848,41 @@ xfs_dir2_sf_lookup(
if (args->namelen == 2 && if (args->namelen == 2 &&
args->name[0] == '.' && args->name[1] == '.') { args->name[0] == '.' && args->name[1] == '.') {
args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent); args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
args->cmpresult = XFS_CMP_EXACT;
return XFS_ERROR(EEXIST); return XFS_ERROR(EEXIST);
} }
/* /*
* Loop over all the entries trying to match ours. * Loop over all the entries trying to match ours.
*/ */
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); ci_sfep = NULL;
i < sfp->hdr.count; for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen && /*
sfep->name[0] == args->name[0] && * Compare name and if it's an exact match, return the inode
memcmp(args->name, sfep->name, args->namelen) == 0) { * number. If it's the first case-insensitive match, store the
args->inumber = * inode number and continue looking for an exact match.
xfs_dir2_sf_get_inumber(sfp, */
xfs_dir2_sf_inumberp(sfep)); cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name,
return XFS_ERROR(EEXIST); sfep->namelen);
if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
args->cmpresult = cmp;
args->inumber = xfs_dir2_sf_get_inumber(sfp,
xfs_dir2_sf_inumberp(sfep));
if (cmp == XFS_CMP_EXACT)
return XFS_ERROR(EEXIST);
ci_sfep = sfep;
} }
} }
ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
/* /*
* Didn't find it. * Here, we can only be doing a lookup (not a rename or replace).
* If a case-insensitive match was not found, return ENOENT.
*/ */
ASSERT(args->oknoent); if (!ci_sfep)
return XFS_ERROR(ENOENT); return XFS_ERROR(ENOENT);
/* otherwise process the CI match as required by the caller */
error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen);
return XFS_ERROR(error);
} }
/* /*
@ -904,24 +921,21 @@ xfs_dir2_sf_removename(
* Loop over the old directory entries. * Loop over the old directory entries.
* Find the one we're deleting. * Find the one we're deleting.
*/ */
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
i < sfp->hdr.count; i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
if (sfep->namelen == args->namelen && XFS_CMP_EXACT) {
sfep->name[0] == args->name[0] &&
memcmp(sfep->name, args->name, args->namelen) == 0) {
ASSERT(xfs_dir2_sf_get_inumber(sfp, ASSERT(xfs_dir2_sf_get_inumber(sfp,
xfs_dir2_sf_inumberp(sfep)) == xfs_dir2_sf_inumberp(sfep)) ==
args->inumber); args->inumber);
break; break;
} }
} }
/* /*
* Didn't find it. * Didn't find it.
*/ */
if (i == sfp->hdr.count) { if (i == sfp->hdr.count)
return XFS_ERROR(ENOENT); return XFS_ERROR(ENOENT);
}
/* /*
* Calculate sizes. * Calculate sizes.
*/ */
@ -1042,11 +1056,10 @@ xfs_dir2_sf_replace(
*/ */
else { else {
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count; i < sfp->hdr.count;
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen && if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
sfep->name[0] == args->name[0] && XFS_CMP_EXACT) {
memcmp(args->name, sfep->name, args->namelen) == 0) {
#if XFS_BIG_INUMS || defined(DEBUG) #if XFS_BIG_INUMS || defined(DEBUG)
ino = xfs_dir2_sf_get_inumber(sfp, ino = xfs_dir2_sf_get_inumber(sfp,
xfs_dir2_sf_inumberp(sfep)); xfs_dir2_sf_inumberp(sfep));
@ -1061,7 +1074,7 @@ xfs_dir2_sf_replace(
* Didn't find it. * Didn't find it.
*/ */
if (i == sfp->hdr.count) { if (i == sfp->hdr.count) {
ASSERT(args->oknoent); ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
#if XFS_BIG_INUMS #if XFS_BIG_INUMS
if (i8elevated) if (i8elevated)
xfs_dir2_sf_toino4(args); xfs_dir2_sf_toino4(args);
@ -1174,7 +1187,7 @@ xfs_dir2_sf_toino4(
/* /*
* Clean up the inode. * Clean up the inode.
*/ */
kmem_free(buf, oldsize); kmem_free(buf);
dp->i_d.di_size = newsize; dp->i_d.di_size = newsize;
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
} }
@ -1251,7 +1264,7 @@ xfs_dir2_sf_toino8(
/* /*
* Clean up the inode. * Clean up the inode.
*/ */
kmem_free(buf, oldsize); kmem_free(buf);
dp->i_d.di_size = newsize; dp->i_d.di_size = newsize;
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
} }

View File

@ -62,7 +62,7 @@ typedef union {
* Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t.
* Only need 16 bits, this is the byte offset into the single block form. * Only need 16 bits, this is the byte offset into the single block form.
*/ */
typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t; typedef struct { __uint8_t i[2]; } __arch_pack xfs_dir2_sf_off_t;
/* /*
* The parent directory has a dedicated field, and the self-pointer must * The parent directory has a dedicated field, and the self-pointer must
@ -76,14 +76,14 @@ typedef struct xfs_dir2_sf_hdr {
__uint8_t count; /* count of entries */ __uint8_t count; /* count of entries */
__uint8_t i8count; /* count of 8-byte inode #s */ __uint8_t i8count; /* count of 8-byte inode #s */
xfs_dir2_inou_t parent; /* parent dir inode number */ xfs_dir2_inou_t parent; /* parent dir inode number */
} xfs_dir2_sf_hdr_t; } __arch_pack xfs_dir2_sf_hdr_t;
typedef struct xfs_dir2_sf_entry { typedef struct xfs_dir2_sf_entry {
__uint8_t namelen; /* actual name length */ __uint8_t namelen; /* actual name length */
xfs_dir2_sf_off_t offset; /* saved offset */ xfs_dir2_sf_off_t offset; /* saved offset */
__uint8_t name[1]; /* name, variable size */ __uint8_t name[1]; /* name, variable size */
xfs_dir2_inou_t inumber; /* inode number, var. offset */ xfs_dir2_inou_t inumber; /* inode number, var. offset */
} xfs_dir2_sf_entry_t; } __arch_pack xfs_dir2_sf_entry_t;
typedef struct xfs_dir2_sf { typedef struct xfs_dir2_sf {
xfs_dir2_sf_hdr_t hdr; /* shortform header */ xfs_dir2_sf_hdr_t hdr; /* shortform header */

View File

@ -85,7 +85,8 @@ xfs_dir2_trace_args(
(void *)((unsigned long)(args->inumber >> 32)), (void *)((unsigned long)(args->inumber >> 32)),
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
(void *)args->dp, (void *)args->trans, (void *)args->dp, (void *)args->trans,
(void *)(unsigned long)args->justcheck, NULL, NULL); (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
NULL, NULL);
} }
void void
@ -100,7 +101,7 @@ xfs_dir2_trace_args_b(
(void *)((unsigned long)(args->inumber >> 32)), (void *)((unsigned long)(args->inumber >> 32)),
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
(void *)args->dp, (void *)args->trans, (void *)args->dp, (void *)args->trans,
(void *)(unsigned long)args->justcheck, (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
(void *)(bp ? bp->bps[0] : NULL), NULL); (void *)(bp ? bp->bps[0] : NULL), NULL);
} }
@ -117,7 +118,7 @@ xfs_dir2_trace_args_bb(
(void *)((unsigned long)(args->inumber >> 32)), (void *)((unsigned long)(args->inumber >> 32)),
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
(void *)args->dp, (void *)args->trans, (void *)args->dp, (void *)args->trans,
(void *)(unsigned long)args->justcheck, (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
(void *)(lbp ? lbp->bps[0] : NULL), (void *)(lbp ? lbp->bps[0] : NULL),
(void *)(dbp ? dbp->bps[0] : NULL)); (void *)(dbp ? dbp->bps[0] : NULL));
} }
@ -157,8 +158,8 @@ xfs_dir2_trace_args_db(
(void *)((unsigned long)(args->inumber >> 32)), (void *)((unsigned long)(args->inumber >> 32)),
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
(void *)args->dp, (void *)args->trans, (void *)args->dp, (void *)args->trans,
(void *)(unsigned long)args->justcheck, (void *)(long)db, (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
(void *)dbp); (void *)(long)db, (void *)dbp);
} }
void void
@ -173,7 +174,7 @@ xfs_dir2_trace_args_i(
(void *)((unsigned long)(args->inumber >> 32)), (void *)((unsigned long)(args->inumber >> 32)),
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
(void *)args->dp, (void *)args->trans, (void *)args->dp, (void *)args->trans,
(void *)(unsigned long)args->justcheck, (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
(void *)((unsigned long)(i >> 32)), (void *)((unsigned long)(i >> 32)),
(void *)((unsigned long)(i & 0xFFFFFFFF))); (void *)((unsigned long)(i & 0xFFFFFFFF)));
} }
@ -190,7 +191,8 @@ xfs_dir2_trace_args_s(
(void *)((unsigned long)(args->inumber >> 32)), (void *)((unsigned long)(args->inumber >> 32)),
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
(void *)args->dp, (void *)args->trans, (void *)args->dp, (void *)args->trans,
(void *)(unsigned long)args->justcheck, (void *)(long)s, NULL); (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
(void *)(long)s, NULL);
} }
void void
@ -208,7 +210,7 @@ xfs_dir2_trace_args_sb(
(void *)((unsigned long)(args->inumber >> 32)), (void *)((unsigned long)(args->inumber >> 32)),
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
(void *)args->dp, (void *)args->trans, (void *)args->dp, (void *)args->trans,
(void *)(unsigned long)args->justcheck, (void *)(long)s, (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
(void *)dbp); (void *)(long)s, (void *)dbp);
} }
#endif /* XFS_DIR2_TRACE */ #endif /* XFS_DIR2_TRACE */

View File

@ -166,6 +166,6 @@ typedef enum {
#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \ #define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
DM_FLAGS_NDELAY : 0) DM_FLAGS_NDELAY : 0)
#define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) #define AT_DELAY_FLAG(f) ((f & XFS_ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0)
#endif /* __XFS_DMAPI_H__ */ #endif /* __XFS_DMAPI_H__ */

View File

@ -66,14 +66,6 @@ int xfs_etest[XFS_NUM_INJECT_ERROR];
int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR]; int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR];
char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR]; char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR];
void
xfs_error_test_init(void)
{
memset(xfs_etest, 0, sizeof(xfs_etest));
memset(xfs_etest_fsid, 0, sizeof(xfs_etest_fsid));
memset(xfs_etest_fsname, 0, sizeof(xfs_etest_fsname));
}
int int
xfs_error_test(int error_tag, int *fsidp, char *expression, xfs_error_test(int error_tag, int *fsidp, char *expression,
int line, char *file, unsigned long randfactor) int line, char *file, unsigned long randfactor)
@ -150,8 +142,7 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud)
xfs_etest[i]); xfs_etest[i]);
xfs_etest[i] = 0; xfs_etest[i] = 0;
xfs_etest_fsid[i] = 0LL; xfs_etest_fsid[i] = 0LL;
kmem_free(xfs_etest_fsname[i], kmem_free(xfs_etest_fsname[i]);
strlen(xfs_etest_fsname[i]) + 1);
xfs_etest_fsname[i] = NULL; xfs_etest_fsname[i] = NULL;
} }
} }
@ -175,7 +166,7 @@ xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap)
newfmt = kmem_alloc(len, KM_SLEEP); newfmt = kmem_alloc(len, KM_SLEEP);
sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt); sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt);
icmn_err(level, newfmt, ap); icmn_err(level, newfmt, ap);
kmem_free(newfmt, len); kmem_free(newfmt);
} else { } else {
icmn_err(level, fmt, ap); icmn_err(level, fmt, ap);
} }

View File

@ -127,7 +127,6 @@ extern void xfs_corruption_error(char *tag, int level, struct xfs_mount *mp,
#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) #if (defined(DEBUG) || defined(INDUCE_IO_ERROR))
extern int xfs_error_test(int, int *, char *, int, char *, unsigned long); extern int xfs_error_test(int, int *, char *, int, char *, unsigned long);
extern void xfs_error_test_init(void);
#define XFS_NUM_INJECT_ERROR 10 #define XFS_NUM_INJECT_ERROR 10

View File

@ -41,8 +41,7 @@ xfs_efi_item_free(xfs_efi_log_item_t *efip)
int nexts = efip->efi_format.efi_nextents; int nexts = efip->efi_format.efi_nextents;
if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
kmem_free(efip, sizeof(xfs_efi_log_item_t) + kmem_free(efip);
(nexts - 1) * sizeof(xfs_extent_t));
} else { } else {
kmem_zone_free(xfs_efi_zone, efip); kmem_zone_free(xfs_efi_zone, efip);
} }
@ -374,8 +373,7 @@ xfs_efd_item_free(xfs_efd_log_item_t *efdp)
int nexts = efdp->efd_format.efd_nextents; int nexts = efdp->efd_format.efd_nextents;
if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { if (nexts > XFS_EFD_MAX_FAST_EXTENTS) {
kmem_free(efdp, sizeof(xfs_efd_log_item_t) + kmem_free(efdp);
(nexts - 1) * sizeof(xfs_extent_t));
} else { } else {
kmem_zone_free(xfs_efd_zone, efdp); kmem_zone_free(xfs_efd_zone, efdp);
} }

View File

@ -397,10 +397,12 @@ int
xfs_filestream_init(void) xfs_filestream_init(void)
{ {
item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item"); item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item");
if (!item_zone)
return -ENOMEM;
#ifdef XFS_FILESTREAMS_TRACE #ifdef XFS_FILESTREAMS_TRACE
xfs_filestreams_trace_buf = ktrace_alloc(XFS_FSTRM_KTRACE_SIZE, KM_SLEEP); xfs_filestreams_trace_buf = ktrace_alloc(XFS_FSTRM_KTRACE_SIZE, KM_SLEEP);
#endif #endif
return item_zone ? 0 : -ENOMEM; return 0;
} }
/* /*

View File

@ -239,6 +239,7 @@ typedef struct xfs_fsop_resblks {
#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */ #define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */
#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */ #define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */
#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */ #define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */
#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */
#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ #define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
@ -371,6 +372,9 @@ typedef struct xfs_fsop_attrlist_handlereq {
typedef struct xfs_attr_multiop { typedef struct xfs_attr_multiop {
__u32 am_opcode; __u32 am_opcode;
#define ATTR_OP_GET 1 /* return the indicated attr's value */
#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */
#define ATTR_OP_REMOVE 3 /* remove the indicated attr */
__s32 am_error; __s32 am_error;
void __user *am_attrname; void __user *am_attrname;
void __user *am_attrvalue; void __user *am_attrvalue;

View File

@ -95,6 +95,8 @@ xfs_fs_geometry(
XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) | XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |
(xfs_sb_version_hassector(&mp->m_sb) ? (xfs_sb_version_hassector(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_SECTOR : 0) | XFS_FSOP_GEOM_FLAGS_SECTOR : 0) |
(xfs_sb_version_hasasciici(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_DIRV2CI : 0) |
(xfs_sb_version_haslazysbcount(&mp->m_sb) ? (xfs_sb_version_haslazysbcount(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) | XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) |
(xfs_sb_version_hasattr2(&mp->m_sb) ? (xfs_sb_version_hasattr2(&mp->m_sb) ?

View File

@ -1763,67 +1763,6 @@ xfs_itruncate_finish(
return 0; return 0;
} }
/*
* xfs_igrow_start
*
* Do the first part of growing a file: zero any data in the last
* block that is beyond the old EOF. We need to do this before
* the inode is joined to the transaction to modify the i_size.
* That way we can drop the inode lock and call into the buffer
* cache to get the buffer mapping the EOF.
*/
int
xfs_igrow_start(
xfs_inode_t *ip,
xfs_fsize_t new_size,
cred_t *credp)
{
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
ASSERT(new_size > ip->i_size);
/*
* Zero any pages that may have been created by
* xfs_write_file() beyond the end of the file
* and any blocks between the old and new file sizes.
*/
return xfs_zero_eof(ip, new_size, ip->i_size);
}
/*
* xfs_igrow_finish
*
* This routine is called to extend the size of a file.
* The inode must have both the iolock and the ilock locked
* for update and it must be a part of the current transaction.
* The xfs_igrow_start() function must have been called previously.
* If the change_flag is not zero, the inode change timestamp will
* be updated.
*/
void
xfs_igrow_finish(
xfs_trans_t *tp,
xfs_inode_t *ip,
xfs_fsize_t new_size,
int change_flag)
{
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
ASSERT(ip->i_transp == tp);
ASSERT(new_size > ip->i_size);
/*
* Update the file size. Update the inode change timestamp
* if change_flag set.
*/
ip->i_d.di_size = new_size;
ip->i_size = new_size;
if (change_flag)
xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
}
/* /*
* This is called when the inode's link count goes to 0. * This is called when the inode's link count goes to 0.
* We place the on-disk inode on a list in the AGI. It * We place the on-disk inode on a list in the AGI. It
@ -2258,7 +2197,7 @@ xfs_ifree_cluster(
xfs_trans_binval(tp, bp); xfs_trans_binval(tp, bp);
} }
kmem_free(ip_found, ninodes * sizeof(xfs_inode_t *)); kmem_free(ip_found);
xfs_put_perag(mp, pag); xfs_put_perag(mp, pag);
} }
@ -2470,7 +2409,7 @@ xfs_iroot_realloc(
(int)new_size); (int)new_size);
memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t)); memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t));
} }
kmem_free(ifp->if_broot, ifp->if_broot_bytes); kmem_free(ifp->if_broot);
ifp->if_broot = new_broot; ifp->if_broot = new_broot;
ifp->if_broot_bytes = (int)new_size; ifp->if_broot_bytes = (int)new_size;
ASSERT(ifp->if_broot_bytes <= ASSERT(ifp->if_broot_bytes <=
@ -2514,7 +2453,7 @@ xfs_idata_realloc(
if (new_size == 0) { if (new_size == 0) {
if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); kmem_free(ifp->if_u1.if_data);
} }
ifp->if_u1.if_data = NULL; ifp->if_u1.if_data = NULL;
real_size = 0; real_size = 0;
@ -2529,7 +2468,7 @@ xfs_idata_realloc(
ASSERT(ifp->if_real_bytes != 0); ASSERT(ifp->if_real_bytes != 0);
memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
new_size); new_size);
kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); kmem_free(ifp->if_u1.if_data);
ifp->if_u1.if_data = ifp->if_u2.if_inline_data; ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
} }
real_size = 0; real_size = 0;
@ -2636,7 +2575,7 @@ xfs_idestroy_fork(
ifp = XFS_IFORK_PTR(ip, whichfork); ifp = XFS_IFORK_PTR(ip, whichfork);
if (ifp->if_broot != NULL) { if (ifp->if_broot != NULL) {
kmem_free(ifp->if_broot, ifp->if_broot_bytes); kmem_free(ifp->if_broot);
ifp->if_broot = NULL; ifp->if_broot = NULL;
} }
@ -2650,7 +2589,7 @@ xfs_idestroy_fork(
if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) &&
(ifp->if_u1.if_data != NULL)) { (ifp->if_u1.if_data != NULL)) {
ASSERT(ifp->if_real_bytes != 0); ASSERT(ifp->if_real_bytes != 0);
kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); kmem_free(ifp->if_u1.if_data);
ifp->if_u1.if_data = NULL; ifp->if_u1.if_data = NULL;
ifp->if_real_bytes = 0; ifp->if_real_bytes = 0;
} }
@ -3058,7 +2997,7 @@ xfs_iflush_cluster(
out_free: out_free:
read_unlock(&pag->pag_ici_lock); read_unlock(&pag->pag_ici_lock);
kmem_free(ilist, ilist_size); kmem_free(ilist);
return 0; return 0;
@ -3102,7 +3041,7 @@ cluster_corrupt_out:
* Unlocks the flush lock * Unlocks the flush lock
*/ */
xfs_iflush_abort(iq); xfs_iflush_abort(iq);
kmem_free(ilist, ilist_size); kmem_free(ilist);
return XFS_ERROR(EFSCORRUPTED); return XFS_ERROR(EFSCORRUPTED);
} }
@ -3143,8 +3082,6 @@ xfs_iflush(
* flush lock and do nothing. * flush lock and do nothing.
*/ */
if (xfs_inode_clean(ip)) { if (xfs_inode_clean(ip)) {
ASSERT((iip != NULL) ?
!(iip->ili_item.li_flags & XFS_LI_IN_AIL) : 1);
xfs_ifunlock(ip); xfs_ifunlock(ip);
return 0; return 0;
} }
@ -3836,7 +3773,7 @@ xfs_iext_add_indirect_multi(
erp = xfs_iext_irec_new(ifp, erp_idx); erp = xfs_iext_irec_new(ifp, erp_idx);
} }
memmove(&erp->er_extbuf[i], nex2_ep, byte_diff); memmove(&erp->er_extbuf[i], nex2_ep, byte_diff);
kmem_free(nex2_ep, byte_diff); kmem_free(nex2_ep);
erp->er_extcount += nex2; erp->er_extcount += nex2;
xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2); xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2);
} }
@ -4112,7 +4049,7 @@ xfs_iext_direct_to_inline(
*/ */
memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
nextents * sizeof(xfs_bmbt_rec_t)); nextents * sizeof(xfs_bmbt_rec_t));
kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); kmem_free(ifp->if_u1.if_extents);
ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
ifp->if_real_bytes = 0; ifp->if_real_bytes = 0;
} }
@ -4186,7 +4123,7 @@ xfs_iext_indirect_to_direct(
ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ); ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
ep = ifp->if_u1.if_ext_irec->er_extbuf; ep = ifp->if_u1.if_ext_irec->er_extbuf;
kmem_free(ifp->if_u1.if_ext_irec, sizeof(xfs_ext_irec_t)); kmem_free(ifp->if_u1.if_ext_irec);
ifp->if_flags &= ~XFS_IFEXTIREC; ifp->if_flags &= ~XFS_IFEXTIREC;
ifp->if_u1.if_extents = ep; ifp->if_u1.if_extents = ep;
ifp->if_bytes = size; ifp->if_bytes = size;
@ -4212,7 +4149,7 @@ xfs_iext_destroy(
} }
ifp->if_flags &= ~XFS_IFEXTIREC; ifp->if_flags &= ~XFS_IFEXTIREC;
} else if (ifp->if_real_bytes) { } else if (ifp->if_real_bytes) {
kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); kmem_free(ifp->if_u1.if_extents);
} else if (ifp->if_bytes) { } else if (ifp->if_bytes) {
memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
sizeof(xfs_bmbt_rec_t)); sizeof(xfs_bmbt_rec_t));
@ -4483,7 +4420,7 @@ xfs_iext_irec_remove(
if (erp->er_extbuf) { if (erp->er_extbuf) {
xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, xfs_iext_irec_update_extoffs(ifp, erp_idx + 1,
-erp->er_extcount); -erp->er_extcount);
kmem_free(erp->er_extbuf, XFS_IEXT_BUFSZ); kmem_free(erp->er_extbuf);
} }
/* Compact extent records */ /* Compact extent records */
erp = ifp->if_u1.if_ext_irec; erp = ifp->if_u1.if_ext_irec;
@ -4501,8 +4438,7 @@ xfs_iext_irec_remove(
xfs_iext_realloc_indirect(ifp, xfs_iext_realloc_indirect(ifp,
nlists * sizeof(xfs_ext_irec_t)); nlists * sizeof(xfs_ext_irec_t));
} else { } else {
kmem_free(ifp->if_u1.if_ext_irec, kmem_free(ifp->if_u1.if_ext_irec);
sizeof(xfs_ext_irec_t));
} }
ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
} }
@ -4571,7 +4507,7 @@ xfs_iext_irec_compact_pages(
* so er_extoffs don't get modified in * so er_extoffs don't get modified in
* xfs_iext_irec_remove. * xfs_iext_irec_remove.
*/ */
kmem_free(erp_next->er_extbuf, XFS_IEXT_BUFSZ); kmem_free(erp_next->er_extbuf);
erp_next->er_extbuf = NULL; erp_next->er_extbuf = NULL;
xfs_iext_irec_remove(ifp, erp_idx + 1); xfs_iext_irec_remove(ifp, erp_idx + 1);
nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
@ -4596,40 +4532,63 @@ xfs_iext_irec_compact_full(
int nlists; /* number of irec's (ex lists) */ int nlists; /* number of irec's (ex lists) */
ASSERT(ifp->if_flags & XFS_IFEXTIREC); ASSERT(ifp->if_flags & XFS_IFEXTIREC);
nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
erp = ifp->if_u1.if_ext_irec; erp = ifp->if_u1.if_ext_irec;
ep = &erp->er_extbuf[erp->er_extcount]; ep = &erp->er_extbuf[erp->er_extcount];
erp_next = erp + 1; erp_next = erp + 1;
ep_next = erp_next->er_extbuf; ep_next = erp_next->er_extbuf;
while (erp_idx < nlists - 1) { while (erp_idx < nlists - 1) {
/*
* Check how many extent records are available in this irec.
* If there is none skip the whole exercise.
*/
ext_avail = XFS_LINEAR_EXTS - erp->er_extcount; ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
ext_diff = MIN(ext_avail, erp_next->er_extcount); if (ext_avail) {
memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t));
erp->er_extcount += ext_diff;
erp_next->er_extcount -= ext_diff;
/* Remove next page */
if (erp_next->er_extcount == 0) {
/* /*
* Free page before removing extent record * Copy over as many as possible extent records into
* so er_extoffs don't get modified in * the previous page.
* xfs_iext_irec_remove.
*/ */
kmem_free(erp_next->er_extbuf, ext_diff = MIN(ext_avail, erp_next->er_extcount);
erp_next->er_extcount * sizeof(xfs_bmbt_rec_t)); memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t));
erp_next->er_extbuf = NULL; erp->er_extcount += ext_diff;
xfs_iext_irec_remove(ifp, erp_idx + 1); erp_next->er_extcount -= ext_diff;
erp = &ifp->if_u1.if_ext_irec[erp_idx];
nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; /*
/* Update next page */ * If the next irec is empty now we can simply
} else { * remove it.
/* Move rest of page up to become next new page */ */
memmove(erp_next->er_extbuf, ep_next, if (erp_next->er_extcount == 0) {
erp_next->er_extcount * sizeof(xfs_bmbt_rec_t)); /*
ep_next = erp_next->er_extbuf; * Free page before removing extent record
memset(&ep_next[erp_next->er_extcount], 0, * so er_extoffs don't get modified in
(XFS_LINEAR_EXTS - erp_next->er_extcount) * * xfs_iext_irec_remove.
sizeof(xfs_bmbt_rec_t)); */
kmem_free(erp_next->er_extbuf);
erp_next->er_extbuf = NULL;
xfs_iext_irec_remove(ifp, erp_idx + 1);
erp = &ifp->if_u1.if_ext_irec[erp_idx];
nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
/*
* If the next irec is not empty move up the content
* that has not been copied to the previous page to
* the beggining of this one.
*/
} else {
memmove(erp_next->er_extbuf, &ep_next[ext_diff],
erp_next->er_extcount *
sizeof(xfs_bmbt_rec_t));
ep_next = erp_next->er_extbuf;
memset(&ep_next[erp_next->er_extcount], 0,
(XFS_LINEAR_EXTS -
erp_next->er_extcount) *
sizeof(xfs_bmbt_rec_t));
}
} }
if (erp->er_extcount == XFS_LINEAR_EXTS) { if (erp->er_extcount == XFS_LINEAR_EXTS) {
erp_idx++; erp_idx++;
if (erp_idx < nlists) if (erp_idx < nlists)

View File

@ -507,9 +507,6 @@ int xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
xfs_fsize_t, int, int); xfs_fsize_t, int, int);
int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
int xfs_igrow_start(xfs_inode_t *, xfs_fsize_t, struct cred *);
void xfs_igrow_finish(struct xfs_trans *, xfs_inode_t *,
xfs_fsize_t, int);
void xfs_idestroy_fork(xfs_inode_t *, int); void xfs_idestroy_fork(xfs_inode_t *, int);
void xfs_idestroy(xfs_inode_t *); void xfs_idestroy(xfs_inode_t *);

View File

@ -686,7 +686,7 @@ xfs_inode_item_unlock(
ASSERT(ip->i_d.di_nextents > 0); ASSERT(ip->i_d.di_nextents > 0);
ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT); ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT);
ASSERT(ip->i_df.if_bytes > 0); ASSERT(ip->i_df.if_bytes > 0);
kmem_free(iip->ili_extents_buf, ip->i_df.if_bytes); kmem_free(iip->ili_extents_buf);
iip->ili_extents_buf = NULL; iip->ili_extents_buf = NULL;
} }
if (iip->ili_aextents_buf != NULL) { if (iip->ili_aextents_buf != NULL) {
@ -694,7 +694,7 @@ xfs_inode_item_unlock(
ASSERT(ip->i_d.di_anextents > 0); ASSERT(ip->i_d.di_anextents > 0);
ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT); ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT);
ASSERT(ip->i_afp->if_bytes > 0); ASSERT(ip->i_afp->if_bytes > 0);
kmem_free(iip->ili_aextents_buf, ip->i_afp->if_bytes); kmem_free(iip->ili_aextents_buf);
iip->ili_aextents_buf = NULL; iip->ili_aextents_buf = NULL;
} }
@ -957,8 +957,7 @@ xfs_inode_item_destroy(
{ {
#ifdef XFS_TRANS_DEBUG #ifdef XFS_TRANS_DEBUG
if (ip->i_itemp->ili_root_size != 0) { if (ip->i_itemp->ili_root_size != 0) {
kmem_free(ip->i_itemp->ili_orig_root, kmem_free(ip->i_itemp->ili_orig_root);
ip->i_itemp->ili_root_size);
} }
#endif #endif
kmem_zone_free(xfs_ili_zone, ip->i_itemp); kmem_zone_free(xfs_ili_zone, ip->i_itemp);

View File

@ -889,6 +889,16 @@ xfs_iomap_write_unwritten(
count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb); count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb);
/*
* Reserve enough blocks in this transaction for two complete extent
* btree splits. We may be converting the middle part of an unwritten
* extent and in this case we will insert two new extents in the btree
* each of which could cause a full split.
*
* This reservation amount will be used in the first call to
* xfs_bmbt_split() to select an AG with enough space to satisfy the
* rest of the operation.
*/
resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1; resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1;
do { do {

View File

@ -257,7 +257,7 @@ xfs_bulkstat_one(
*ubused = error; *ubused = error;
out_free: out_free:
kmem_free(buf, sizeof(*buf)); kmem_free(buf);
return error; return error;
} }
@ -708,7 +708,7 @@ xfs_bulkstat(
/* /*
* Done, we're either out of filesystem or space to put the data. * Done, we're either out of filesystem or space to put the data.
*/ */
kmem_free(irbuf, irbsize); kmem_free(irbuf);
*ubcountp = ubelem; *ubcountp = ubelem;
/* /*
* Found some inodes, return them now and return the error next time. * Found some inodes, return them now and return the error next time.
@ -914,7 +914,7 @@ xfs_inumbers(
} }
*lastino = XFS_AGINO_TO_INO(mp, agno, agino); *lastino = XFS_AGINO_TO_INO(mp, agno, agino);
} }
kmem_free(buffer, bcount * sizeof(*buffer)); kmem_free(buffer);
if (cur) if (cur)
xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR : xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR :
XFS_BTREE_NOERROR)); XFS_BTREE_NOERROR));

View File

@ -226,20 +226,24 @@ xlog_grant_sub_space(struct log *log, int bytes)
static void static void
xlog_grant_add_space_write(struct log *log, int bytes) xlog_grant_add_space_write(struct log *log, int bytes)
{ {
log->l_grant_write_bytes += bytes; int tmp = log->l_logsize - log->l_grant_write_bytes;
if (log->l_grant_write_bytes > log->l_logsize) { if (tmp > bytes)
log->l_grant_write_bytes -= log->l_logsize; log->l_grant_write_bytes += bytes;
else {
log->l_grant_write_cycle++; log->l_grant_write_cycle++;
log->l_grant_write_bytes = bytes - tmp;
} }
} }
static void static void
xlog_grant_add_space_reserve(struct log *log, int bytes) xlog_grant_add_space_reserve(struct log *log, int bytes)
{ {
log->l_grant_reserve_bytes += bytes; int tmp = log->l_logsize - log->l_grant_reserve_bytes;
if (log->l_grant_reserve_bytes > log->l_logsize) { if (tmp > bytes)
log->l_grant_reserve_bytes -= log->l_logsize; log->l_grant_reserve_bytes += bytes;
else {
log->l_grant_reserve_cycle++; log->l_grant_reserve_cycle++;
log->l_grant_reserve_bytes = bytes - tmp;
} }
} }
@ -1228,7 +1232,7 @@ xlog_alloc_log(xfs_mount_t *mp,
spin_lock_init(&log->l_icloglock); spin_lock_init(&log->l_icloglock);
spin_lock_init(&log->l_grant_lock); spin_lock_init(&log->l_grant_lock);
initnsema(&log->l_flushsema, 0, "ic-flush"); sv_init(&log->l_flush_wait, 0, "flush_wait");
/* log record size must be multiple of BBSIZE; see xlog_rec_header_t */ /* log record size must be multiple of BBSIZE; see xlog_rec_header_t */
ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0); ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0);
@ -1570,10 +1574,9 @@ xlog_dealloc_log(xlog_t *log)
} }
#endif #endif
next_iclog = iclog->ic_next; next_iclog = iclog->ic_next;
kmem_free(iclog, sizeof(xlog_in_core_t)); kmem_free(iclog);
iclog = next_iclog; iclog = next_iclog;
} }
freesema(&log->l_flushsema);
spinlock_destroy(&log->l_icloglock); spinlock_destroy(&log->l_icloglock);
spinlock_destroy(&log->l_grant_lock); spinlock_destroy(&log->l_grant_lock);
@ -1587,7 +1590,7 @@ xlog_dealloc_log(xlog_t *log)
} }
#endif #endif
log->l_mp->m_log = NULL; log->l_mp->m_log = NULL;
kmem_free(log, sizeof(xlog_t)); kmem_free(log);
} /* xlog_dealloc_log */ } /* xlog_dealloc_log */
/* /*
@ -2097,6 +2100,7 @@ xlog_state_do_callback(
int funcdidcallbacks; /* flag: function did callbacks */ int funcdidcallbacks; /* flag: function did callbacks */
int repeats; /* for issuing console warnings if int repeats; /* for issuing console warnings if
* looping too many times */ * looping too many times */
int wake = 0;
spin_lock(&log->l_icloglock); spin_lock(&log->l_icloglock);
first_iclog = iclog = log->l_iclog; first_iclog = iclog = log->l_iclog;
@ -2278,15 +2282,13 @@ xlog_state_do_callback(
} }
#endif #endif
flushcnt = 0; if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR))
if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) { wake = 1;
flushcnt = log->l_flushcnt;
log->l_flushcnt = 0;
}
spin_unlock(&log->l_icloglock); spin_unlock(&log->l_icloglock);
while (flushcnt--)
vsema(&log->l_flushsema); if (wake)
} /* xlog_state_do_callback */ sv_broadcast(&log->l_flush_wait);
}
/* /*
@ -2384,16 +2386,15 @@ restart:
} }
iclog = log->l_iclog; iclog = log->l_iclog;
if (! (iclog->ic_state == XLOG_STATE_ACTIVE)) { if (iclog->ic_state != XLOG_STATE_ACTIVE) {
log->l_flushcnt++;
spin_unlock(&log->l_icloglock);
xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH); xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH);
XFS_STATS_INC(xs_log_noiclogs); XFS_STATS_INC(xs_log_noiclogs);
/* Ensure that log writes happen */
psema(&log->l_flushsema, PINOD); /* Wait for log writes to have flushed */
sv_wait(&log->l_flush_wait, 0, &log->l_icloglock, 0);
goto restart; goto restart;
} }
ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE);
head = &iclog->ic_header; head = &iclog->ic_header;
atomic_inc(&iclog->ic_refcnt); /* prevents sync */ atomic_inc(&iclog->ic_refcnt); /* prevents sync */

View File

@ -423,10 +423,8 @@ typedef struct log {
int l_logBBsize; /* size of log in BB chunks */ int l_logBBsize; /* size of log in BB chunks */
/* The following block of fields are changed while holding icloglock */ /* The following block of fields are changed while holding icloglock */
sema_t l_flushsema ____cacheline_aligned_in_smp; sv_t l_flush_wait ____cacheline_aligned_in_smp;
/* iclog flushing semaphore */ /* waiting for iclog flush */
int l_flushcnt; /* # of procs waiting on this
* sema */
int l_covered_state;/* state of "covering disk int l_covered_state;/* state of "covering disk
* log entries" */ * log entries" */
xlog_in_core_t *l_iclog; /* head log queue */ xlog_in_core_t *l_iclog; /* head log queue */

View File

@ -1715,8 +1715,7 @@ xlog_check_buffer_cancelled(
} else { } else {
prevp->bc_next = bcp->bc_next; prevp->bc_next = bcp->bc_next;
} }
kmem_free(bcp, kmem_free(bcp);
sizeof(xfs_buf_cancel_t));
} }
} }
return 1; return 1;
@ -2519,7 +2518,7 @@ write_inode_buffer:
error: error:
if (need_free) if (need_free)
kmem_free(in_f, sizeof(*in_f)); kmem_free(in_f);
return XFS_ERROR(error); return XFS_ERROR(error);
} }
@ -2830,16 +2829,14 @@ xlog_recover_free_trans(
item = item->ri_next; item = item->ri_next;
/* Free the regions in the item. */ /* Free the regions in the item. */
for (i = 0; i < free_item->ri_cnt; i++) { for (i = 0; i < free_item->ri_cnt; i++) {
kmem_free(free_item->ri_buf[i].i_addr, kmem_free(free_item->ri_buf[i].i_addr);
free_item->ri_buf[i].i_len);
} }
/* Free the item itself */ /* Free the item itself */
kmem_free(free_item->ri_buf, kmem_free(free_item->ri_buf);
(free_item->ri_total * sizeof(xfs_log_iovec_t))); kmem_free(free_item);
kmem_free(free_item, sizeof(xlog_recover_item_t));
} while (first_item != item); } while (first_item != item);
/* Free the transaction recover structure */ /* Free the transaction recover structure */
kmem_free(trans, sizeof(xlog_recover_t)); kmem_free(trans);
} }
STATIC int STATIC int
@ -3786,8 +3783,7 @@ xlog_do_log_recovery(
error = xlog_do_recovery_pass(log, head_blk, tail_blk, error = xlog_do_recovery_pass(log, head_blk, tail_blk,
XLOG_RECOVER_PASS1); XLOG_RECOVER_PASS1);
if (error != 0) { if (error != 0) {
kmem_free(log->l_buf_cancel_table, kmem_free(log->l_buf_cancel_table);
XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*));
log->l_buf_cancel_table = NULL; log->l_buf_cancel_table = NULL;
return error; return error;
} }
@ -3806,8 +3802,7 @@ xlog_do_log_recovery(
} }
#endif /* DEBUG */ #endif /* DEBUG */
kmem_free(log->l_buf_cancel_table, kmem_free(log->l_buf_cancel_table);
XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*));
log->l_buf_cancel_table = NULL; log->l_buf_cancel_table = NULL;
return error; return error;

View File

@ -47,12 +47,10 @@
STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t); STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t);
STATIC int xfs_uuid_mount(xfs_mount_t *); STATIC int xfs_uuid_mount(xfs_mount_t *);
STATIC void xfs_uuid_unmount(xfs_mount_t *mp);
STATIC void xfs_unmountfs_wait(xfs_mount_t *); STATIC void xfs_unmountfs_wait(xfs_mount_t *);
#ifdef HAVE_PERCPU_SB #ifdef HAVE_PERCPU_SB
STATIC void xfs_icsb_destroy_counters(xfs_mount_t *);
STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t,
int); int);
STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t, STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t,
@ -63,7 +61,6 @@ STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
#else #else
#define xfs_icsb_destroy_counters(mp) do { } while (0)
#define xfs_icsb_balance_counter(mp, a, b) do { } while (0) #define xfs_icsb_balance_counter(mp, a, b) do { } while (0)
#define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0) #define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0)
#define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0) #define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0)
@ -125,34 +122,12 @@ static const struct {
{ sizeof(xfs_sb_t), 0 } { sizeof(xfs_sb_t), 0 }
}; };
/*
* Return a pointer to an initialized xfs_mount structure.
*/
xfs_mount_t *
xfs_mount_init(void)
{
xfs_mount_t *mp;
mp = kmem_zalloc(sizeof(xfs_mount_t), KM_SLEEP);
if (xfs_icsb_init_counters(mp)) {
mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB;
}
spin_lock_init(&mp->m_sb_lock);
mutex_init(&mp->m_ilock);
mutex_init(&mp->m_growlock);
atomic_set(&mp->m_active_trans, 0);
return mp;
}
/* /*
* Free up the resources associated with a mount structure. Assume that * Free up the resources associated with a mount structure. Assume that
* the structure was initially zeroed, so we can tell which fields got * the structure was initially zeroed, so we can tell which fields got
* initialized. * initialized.
*/ */
void STATIC void
xfs_mount_free( xfs_mount_free(
xfs_mount_t *mp) xfs_mount_t *mp)
{ {
@ -161,11 +136,8 @@ xfs_mount_free(
for (agno = 0; agno < mp->m_maxagi; agno++) for (agno = 0; agno < mp->m_maxagi; agno++)
if (mp->m_perag[agno].pagb_list) if (mp->m_perag[agno].pagb_list)
kmem_free(mp->m_perag[agno].pagb_list, kmem_free(mp->m_perag[agno].pagb_list);
sizeof(xfs_perag_busy_t) * kmem_free(mp->m_perag);
XFS_PAGB_NUM_SLOTS);
kmem_free(mp->m_perag,
sizeof(xfs_perag_t) * mp->m_sb.sb_agcount);
} }
spinlock_destroy(&mp->m_ail_lock); spinlock_destroy(&mp->m_ail_lock);
@ -176,13 +148,11 @@ xfs_mount_free(
XFS_QM_DONE(mp); XFS_QM_DONE(mp);
if (mp->m_fsname != NULL) if (mp->m_fsname != NULL)
kmem_free(mp->m_fsname, mp->m_fsname_len); kmem_free(mp->m_fsname);
if (mp->m_rtname != NULL) if (mp->m_rtname != NULL)
kmem_free(mp->m_rtname, strlen(mp->m_rtname) + 1); kmem_free(mp->m_rtname);
if (mp->m_logname != NULL) if (mp->m_logname != NULL)
kmem_free(mp->m_logname, strlen(mp->m_logname) + 1); kmem_free(mp->m_logname);
xfs_icsb_destroy_counters(mp);
} }
/* /*
@ -288,6 +258,19 @@ xfs_mount_validate_sb(
return XFS_ERROR(EFSCORRUPTED); return XFS_ERROR(EFSCORRUPTED);
} }
/*
* Until this is fixed only page-sized or smaller data blocks work.
*/
if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
xfs_fs_mount_cmn_err(flags,
"file system with blocksize %d bytes",
sbp->sb_blocksize);
xfs_fs_mount_cmn_err(flags,
"only pagesize (%ld) or less will currently work.",
PAGE_SIZE);
return XFS_ERROR(ENOSYS);
}
if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
xfs_fs_mount_cmn_err(flags, xfs_fs_mount_cmn_err(flags,
@ -309,19 +292,6 @@ xfs_mount_validate_sb(
return XFS_ERROR(ENOSYS); return XFS_ERROR(ENOSYS);
} }
/*
* Until this is fixed only page-sized or smaller data blocks work.
*/
if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
xfs_fs_mount_cmn_err(flags,
"file system with blocksize %d bytes",
sbp->sb_blocksize);
xfs_fs_mount_cmn_err(flags,
"only pagesize (%ld) or less will currently work.",
PAGE_SIZE);
return XFS_ERROR(ENOSYS);
}
return 0; return 0;
} }
@ -994,9 +964,19 @@ xfs_mountfs(
* Re-check for ATTR2 in case it was found in bad_features2 * Re-check for ATTR2 in case it was found in bad_features2
* slot. * slot.
*/ */
if (xfs_sb_version_hasattr2(&mp->m_sb)) if (xfs_sb_version_hasattr2(&mp->m_sb) &&
!(mp->m_flags & XFS_MOUNT_NOATTR2))
mp->m_flags |= XFS_MOUNT_ATTR2; mp->m_flags |= XFS_MOUNT_ATTR2;
}
if (xfs_sb_version_hasattr2(&mp->m_sb) &&
(mp->m_flags & XFS_MOUNT_NOATTR2)) {
xfs_sb_version_removeattr2(&mp->m_sb);
update_flags |= XFS_SB_FEATURES2;
/* update sb_versionnum for the clearing of the morebits */
if (!sbp->sb_features2)
update_flags |= XFS_SB_VERSIONNUM;
} }
/* /*
@ -1255,15 +1235,13 @@ xfs_mountfs(
error2: error2:
for (agno = 0; agno < sbp->sb_agcount; agno++) for (agno = 0; agno < sbp->sb_agcount; agno++)
if (mp->m_perag[agno].pagb_list) if (mp->m_perag[agno].pagb_list)
kmem_free(mp->m_perag[agno].pagb_list, kmem_free(mp->m_perag[agno].pagb_list);
sizeof(xfs_perag_busy_t) * XFS_PAGB_NUM_SLOTS); kmem_free(mp->m_perag);
kmem_free(mp->m_perag, sbp->sb_agcount * sizeof(xfs_perag_t));
mp->m_perag = NULL; mp->m_perag = NULL;
/* FALLTHROUGH */ /* FALLTHROUGH */
error1: error1:
if (uuid_mounted) if (uuid_mounted)
xfs_uuid_unmount(mp); uuid_table_remove(&mp->m_sb.sb_uuid);
xfs_freesb(mp);
return error; return error;
} }
@ -1274,7 +1252,7 @@ xfs_mountfs(
* log and makes sure that incore structures are freed. * log and makes sure that incore structures are freed.
*/ */
int int
xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) xfs_unmountfs(xfs_mount_t *mp)
{ {
__uint64_t resblks; __uint64_t resblks;
int error = 0; int error = 0;
@ -1341,9 +1319,8 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
*/ */
ASSERT(mp->m_inodes == NULL); ASSERT(mp->m_inodes == NULL);
xfs_unmountfs_close(mp, cr);
if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0)
xfs_uuid_unmount(mp); uuid_table_remove(&mp->m_sb.sb_uuid);
#if defined(DEBUG) || defined(INDUCE_IO_ERROR) #if defined(DEBUG) || defined(INDUCE_IO_ERROR)
xfs_errortag_clearall(mp, 0); xfs_errortag_clearall(mp, 0);
@ -1352,16 +1329,6 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
return 0; return 0;
} }
void
xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr)
{
if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
xfs_free_buftarg(mp->m_logdev_targp, 1);
if (mp->m_rtdev_targp)
xfs_free_buftarg(mp->m_rtdev_targp, 1);
xfs_free_buftarg(mp->m_ddev_targp, 0);
}
STATIC void STATIC void
xfs_unmountfs_wait(xfs_mount_t *mp) xfs_unmountfs_wait(xfs_mount_t *mp)
{ {
@ -1904,16 +1871,6 @@ xfs_uuid_mount(
return 0; return 0;
} }
/*
* Remove filesystem from the UUID table.
*/
STATIC void
xfs_uuid_unmount(
xfs_mount_t *mp)
{
uuid_table_remove(&mp->m_sb.sb_uuid);
}
/* /*
* Used to log changes to the superblock unit and width fields which could * Used to log changes to the superblock unit and width fields which could
* be altered by the mount options, as well as any potential sb_features2 * be altered by the mount options, as well as any potential sb_features2
@ -1928,7 +1885,8 @@ xfs_mount_log_sb(
int error; int error;
ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID | ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID |
XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2)); XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2 |
XFS_SB_VERSIONNUM));
tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);
error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
@ -2109,7 +2067,7 @@ xfs_icsb_reinit_counters(
xfs_icsb_unlock(mp); xfs_icsb_unlock(mp);
} }
STATIC void void
xfs_icsb_destroy_counters( xfs_icsb_destroy_counters(
xfs_mount_t *mp) xfs_mount_t *mp)
{ {

View File

@ -61,6 +61,7 @@ struct xfs_bmap_free;
struct xfs_extdelta; struct xfs_extdelta;
struct xfs_swapext; struct xfs_swapext;
struct xfs_mru_cache; struct xfs_mru_cache;
struct xfs_nameops;
/* /*
* Prototypes and functions for the Data Migration subsystem. * Prototypes and functions for the Data Migration subsystem.
@ -210,12 +211,14 @@ typedef struct xfs_icsb_cnts {
extern int xfs_icsb_init_counters(struct xfs_mount *); extern int xfs_icsb_init_counters(struct xfs_mount *);
extern void xfs_icsb_reinit_counters(struct xfs_mount *); extern void xfs_icsb_reinit_counters(struct xfs_mount *);
extern void xfs_icsb_destroy_counters(struct xfs_mount *);
extern void xfs_icsb_sync_counters(struct xfs_mount *, int); extern void xfs_icsb_sync_counters(struct xfs_mount *, int);
extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int); extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int);
#else #else
#define xfs_icsb_init_counters(mp) (0) #define xfs_icsb_init_counters(mp) (0)
#define xfs_icsb_reinit_counters(mp) do { } while (0) #define xfs_icsb_destroy_counters(mp) do { } while (0)
#define xfs_icsb_reinit_counters(mp) do { } while (0)
#define xfs_icsb_sync_counters(mp, flags) do { } while (0) #define xfs_icsb_sync_counters(mp, flags) do { } while (0)
#define xfs_icsb_sync_counters_locked(mp, flags) do { } while (0) #define xfs_icsb_sync_counters_locked(mp, flags) do { } while (0)
#endif #endif
@ -313,6 +316,7 @@ typedef struct xfs_mount {
__uint8_t m_inode_quiesce;/* call quiesce on new inodes. __uint8_t m_inode_quiesce;/* call quiesce on new inodes.
field governed by m_ilock */ field governed by m_ilock */
__uint8_t m_sectbb_log; /* sectlog - BBSHIFT */ __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 */ int m_dirblksize; /* directory block sz--bytes */
int m_dirblkfsbs; /* directory block sz--fsbs */ int m_dirblkfsbs; /* directory block sz--fsbs */
xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */
@ -378,6 +382,7 @@ typedef struct xfs_mount {
counters */ counters */
#define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams #define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams
allocator */ allocator */
#define XFS_MOUNT_NOATTR2 (1ULL << 25) /* disable use of attr2 format */
/* /*
@ -510,15 +515,12 @@ typedef struct xfs_mod_sb {
#define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock)) #define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock))
#define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock)) #define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock))
extern xfs_mount_t *xfs_mount_init(void);
extern void xfs_mod_sb(xfs_trans_t *, __int64_t); extern void xfs_mod_sb(xfs_trans_t *, __int64_t);
extern int xfs_log_sbcount(xfs_mount_t *, uint); extern int xfs_log_sbcount(xfs_mount_t *, uint);
extern void xfs_mount_free(xfs_mount_t *mp);
extern int xfs_mountfs(xfs_mount_t *mp, int); extern int xfs_mountfs(xfs_mount_t *mp, int);
extern void xfs_mountfs_check_barriers(xfs_mount_t *mp); extern void xfs_mountfs_check_barriers(xfs_mount_t *mp);
extern int xfs_unmountfs(xfs_mount_t *, struct cred *); extern int xfs_unmountfs(xfs_mount_t *);
extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *);
extern int xfs_unmountfs_writesb(xfs_mount_t *); extern int xfs_unmountfs_writesb(xfs_mount_t *);
extern int xfs_unmount_flush(xfs_mount_t *, int); 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(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
@ -544,9 +546,6 @@ extern void xfs_qmops_put(struct xfs_mount *);
extern struct xfs_dmops xfs_dmcore_xfs; extern struct xfs_dmops xfs_dmcore_xfs;
extern int xfs_init(void);
extern void xfs_cleanup(void);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __XFS_MOUNT_H__ */ #endif /* __XFS_MOUNT_H__ */

View File

@ -307,15 +307,18 @@ xfs_mru_cache_init(void)
xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t), xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t),
"xfs_mru_cache_elem"); "xfs_mru_cache_elem");
if (!xfs_mru_elem_zone) if (!xfs_mru_elem_zone)
return ENOMEM; goto out;
xfs_mru_reap_wq = create_singlethread_workqueue("xfs_mru_cache"); xfs_mru_reap_wq = create_singlethread_workqueue("xfs_mru_cache");
if (!xfs_mru_reap_wq) { if (!xfs_mru_reap_wq)
kmem_zone_destroy(xfs_mru_elem_zone); goto out_destroy_mru_elem_zone;
return ENOMEM;
}
return 0; return 0;
out_destroy_mru_elem_zone:
kmem_zone_destroy(xfs_mru_elem_zone);
out:
return -ENOMEM;
} }
void void
@ -382,9 +385,9 @@ xfs_mru_cache_create(
exit: exit:
if (err && mru && mru->lists) if (err && mru && mru->lists)
kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists)); kmem_free(mru->lists);
if (err && mru) if (err && mru)
kmem_free(mru, sizeof(*mru)); kmem_free(mru);
return err; return err;
} }
@ -424,8 +427,8 @@ xfs_mru_cache_destroy(
xfs_mru_cache_flush(mru); xfs_mru_cache_flush(mru);
kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists)); kmem_free(mru->lists);
kmem_free(mru, sizeof(*mru)); kmem_free(mru);
} }
/* /*

View File

@ -336,21 +336,17 @@ xfs_rename(
ASSERT(error != EEXIST); ASSERT(error != EEXIST);
if (error) if (error)
goto abort_return; goto abort_return;
xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
} else {
/*
* We always want to hit the ctime on the source inode.
* We do it in the if clause above for the 'new_parent &&
* src_is_directory' case, and here we get all the other
* cases. This isn't strictly required by the standards
* since the source inode isn't really being changed,
* but old unix file systems did it and some incremental
* backup programs won't work without it.
*/
xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG);
} }
/*
* We always want to hit the ctime on the source inode.
*
* This isn't strictly required by the standards since the source
* inode isn't really being changed, but old unix file systems did
* it and some incremental backup programs won't work without it.
*/
xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG);
/* /*
* Adjust the link count on src_dp. This is necessary when * Adjust the link count on src_dp. This is necessary when
* renaming a directory, either within one parent when * renaming a directory, either within one parent when

View File

@ -2062,7 +2062,7 @@ xfs_growfs_rt(
/* /*
* Free the fake mp structure. * Free the fake mp structure.
*/ */
kmem_free(nmp, sizeof(*nmp)); kmem_free(nmp);
return error; return error;
} }

View File

@ -46,10 +46,12 @@ struct xfs_mount;
#define XFS_SB_VERSION_SECTORBIT 0x0800 #define XFS_SB_VERSION_SECTORBIT 0x0800
#define XFS_SB_VERSION_EXTFLGBIT 0x1000 #define XFS_SB_VERSION_EXTFLGBIT 0x1000
#define XFS_SB_VERSION_DIRV2BIT 0x2000 #define XFS_SB_VERSION_DIRV2BIT 0x2000
#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */
#define XFS_SB_VERSION_MOREBITSBIT 0x8000 #define XFS_SB_VERSION_MOREBITSBIT 0x8000
#define XFS_SB_VERSION_OKSASHFBITS \ #define XFS_SB_VERSION_OKSASHFBITS \
(XFS_SB_VERSION_EXTFLGBIT | \ (XFS_SB_VERSION_EXTFLGBIT | \
XFS_SB_VERSION_DIRV2BIT) XFS_SB_VERSION_DIRV2BIT | \
XFS_SB_VERSION_BORGBIT)
#define XFS_SB_VERSION_OKREALFBITS \ #define XFS_SB_VERSION_OKREALFBITS \
(XFS_SB_VERSION_ATTRBIT | \ (XFS_SB_VERSION_ATTRBIT | \
XFS_SB_VERSION_NLINKBIT | \ XFS_SB_VERSION_NLINKBIT | \
@ -437,6 +439,12 @@ static inline int xfs_sb_version_hassector(xfs_sb_t *sbp)
((sbp)->sb_versionnum & XFS_SB_VERSION_SECTORBIT); ((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) && \
(sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT);
}
static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp) static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
{ {
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
@ -473,6 +481,13 @@ static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp)
((sbp)->sb_features2 | XFS_SB_VERSION2_ATTR2BIT))); ((sbp)->sb_features2 | XFS_SB_VERSION2_ATTR2BIT)));
} }
static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp)
{
sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT;
if (!sbp->sb_features2)
sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT;
}
/* /*
* end of superblock version macros * end of superblock version macros
*/ */

View File

@ -889,7 +889,7 @@ shut_us_down:
tp->t_commit_lsn = commit_lsn; tp->t_commit_lsn = commit_lsn;
if (nvec > XFS_TRANS_LOGVEC_COUNT) { if (nvec > XFS_TRANS_LOGVEC_COUNT) {
kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t)); kmem_free(log_vector);
} }
/* /*
@ -1265,7 +1265,7 @@ xfs_trans_committed(
ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag);
next_licp = licp->lic_next; next_licp = licp->lic_next;
kmem_free(licp, sizeof(xfs_log_item_chunk_t)); kmem_free(licp);
licp = next_licp; licp = next_licp;
} }

View File

@ -291,7 +291,7 @@ xfs_trans_inode_broot_debug(
iip = ip->i_itemp; iip = ip->i_itemp;
if (iip->ili_root_size != 0) { if (iip->ili_root_size != 0) {
ASSERT(iip->ili_orig_root != NULL); ASSERT(iip->ili_orig_root != NULL);
kmem_free(iip->ili_orig_root, iip->ili_root_size); kmem_free(iip->ili_orig_root);
iip->ili_root_size = 0; iip->ili_root_size = 0;
iip->ili_orig_root = NULL; iip->ili_orig_root = NULL;
} }

View File

@ -161,7 +161,7 @@ xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
licpp = &((*licpp)->lic_next); licpp = &((*licpp)->lic_next);
} }
*licpp = licp->lic_next; *licpp = licp->lic_next;
kmem_free(licp, sizeof(xfs_log_item_chunk_t)); kmem_free(licp);
tp->t_items_free -= XFS_LIC_NUM_SLOTS; tp->t_items_free -= XFS_LIC_NUM_SLOTS;
} }
} }
@ -314,7 +314,7 @@ xfs_trans_free_items(
ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
(void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN);
next_licp = licp->lic_next; next_licp = licp->lic_next;
kmem_free(licp, sizeof(xfs_log_item_chunk_t)); kmem_free(licp);
licp = next_licp; licp = next_licp;
} }
@ -363,7 +363,7 @@ xfs_trans_unlock_items(xfs_trans_t *tp, xfs_lsn_t commit_lsn)
next_licp = licp->lic_next; next_licp = licp->lic_next;
if (XFS_LIC_ARE_ALL_FREE(licp)) { if (XFS_LIC_ARE_ALL_FREE(licp)) {
*licpp = next_licp; *licpp = next_licp;
kmem_free(licp, sizeof(xfs_log_item_chunk_t)); kmem_free(licp);
freed -= XFS_LIC_NUM_SLOTS; freed -= XFS_LIC_NUM_SLOTS;
} else { } else {
licpp = &(licp->lic_next); licpp = &(licp->lic_next);
@ -530,7 +530,7 @@ xfs_trans_free_busy(xfs_trans_t *tp)
lbcp = tp->t_busy.lbc_next; lbcp = tp->t_busy.lbc_next;
while (lbcp != NULL) { while (lbcp != NULL) {
lbcq = lbcp->lbc_next; lbcq = lbcp->lbc_next;
kmem_free(lbcp, sizeof(xfs_log_busy_chunk_t)); kmem_free(lbcp);
lbcp = lbcq; lbcp = lbcq;
} }

View File

@ -58,586 +58,6 @@
#include "xfs_utils.h" #include "xfs_utils.h"
int __init
xfs_init(void)
{
#ifdef XFS_DABUF_DEBUG
extern spinlock_t xfs_dabuf_global_lock;
spin_lock_init(&xfs_dabuf_global_lock);
#endif
/*
* Initialize all of the zone allocators we use.
*/
xfs_log_ticket_zone = kmem_zone_init(sizeof(xlog_ticket_t),
"xfs_log_ticket");
xfs_bmap_free_item_zone = kmem_zone_init(sizeof(xfs_bmap_free_item_t),
"xfs_bmap_free_item");
xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t),
"xfs_btree_cur");
xfs_da_state_zone = kmem_zone_init(sizeof(xfs_da_state_t),
"xfs_da_state");
xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf");
xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork");
xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans");
xfs_acl_zone_init(xfs_acl_zone, "xfs_acl");
xfs_mru_cache_init();
xfs_filestream_init();
/*
* The size of the zone allocated buf log item is the maximum
* size possible under XFS. This wastes a little bit of memory,
* but it is much faster.
*/
xfs_buf_item_zone =
kmem_zone_init((sizeof(xfs_buf_log_item_t) +
(((XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK) /
NBWORD) * sizeof(int))),
"xfs_buf_item");
xfs_efd_zone =
kmem_zone_init((sizeof(xfs_efd_log_item_t) +
((XFS_EFD_MAX_FAST_EXTENTS - 1) *
sizeof(xfs_extent_t))),
"xfs_efd_item");
xfs_efi_zone =
kmem_zone_init((sizeof(xfs_efi_log_item_t) +
((XFS_EFI_MAX_FAST_EXTENTS - 1) *
sizeof(xfs_extent_t))),
"xfs_efi_item");
/*
* These zones warrant special memory allocator hints
*/
xfs_inode_zone =
kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode",
KM_ZONE_HWALIGN | KM_ZONE_RECLAIM |
KM_ZONE_SPREAD, NULL);
xfs_ili_zone =
kmem_zone_init_flags(sizeof(xfs_inode_log_item_t), "xfs_ili",
KM_ZONE_SPREAD, NULL);
/*
* Allocate global trace buffers.
*/
#ifdef XFS_ALLOC_TRACE
xfs_alloc_trace_buf = ktrace_alloc(XFS_ALLOC_TRACE_SIZE, KM_SLEEP);
#endif
#ifdef XFS_BMAP_TRACE
xfs_bmap_trace_buf = ktrace_alloc(XFS_BMAP_TRACE_SIZE, KM_SLEEP);
#endif
#ifdef XFS_BMBT_TRACE
xfs_bmbt_trace_buf = ktrace_alloc(XFS_BMBT_TRACE_SIZE, KM_SLEEP);
#endif
#ifdef XFS_ATTR_TRACE
xfs_attr_trace_buf = ktrace_alloc(XFS_ATTR_TRACE_SIZE, KM_SLEEP);
#endif
#ifdef XFS_DIR2_TRACE
xfs_dir2_trace_buf = ktrace_alloc(XFS_DIR2_GTRACE_SIZE, KM_SLEEP);
#endif
xfs_dir_startup();
#if (defined(DEBUG) || defined(INDUCE_IO_ERROR))
xfs_error_test_init();
#endif /* DEBUG || INDUCE_IO_ERROR */
xfs_init_procfs();
xfs_sysctl_register();
return 0;
}
void __exit
xfs_cleanup(void)
{
extern kmem_zone_t *xfs_inode_zone;
extern kmem_zone_t *xfs_efd_zone;
extern kmem_zone_t *xfs_efi_zone;
xfs_cleanup_procfs();
xfs_sysctl_unregister();
xfs_filestream_uninit();
xfs_mru_cache_uninit();
xfs_acl_zone_destroy(xfs_acl_zone);
#ifdef XFS_DIR2_TRACE
ktrace_free(xfs_dir2_trace_buf);
#endif
#ifdef XFS_ATTR_TRACE
ktrace_free(xfs_attr_trace_buf);
#endif
#ifdef XFS_BMBT_TRACE
ktrace_free(xfs_bmbt_trace_buf);
#endif
#ifdef XFS_BMAP_TRACE
ktrace_free(xfs_bmap_trace_buf);
#endif
#ifdef XFS_ALLOC_TRACE
ktrace_free(xfs_alloc_trace_buf);
#endif
kmem_zone_destroy(xfs_bmap_free_item_zone);
kmem_zone_destroy(xfs_btree_cur_zone);
kmem_zone_destroy(xfs_inode_zone);
kmem_zone_destroy(xfs_trans_zone);
kmem_zone_destroy(xfs_da_state_zone);
kmem_zone_destroy(xfs_dabuf_zone);
kmem_zone_destroy(xfs_buf_item_zone);
kmem_zone_destroy(xfs_efd_zone);
kmem_zone_destroy(xfs_efi_zone);
kmem_zone_destroy(xfs_ifork_zone);
kmem_zone_destroy(xfs_ili_zone);
kmem_zone_destroy(xfs_log_ticket_zone);
}
/*
* xfs_start_flags
*
* This function fills in xfs_mount_t fields based on mount args.
* Note: the superblock has _not_ yet been read in.
*/
STATIC int
xfs_start_flags(
struct xfs_mount_args *ap,
struct xfs_mount *mp)
{
/* Values are in BBs */
if ((ap->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) {
/*
* At this point the superblock has not been read
* in, therefore we do not know the block size.
* Before the mount call ends we will convert
* these to FSBs.
*/
mp->m_dalign = ap->sunit;
mp->m_swidth = ap->swidth;
}
if (ap->logbufs != -1 &&
ap->logbufs != 0 &&
(ap->logbufs < XLOG_MIN_ICLOGS ||
ap->logbufs > XLOG_MAX_ICLOGS)) {
cmn_err(CE_WARN,
"XFS: invalid logbufs value: %d [not %d-%d]",
ap->logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS);
return XFS_ERROR(EINVAL);
}
mp->m_logbufs = ap->logbufs;
if (ap->logbufsize != -1 &&
ap->logbufsize != 0 &&
(ap->logbufsize < XLOG_MIN_RECORD_BSIZE ||
ap->logbufsize > XLOG_MAX_RECORD_BSIZE ||
!is_power_of_2(ap->logbufsize))) {
cmn_err(CE_WARN,
"XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
ap->logbufsize);
return XFS_ERROR(EINVAL);
}
mp->m_logbsize = ap->logbufsize;
mp->m_fsname_len = strlen(ap->fsname) + 1;
mp->m_fsname = kmem_alloc(mp->m_fsname_len, KM_SLEEP);
strcpy(mp->m_fsname, ap->fsname);
if (ap->rtname[0]) {
mp->m_rtname = kmem_alloc(strlen(ap->rtname) + 1, KM_SLEEP);
strcpy(mp->m_rtname, ap->rtname);
}
if (ap->logname[0]) {
mp->m_logname = kmem_alloc(strlen(ap->logname) + 1, KM_SLEEP);
strcpy(mp->m_logname, ap->logname);
}
if (ap->flags & XFSMNT_WSYNC)
mp->m_flags |= XFS_MOUNT_WSYNC;
#if XFS_BIG_INUMS
if (ap->flags & XFSMNT_INO64) {
mp->m_flags |= XFS_MOUNT_INO64;
mp->m_inoadd = XFS_INO64_OFFSET;
}
#endif
if (ap->flags & XFSMNT_RETERR)
mp->m_flags |= XFS_MOUNT_RETERR;
if (ap->flags & XFSMNT_NOALIGN)
mp->m_flags |= XFS_MOUNT_NOALIGN;
if (ap->flags & XFSMNT_SWALLOC)
mp->m_flags |= XFS_MOUNT_SWALLOC;
if (ap->flags & XFSMNT_OSYNCISOSYNC)
mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC;
if (ap->flags & XFSMNT_32BITINODES)
mp->m_flags |= XFS_MOUNT_32BITINODES;
if (ap->flags & XFSMNT_IOSIZE) {
if (ap->iosizelog > XFS_MAX_IO_LOG ||
ap->iosizelog < XFS_MIN_IO_LOG) {
cmn_err(CE_WARN,
"XFS: invalid log iosize: %d [not %d-%d]",
ap->iosizelog, XFS_MIN_IO_LOG,
XFS_MAX_IO_LOG);
return XFS_ERROR(EINVAL);
}
mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE;
mp->m_readio_log = mp->m_writeio_log = ap->iosizelog;
}
if (ap->flags & XFSMNT_IKEEP)
mp->m_flags |= XFS_MOUNT_IKEEP;
if (ap->flags & XFSMNT_DIRSYNC)
mp->m_flags |= XFS_MOUNT_DIRSYNC;
if (ap->flags & XFSMNT_ATTR2)
mp->m_flags |= XFS_MOUNT_ATTR2;
if (ap->flags2 & XFSMNT2_COMPAT_IOSIZE)
mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE;
/*
* no recovery flag requires a read-only mount
*/
if (ap->flags & XFSMNT_NORECOVERY) {
if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
cmn_err(CE_WARN,
"XFS: tried to mount a FS read-write without recovery!");
return XFS_ERROR(EINVAL);
}
mp->m_flags |= XFS_MOUNT_NORECOVERY;
}
if (ap->flags & XFSMNT_NOUUID)
mp->m_flags |= XFS_MOUNT_NOUUID;
if (ap->flags & XFSMNT_BARRIER)
mp->m_flags |= XFS_MOUNT_BARRIER;
else
mp->m_flags &= ~XFS_MOUNT_BARRIER;
if (ap->flags2 & XFSMNT2_FILESTREAMS)
mp->m_flags |= XFS_MOUNT_FILESTREAMS;
if (ap->flags & XFSMNT_DMAPI)
mp->m_flags |= XFS_MOUNT_DMAPI;
return 0;
}
/*
* This function fills in xfs_mount_t fields based on mount args.
* Note: the superblock _has_ now been read in.
*/
STATIC int
xfs_finish_flags(
struct xfs_mount_args *ap,
struct xfs_mount *mp)
{
int ronly = (mp->m_flags & XFS_MOUNT_RDONLY);
/* Fail a mount where the logbuf is smaller then the log stripe */
if (xfs_sb_version_haslogv2(&mp->m_sb)) {
if ((ap->logbufsize <= 0) &&
(mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE)) {
mp->m_logbsize = mp->m_sb.sb_logsunit;
} else if (ap->logbufsize > 0 &&
ap->logbufsize < mp->m_sb.sb_logsunit) {
cmn_err(CE_WARN,
"XFS: logbuf size must be greater than or equal to log stripe size");
return XFS_ERROR(EINVAL);
}
} else {
/* Fail a mount if the logbuf is larger than 32K */
if (ap->logbufsize > XLOG_BIG_RECORD_BSIZE) {
cmn_err(CE_WARN,
"XFS: logbuf size for version 1 logs must be 16K or 32K");
return XFS_ERROR(EINVAL);
}
}
if (xfs_sb_version_hasattr2(&mp->m_sb))
mp->m_flags |= XFS_MOUNT_ATTR2;
/*
* prohibit r/w mounts of read-only filesystems
*/
if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && !ronly) {
cmn_err(CE_WARN,
"XFS: cannot mount a read-only filesystem as read-write");
return XFS_ERROR(EROFS);
}
/*
* check for shared mount.
*/
if (ap->flags & XFSMNT_SHARED) {
if (!xfs_sb_version_hasshared(&mp->m_sb))
return XFS_ERROR(EINVAL);
/*
* For IRIX 6.5, shared mounts must have the shared
* version bit set, have the persistent readonly
* field set, must be version 0 and can only be mounted
* read-only.
*/
if (!ronly || !(mp->m_sb.sb_flags & XFS_SBF_READONLY) ||
(mp->m_sb.sb_shared_vn != 0))
return XFS_ERROR(EINVAL);
mp->m_flags |= XFS_MOUNT_SHARED;
/*
* Shared XFS V0 can't deal with DMI. Return EINVAL.
*/
if (mp->m_sb.sb_shared_vn == 0 && (ap->flags & XFSMNT_DMAPI))
return XFS_ERROR(EINVAL);
}
if (ap->flags & XFSMNT_UQUOTA) {
mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
if (ap->flags & XFSMNT_UQUOTAENF)
mp->m_qflags |= XFS_UQUOTA_ENFD;
}
if (ap->flags & XFSMNT_GQUOTA) {
mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
if (ap->flags & XFSMNT_GQUOTAENF)
mp->m_qflags |= XFS_OQUOTA_ENFD;
} else if (ap->flags & XFSMNT_PQUOTA) {
mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
if (ap->flags & XFSMNT_PQUOTAENF)
mp->m_qflags |= XFS_OQUOTA_ENFD;
}
return 0;
}
/*
* xfs_mount
*
* The file system configurations are:
* (1) device (partition) with data and internal log
* (2) logical volume with data and log subvolumes.
* (3) logical volume with data, log, and realtime subvolumes.
*
* We only have to handle opening the log and realtime volumes here if
* they are present. The data subvolume has already been opened by
* get_sb_bdev() and is stored in vfsp->vfs_super->s_bdev.
*/
int
xfs_mount(
struct xfs_mount *mp,
struct xfs_mount_args *args,
cred_t *credp)
{
struct block_device *ddev, *logdev, *rtdev;
int flags = 0, error;
ddev = mp->m_super->s_bdev;
logdev = rtdev = NULL;
error = xfs_dmops_get(mp, args);
if (error)
return error;
error = xfs_qmops_get(mp, args);
if (error)
return error;
if (args->flags & XFSMNT_QUIET)
flags |= XFS_MFSI_QUIET;
/*
* Open real time and log devices - order is important.
*/
if (args->logname[0]) {
error = xfs_blkdev_get(mp, args->logname, &logdev);
if (error)
return error;
}
if (args->rtname[0]) {
error = xfs_blkdev_get(mp, args->rtname, &rtdev);
if (error) {
xfs_blkdev_put(logdev);
return error;
}
if (rtdev == ddev || rtdev == logdev) {
cmn_err(CE_WARN,
"XFS: Cannot mount filesystem with identical rtdev and ddev/logdev.");
xfs_blkdev_put(logdev);
xfs_blkdev_put(rtdev);
return EINVAL;
}
}
/*
* Setup xfs_mount buffer target pointers
*/
error = ENOMEM;
mp->m_ddev_targp = xfs_alloc_buftarg(ddev, 0);
if (!mp->m_ddev_targp) {
xfs_blkdev_put(logdev);
xfs_blkdev_put(rtdev);
return error;
}
if (rtdev) {
mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev, 1);
if (!mp->m_rtdev_targp) {
xfs_blkdev_put(logdev);
xfs_blkdev_put(rtdev);
goto error0;
}
}
mp->m_logdev_targp = (logdev && logdev != ddev) ?
xfs_alloc_buftarg(logdev, 1) : mp->m_ddev_targp;
if (!mp->m_logdev_targp) {
xfs_blkdev_put(logdev);
xfs_blkdev_put(rtdev);
goto error0;
}
/*
* Setup flags based on mount(2) options and then the superblock
*/
error = xfs_start_flags(args, mp);
if (error)
goto error1;
error = xfs_readsb(mp, flags);
if (error)
goto error1;
error = xfs_finish_flags(args, mp);
if (error)
goto error2;
/*
* Setup xfs_mount buffer target pointers based on superblock
*/
error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize,
mp->m_sb.sb_sectsize);
if (!error && logdev && logdev != ddev) {
unsigned int log_sector_size = BBSIZE;
if (xfs_sb_version_hassector(&mp->m_sb))
log_sector_size = mp->m_sb.sb_logsectsize;
error = xfs_setsize_buftarg(mp->m_logdev_targp,
mp->m_sb.sb_blocksize,
log_sector_size);
}
if (!error && rtdev)
error = xfs_setsize_buftarg(mp->m_rtdev_targp,
mp->m_sb.sb_blocksize,
mp->m_sb.sb_sectsize);
if (error)
goto error2;
if (mp->m_flags & XFS_MOUNT_BARRIER)
xfs_mountfs_check_barriers(mp);
if ((error = xfs_filestream_mount(mp)))
goto error2;
error = xfs_mountfs(mp, flags);
if (error)
goto error2;
XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, args->mtpt, args->fsname);
return 0;
error2:
if (mp->m_sb_bp)
xfs_freesb(mp);
error1:
xfs_binval(mp->m_ddev_targp);
if (logdev && logdev != ddev)
xfs_binval(mp->m_logdev_targp);
if (rtdev)
xfs_binval(mp->m_rtdev_targp);
error0:
xfs_unmountfs_close(mp, credp);
xfs_qmops_put(mp);
xfs_dmops_put(mp);
return error;
}
int
xfs_unmount(
xfs_mount_t *mp,
int flags,
cred_t *credp)
{
xfs_inode_t *rip;
bhv_vnode_t *rvp;
int unmount_event_wanted = 0;
int unmount_event_flags = 0;
int xfs_unmountfs_needed = 0;
int error;
rip = mp->m_rootip;
rvp = XFS_ITOV(rip);
#ifdef HAVE_DMAPI
if (mp->m_flags & XFS_MOUNT_DMAPI) {
error = XFS_SEND_PREUNMOUNT(mp,
rip, DM_RIGHT_NULL, rip, DM_RIGHT_NULL,
NULL, NULL, 0, 0,
(mp->m_dmevmask & (1<<DM_EVENT_PREUNMOUNT))?
0:DM_FLAGS_UNWANTED);
if (error)
return XFS_ERROR(error);
unmount_event_wanted = 1;
unmount_event_flags = (mp->m_dmevmask & (1<<DM_EVENT_UNMOUNT))?
0 : DM_FLAGS_UNWANTED;
}
#endif
/*
* Blow away any referenced inode in the filestreams cache.
* This can and will cause log traffic as inodes go inactive
* here.
*/
xfs_filestream_unmount(mp);
XFS_bflush(mp->m_ddev_targp);
error = xfs_unmount_flush(mp, 0);
if (error)
goto out;
ASSERT(vn_count(rvp) == 1);
/*
* Drop the reference count
*/
IRELE(rip);
/*
* If we're forcing a shutdown, typically because of a media error,
* we want to make sure we invalidate dirty pages that belong to
* referenced vnodes as well.
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
error = xfs_sync(mp, SYNC_WAIT | SYNC_CLOSE);
ASSERT(error != EFSCORRUPTED);
}
xfs_unmountfs_needed = 1;
out:
/* Send DMAPI event, if required.
* Then do xfs_unmountfs() if needed.
* Then return error (or zero).
*/
if (unmount_event_wanted) {
/* Note: mp structure must still exist for
* XFS_SEND_UNMOUNT() call.
*/
XFS_SEND_UNMOUNT(mp, error == 0 ? rip : NULL,
DM_RIGHT_NULL, 0, error, unmount_event_flags);
}
if (xfs_unmountfs_needed) {
/*
* Call common unmount function to flush to disk
* and free the super block buffer & mount structures.
*/
xfs_unmountfs(mp, credp);
xfs_qmops_put(mp);
xfs_dmops_put(mp);
kmem_free(mp, sizeof(xfs_mount_t));
}
return XFS_ERROR(error);
}
STATIC void STATIC void
xfs_quiesce_fs( xfs_quiesce_fs(
xfs_mount_t *mp) xfs_mount_t *mp)
@ -694,30 +114,6 @@ xfs_attr_quiesce(
xfs_unmountfs_writesb(mp); xfs_unmountfs_writesb(mp);
} }
int
xfs_mntupdate(
struct xfs_mount *mp,
int *flags,
struct xfs_mount_args *args)
{
if (!(*flags & MS_RDONLY)) { /* rw/ro -> rw */
if (mp->m_flags & XFS_MOUNT_RDONLY)
mp->m_flags &= ~XFS_MOUNT_RDONLY;
if (args->flags & XFSMNT_BARRIER) {
mp->m_flags |= XFS_MOUNT_BARRIER;
xfs_mountfs_check_barriers(mp);
} else {
mp->m_flags &= ~XFS_MOUNT_BARRIER;
}
} else if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { /* rw -> ro */
xfs_filestream_flush(mp);
xfs_sync(mp, SYNC_DATA_QUIESCE);
xfs_attr_quiesce(mp);
mp->m_flags |= XFS_MOUNT_RDONLY;
}
return 0;
}
/* /*
* xfs_unmount_flush implements a set of flush operation on special * xfs_unmount_flush implements a set of flush operation on special
* inodes, which are needed as a separate set of operations so that * inodes, which are needed as a separate set of operations so that
@ -1048,7 +444,7 @@ xfs_sync_inodes(
if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) { if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) {
XFS_MOUNT_IUNLOCK(mp); XFS_MOUNT_IUNLOCK(mp);
kmem_free(ipointer, sizeof(xfs_iptr_t)); kmem_free(ipointer);
return 0; return 0;
} }
@ -1194,7 +590,7 @@ xfs_sync_inodes(
} }
XFS_MOUNT_IUNLOCK(mp); XFS_MOUNT_IUNLOCK(mp);
ASSERT(ipointer_in == B_FALSE); ASSERT(ipointer_in == B_FALSE);
kmem_free(ipointer, sizeof(xfs_iptr_t)); kmem_free(ipointer);
return XFS_ERROR(error); return XFS_ERROR(error);
} }
@ -1224,7 +620,7 @@ xfs_sync_inodes(
ASSERT(ipointer_in == B_FALSE); ASSERT(ipointer_in == B_FALSE);
kmem_free(ipointer, sizeof(xfs_iptr_t)); kmem_free(ipointer);
return XFS_ERROR(last_error); return XFS_ERROR(last_error);
} }

View File

@ -8,11 +8,6 @@ struct kstatfs;
struct xfs_mount; struct xfs_mount;
struct xfs_mount_args; struct xfs_mount_args;
int xfs_mount(struct xfs_mount *mp, struct xfs_mount_args *args,
struct cred *credp);
int xfs_unmount(struct xfs_mount *mp, int flags, struct cred *credp);
int xfs_mntupdate(struct xfs_mount *mp, int *flags,
struct xfs_mount_args *args);
int xfs_sync(struct xfs_mount *mp, int flags); int xfs_sync(struct xfs_mount *mp, int flags);
void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname,
int lnnum); int lnnum);

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,9 @@
#define _XFS_VNODEOPS_H 1 #define _XFS_VNODEOPS_H 1
struct attrlist_cursor_kern; struct attrlist_cursor_kern;
struct bhv_vattr;
struct cred; struct cred;
struct file; struct file;
struct iattr;
struct inode; struct inode;
struct iovec; struct iovec;
struct kiocb; struct kiocb;
@ -15,14 +15,18 @@ struct xfs_iomap;
int xfs_open(struct xfs_inode *ip); int xfs_open(struct xfs_inode *ip);
int xfs_setattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags, int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags,
struct cred *credp); struct cred *credp);
#define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */
#define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */
#define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */
int xfs_readlink(struct xfs_inode *ip, char *link); int xfs_readlink(struct xfs_inode *ip, char *link);
int xfs_fsync(struct xfs_inode *ip); int xfs_fsync(struct xfs_inode *ip);
int xfs_release(struct xfs_inode *ip); int xfs_release(struct xfs_inode *ip);
int xfs_inactive(struct xfs_inode *ip); int xfs_inactive(struct xfs_inode *ip);
int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode **ipp); struct xfs_inode **ipp, struct xfs_name *ci_name);
int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode, int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode,
xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp); xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp);
int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
@ -31,8 +35,6 @@ int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
struct xfs_name *target_name); struct xfs_name *target_name);
int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name, int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name,
mode_t mode, struct xfs_inode **ipp, struct cred *credp); mode_t mode, struct xfs_inode **ipp, struct cred *credp);
int xfs_rmdir(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode *cdp);
int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize, int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize,
xfs_off_t *offset, filldir_t filldir); xfs_off_t *offset, filldir_t filldir);
int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,

View File

@ -230,6 +230,7 @@ extern void d_delete(struct dentry *);
extern struct dentry * d_alloc(struct dentry *, const struct qstr *); extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
extern struct dentry * d_alloc_anon(struct inode *); extern struct dentry * d_alloc_anon(struct inode *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *); extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
extern struct dentry * d_add_ci(struct inode *, struct dentry *, struct qstr *);
extern void shrink_dcache_sb(struct super_block *); extern void shrink_dcache_sb(struct super_block *);
extern void shrink_dcache_parent(struct dentry *); extern void shrink_dcache_parent(struct dentry *);
extern void shrink_dcache_for_umount(struct super_block *); extern void shrink_dcache_for_umount(struct super_block *);