forked from Minki/linux
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:
commit
b8a327be3f
102
fs/dcache.c
102
fs/dcache.c
@ -1220,6 +1220,107 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
|
||||
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
|
||||
@ -2254,6 +2355,7 @@ EXPORT_SYMBOL(d_path);
|
||||
EXPORT_SYMBOL(d_prune_aliases);
|
||||
EXPORT_SYMBOL(d_rehash);
|
||||
EXPORT_SYMBOL(d_splice_alias);
|
||||
EXPORT_SYMBOL(d_add_ci);
|
||||
EXPORT_SYMBOL(d_validate);
|
||||
EXPORT_SYMBOL(dget_locked);
|
||||
EXPORT_SYMBOL(dput);
|
||||
|
@ -106,7 +106,8 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \
|
||||
xfs_iops.o \
|
||||
xfs_lrw.o \
|
||||
xfs_super.o \
|
||||
xfs_vnode.o)
|
||||
xfs_vnode.o \
|
||||
xfs_xattr.o)
|
||||
|
||||
# Objects in support/
|
||||
xfs-y += $(addprefix support/, \
|
||||
|
@ -90,7 +90,7 @@ kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize,
|
||||
}
|
||||
|
||||
void
|
||||
kmem_free(void *ptr, size_t size)
|
||||
kmem_free(const void *ptr)
|
||||
{
|
||||
if (!is_vmalloc_addr(ptr)) {
|
||||
kfree(ptr);
|
||||
@ -100,7 +100,7 @@ kmem_free(void *ptr, size_t size)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
void *new;
|
||||
@ -110,7 +110,7 @@ kmem_realloc(void *ptr, size_t newsize, size_t oldsize,
|
||||
if (new)
|
||||
memcpy(new, ptr,
|
||||
((oldsize < newsize) ? oldsize : newsize));
|
||||
kmem_free(ptr, oldsize);
|
||||
kmem_free(ptr);
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ kmem_flags_convert(unsigned int __nocast flags)
|
||||
extern void *kmem_alloc(size_t, unsigned int __nocast);
|
||||
extern void *kmem_zalloc(size_t, unsigned int __nocast);
|
||||
extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast);
|
||||
extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast);
|
||||
extern void kmem_free(void *, size_t);
|
||||
extern void *kmem_realloc(const void *, size_t, size_t, unsigned int __nocast);
|
||||
extern void kmem_free(const void *);
|
||||
|
||||
/*
|
||||
* Zone interfaces
|
||||
|
@ -409,7 +409,6 @@ xfs_start_buffer_writeback(
|
||||
STATIC void
|
||||
xfs_start_page_writeback(
|
||||
struct page *page,
|
||||
struct writeback_control *wbc,
|
||||
int clear_dirty,
|
||||
int buffers)
|
||||
{
|
||||
@ -858,7 +857,7 @@ xfs_convert_page(
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
xfs_start_page_writeback(page, wbc, !page_dirty, count);
|
||||
xfs_start_page_writeback(page, !page_dirty, count);
|
||||
}
|
||||
|
||||
return done;
|
||||
@ -1130,7 +1129,7 @@ xfs_page_state_convert(
|
||||
SetPageUptodate(page);
|
||||
|
||||
if (startio)
|
||||
xfs_start_page_writeback(page, wbc, 1, count);
|
||||
xfs_start_page_writeback(page, 1, count);
|
||||
|
||||
if (ioend && iomap_valid) {
|
||||
offset = (iomap.iomap_offset + iomap.iomap_bsize - 1) >>
|
||||
|
@ -310,8 +310,7 @@ _xfs_buf_free_pages(
|
||||
xfs_buf_t *bp)
|
||||
{
|
||||
if (bp->b_pages != bp->b_page_array) {
|
||||
kmem_free(bp->b_pages,
|
||||
bp->b_page_count * sizeof(struct page *));
|
||||
kmem_free(bp->b_pages);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1398,7 +1397,7 @@ STATIC void
|
||||
xfs_free_bufhash(
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1428,13 +1427,10 @@ xfs_unregister_buftarg(
|
||||
|
||||
void
|
||||
xfs_free_buftarg(
|
||||
xfs_buftarg_t *btp,
|
||||
int external)
|
||||
xfs_buftarg_t *btp)
|
||||
{
|
||||
xfs_flush_buftarg(btp, 1);
|
||||
xfs_blkdev_issue_flush(btp);
|
||||
if (external)
|
||||
xfs_blkdev_put(btp->bt_bdev);
|
||||
xfs_free_bufhash(btp);
|
||||
iput(btp->bt_mapping->host);
|
||||
|
||||
@ -1444,7 +1440,7 @@ xfs_free_buftarg(
|
||||
xfs_unregister_buftarg(btp);
|
||||
kthread_stop(btp->bt_task);
|
||||
|
||||
kmem_free(btp, sizeof(*btp));
|
||||
kmem_free(btp);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
@ -1575,7 +1571,7 @@ xfs_alloc_buftarg(
|
||||
return btp;
|
||||
|
||||
error:
|
||||
kmem_free(btp, sizeof(*btp));
|
||||
kmem_free(btp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -429,7 +429,7 @@ static inline void xfs_bdwrite(void *mp, xfs_buf_t *bp)
|
||||
* Handling of buftargs.
|
||||
*/
|
||||
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 int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
|
||||
extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
|
||||
|
@ -215,7 +215,7 @@ xfs_fs_get_parent(
|
||||
struct xfs_inode *cip;
|
||||
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))
|
||||
return ERR_PTR(-error);
|
||||
|
||||
|
@ -48,6 +48,8 @@
|
||||
#include "xfs_dfrag.h"
|
||||
#include "xfs_fsops.h"
|
||||
#include "xfs_vnodeops.h"
|
||||
#include "xfs_quota.h"
|
||||
#include "xfs_inode_item.h"
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/dcache.h>
|
||||
@ -468,6 +470,12 @@ xfs_attrlist_by_handle(
|
||||
if (al_hreq.buflen > XATTR_LIST_MAX)
|
||||
return -XFS_ERROR(EINVAL);
|
||||
|
||||
/*
|
||||
* Reject flags, only allow namespaces.
|
||||
*/
|
||||
if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE))
|
||||
return -XFS_ERROR(EINVAL);
|
||||
|
||||
error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode);
|
||||
if (error)
|
||||
goto out;
|
||||
@ -587,7 +595,7 @@ xfs_attrmulti_by_handle(
|
||||
goto out;
|
||||
|
||||
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)
|
||||
goto out_vn_rele;
|
||||
|
||||
@ -680,9 +688,9 @@ xfs_ioc_space(
|
||||
return -XFS_ERROR(EFAULT);
|
||||
|
||||
if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
|
||||
attr_flags |= ATTR_NONBLOCK;
|
||||
attr_flags |= XFS_ATTR_NONBLOCK;
|
||||
if (ioflags & IO_INVIS)
|
||||
attr_flags |= ATTR_DMI;
|
||||
attr_flags |= XFS_ATTR_DMI;
|
||||
|
||||
error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos,
|
||||
NULL, attr_flags);
|
||||
@ -873,6 +881,322 @@ xfs_ioc_fsgetxattr(
|
||||
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
|
||||
xfs_ioc_fssetxattr(
|
||||
xfs_inode_t *ip,
|
||||
@ -880,31 +1204,16 @@ xfs_ioc_fssetxattr(
|
||||
void __user *arg)
|
||||
{
|
||||
struct fsxattr fa;
|
||||
struct bhv_vattr *vattr;
|
||||
int error;
|
||||
int attr_flags;
|
||||
unsigned int mask;
|
||||
|
||||
if (copy_from_user(&fa, arg, sizeof(fa)))
|
||||
return -EFAULT;
|
||||
|
||||
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL);
|
||||
if (unlikely(!vattr))
|
||||
return -ENOMEM;
|
||||
|
||||
attr_flags = 0;
|
||||
mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID;
|
||||
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;
|
||||
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;
|
||||
return -xfs_ioctl_setattr(ip, &fa, mask);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
@ -926,10 +1235,9 @@ xfs_ioc_setxflags(
|
||||
struct file *filp,
|
||||
void __user *arg)
|
||||
{
|
||||
struct bhv_vattr *vattr;
|
||||
struct fsxattr fa;
|
||||
unsigned int flags;
|
||||
int attr_flags;
|
||||
int error;
|
||||
unsigned int mask;
|
||||
|
||||
if (copy_from_user(&flags, arg, sizeof(flags)))
|
||||
return -EFAULT;
|
||||
@ -939,22 +1247,12 @@ xfs_ioc_setxflags(
|
||||
FS_SYNC_FL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL);
|
||||
if (unlikely(!vattr))
|
||||
return -ENOMEM;
|
||||
|
||||
attr_flags = 0;
|
||||
mask = FSX_XFLAGS;
|
||||
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;
|
||||
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;
|
||||
return -xfs_ioctl_setattr(ip, &fa, mask);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
|
@ -181,23 +181,6 @@ xfs_ichgtime_fast(
|
||||
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
|
||||
* here (as we do for default ACLs) is a mechanism by which creation of
|
||||
@ -245,8 +228,7 @@ STATIC void
|
||||
xfs_cleanup_inode(
|
||||
struct inode *dir,
|
||||
struct inode *inode,
|
||||
struct dentry *dentry,
|
||||
int mode)
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct xfs_name teardown;
|
||||
|
||||
@ -257,10 +239,7 @@ xfs_cleanup_inode(
|
||||
*/
|
||||
xfs_dentry_to_name(&teardown, dentry);
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
xfs_rmdir(XFS_I(dir), &teardown, XFS_I(inode));
|
||||
else
|
||||
xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
|
||||
xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
|
||||
iput(inode);
|
||||
}
|
||||
|
||||
@ -275,7 +254,7 @@ xfs_vn_mknod(
|
||||
struct xfs_inode *ip = NULL;
|
||||
xfs_acl_t *default_acl = NULL;
|
||||
struct xfs_name name;
|
||||
attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS;
|
||||
int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS;
|
||||
int error;
|
||||
|
||||
/*
|
||||
@ -335,14 +314,11 @@ xfs_vn_mknod(
|
||||
}
|
||||
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
xfs_validate_fields(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
xfs_validate_fields(dir);
|
||||
return -error;
|
||||
|
||||
out_cleanup_inode:
|
||||
xfs_cleanup_inode(dir, inode, dentry, mode);
|
||||
xfs_cleanup_inode(dir, inode, dentry);
|
||||
out_free_acl:
|
||||
if (default_acl)
|
||||
_ACL_FREE(default_acl);
|
||||
@ -382,7 +358,7 @@ xfs_vn_lookup(
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
|
||||
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 != ENOENT))
|
||||
return ERR_PTR(-error);
|
||||
@ -393,6 +369,46 @@ xfs_vn_lookup(
|
||||
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
|
||||
xfs_vn_link(
|
||||
struct dentry *old_dentry,
|
||||
@ -414,7 +430,6 @@ xfs_vn_link(
|
||||
}
|
||||
|
||||
xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED);
|
||||
xfs_validate_fields(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
}
|
||||
@ -424,19 +439,23 @@ xfs_vn_unlink(
|
||||
struct inode *dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct xfs_name name;
|
||||
int error;
|
||||
|
||||
inode = dentry->d_inode;
|
||||
xfs_dentry_to_name(&name, dentry);
|
||||
|
||||
error = xfs_remove(XFS_I(dir), &name, XFS_I(inode));
|
||||
if (likely(!error)) {
|
||||
xfs_validate_fields(dir); /* size needs update */
|
||||
xfs_validate_fields(inode);
|
||||
}
|
||||
return -error;
|
||||
error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode));
|
||||
if (error)
|
||||
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
|
||||
@ -466,35 +485,14 @@ xfs_vn_symlink(
|
||||
goto out_cleanup_inode;
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
xfs_validate_fields(dir);
|
||||
xfs_validate_fields(inode);
|
||||
return 0;
|
||||
|
||||
out_cleanup_inode:
|
||||
xfs_cleanup_inode(dir, inode, dentry, 0);
|
||||
xfs_cleanup_inode(dir, inode, dentry);
|
||||
out:
|
||||
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
|
||||
xfs_vn_rename(
|
||||
struct inode *odir,
|
||||
@ -505,22 +503,13 @@ xfs_vn_rename(
|
||||
struct inode *new_inode = ndentry->d_inode;
|
||||
struct xfs_name oname;
|
||||
struct xfs_name nname;
|
||||
int error;
|
||||
|
||||
xfs_dentry_to_name(&oname, odentry);
|
||||
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(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
|
||||
xfs_vn_setattr(
|
||||
struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
struct iattr *iattr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
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;
|
||||
return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -727,109 +668,6 @@ xfs_vn_truncate(
|
||||
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
|
||||
xfs_vn_fallocate(
|
||||
struct inode *inode,
|
||||
@ -853,18 +691,18 @@ xfs_vn_fallocate(
|
||||
|
||||
xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
||||
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) &&
|
||||
offset + len > i_size_read(inode))
|
||||
new_size = offset + len;
|
||||
|
||||
/* Change file size if needed */
|
||||
if (new_size) {
|
||||
bhv_vattr_t va;
|
||||
struct iattr iattr;
|
||||
|
||||
va.va_mask = XFS_AT_SIZE;
|
||||
va.va_size = new_size;
|
||||
error = xfs_setattr(ip, &va, ATTR_NOLOCK, NULL);
|
||||
iattr.ia_valid = ATTR_SIZE;
|
||||
iattr.ia_size = new_size;
|
||||
error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK, NULL);
|
||||
}
|
||||
|
||||
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
||||
@ -877,10 +715,10 @@ const struct inode_operations xfs_inode_operations = {
|
||||
.truncate = xfs_vn_truncate,
|
||||
.getattr = xfs_vn_getattr,
|
||||
.setattr = xfs_vn_setattr,
|
||||
.setxattr = xfs_vn_setxattr,
|
||||
.getxattr = xfs_vn_getxattr,
|
||||
.setxattr = generic_setxattr,
|
||||
.getxattr = generic_getxattr,
|
||||
.removexattr = generic_removexattr,
|
||||
.listxattr = xfs_vn_listxattr,
|
||||
.removexattr = xfs_vn_removexattr,
|
||||
.fallocate = xfs_vn_fallocate,
|
||||
};
|
||||
|
||||
@ -891,16 +729,47 @@ const struct inode_operations xfs_dir_inode_operations = {
|
||||
.unlink = xfs_vn_unlink,
|
||||
.symlink = xfs_vn_symlink,
|
||||
.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,
|
||||
.rename = xfs_vn_rename,
|
||||
.permission = xfs_vn_permission,
|
||||
.getattr = xfs_vn_getattr,
|
||||
.setattr = xfs_vn_setattr,
|
||||
.setxattr = xfs_vn_setxattr,
|
||||
.getxattr = xfs_vn_getxattr,
|
||||
.setxattr = generic_setxattr,
|
||||
.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,
|
||||
.removexattr = xfs_vn_removexattr,
|
||||
};
|
||||
|
||||
const struct inode_operations xfs_symlink_inode_operations = {
|
||||
@ -910,8 +779,8 @@ const struct inode_operations xfs_symlink_inode_operations = {
|
||||
.permission = xfs_vn_permission,
|
||||
.getattr = xfs_vn_getattr,
|
||||
.setattr = xfs_vn_setattr,
|
||||
.setxattr = xfs_vn_setxattr,
|
||||
.getxattr = xfs_vn_getxattr,
|
||||
.setxattr = generic_setxattr,
|
||||
.getxattr = generic_getxattr,
|
||||
.removexattr = generic_removexattr,
|
||||
.listxattr = xfs_vn_listxattr,
|
||||
.removexattr = xfs_vn_removexattr,
|
||||
};
|
||||
|
@ -20,12 +20,14 @@
|
||||
|
||||
extern const struct inode_operations xfs_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 file_operations xfs_file_operations;
|
||||
extern const struct file_operations xfs_dir_file_operations;
|
||||
extern const struct file_operations xfs_invis_file_operations;
|
||||
|
||||
extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
|
||||
|
||||
struct xfs_inode;
|
||||
extern void xfs_ichgtime(struct xfs_inode *, int);
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/div64.h>
|
||||
@ -299,4 +300,11 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y)
|
||||
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__ */
|
||||
|
@ -98,12 +98,21 @@ xfs_read_xfsstats(
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
xfs_init_procfs(void)
|
||||
{
|
||||
if (!proc_mkdir("fs/xfs", NULL))
|
||||
return;
|
||||
create_proc_read_entry("fs/xfs/stat", 0, NULL, xfs_read_xfsstats, NULL);
|
||||
goto out;
|
||||
|
||||
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
|
||||
|
@ -134,7 +134,7 @@ DECLARE_PER_CPU(struct xfsstats, xfsstats);
|
||||
#define XFS_STATS_DEC(v) (per_cpu(xfsstats, current_cpu()).v--)
|
||||
#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);
|
||||
|
||||
|
||||
@ -144,8 +144,14 @@ extern void xfs_cleanup_procfs(void);
|
||||
# define XFS_STATS_DEC(count)
|
||||
# define XFS_STATS_ADD(count, inc)
|
||||
|
||||
static inline void xfs_init_procfs(void) { };
|
||||
static inline void xfs_cleanup_procfs(void) { };
|
||||
static inline int xfs_init_procfs(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void xfs_cleanup_procfs(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_PROC_FS */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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_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 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))
|
||||
|
||||
|
@ -259,15 +259,17 @@ static ctl_table xfs_root_table[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
void
|
||||
int
|
||||
xfs_sysctl_register(void)
|
||||
{
|
||||
xfs_table_header = register_sysctl_table(xfs_root_table);
|
||||
if (!xfs_table_header)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
xfs_sysctl_unregister(void)
|
||||
{
|
||||
if (xfs_table_header)
|
||||
unregister_sysctl_table(xfs_table_header);
|
||||
unregister_sysctl_table(xfs_table_header);
|
||||
}
|
||||
|
@ -93,10 +93,10 @@ enum {
|
||||
extern xfs_param_t xfs_params;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
extern void xfs_sysctl_register(void);
|
||||
extern int xfs_sysctl_register(void);
|
||||
extern void xfs_sysctl_unregister(void);
|
||||
#else
|
||||
# define xfs_sysctl_register() do { } while (0)
|
||||
# define xfs_sysctl_register() (0)
|
||||
# define xfs_sysctl_unregister() do { } while (0)
|
||||
#endif /* CONFIG_SYSCTL */
|
||||
|
||||
|
@ -82,56 +82,6 @@ vn_ioerror(
|
||||
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.
|
||||
|
@ -19,7 +19,6 @@
|
||||
#define __XFS_VNODE_H__
|
||||
|
||||
struct file;
|
||||
struct bhv_vattr;
|
||||
struct xfs_iomap;
|
||||
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
|
||||
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 int vn_revalidate(bhv_vnode_t *);
|
||||
|
||||
/*
|
||||
* 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, \
|
||||
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.
|
||||
|
330
fs/xfs/linux-2.6/xfs_xattr.c
Normal file
330
fs/xfs/linux-2.6/xfs_xattr.c
Normal 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;
|
||||
}
|
@ -1435,8 +1435,7 @@ xfs_dqlock2(
|
||||
/* ARGSUSED */
|
||||
int
|
||||
xfs_qm_dqpurge(
|
||||
xfs_dquot_t *dqp,
|
||||
uint flags)
|
||||
xfs_dquot_t *dqp)
|
||||
{
|
||||
xfs_dqhash_t *thishash;
|
||||
xfs_mount_t *mp = dqp->q_mount;
|
||||
|
@ -164,7 +164,7 @@ extern void xfs_qm_dqprint(xfs_dquot_t *);
|
||||
|
||||
extern void xfs_qm_dqdestroy(xfs_dquot_t *);
|
||||
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 int xfs_qm_dqlock_nowait(xfs_dquot_t *);
|
||||
extern int xfs_qm_dqflock_nowait(xfs_dquot_t *);
|
||||
|
@ -576,8 +576,8 @@ xfs_qm_qoffend_logitem_committed(
|
||||
* xfs_trans_delete_ail() drops the AIL lock.
|
||||
*/
|
||||
xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs);
|
||||
kmem_free(qfs, sizeof(xfs_qoff_logitem_t));
|
||||
kmem_free(qfe, sizeof(xfs_qoff_logitem_t));
|
||||
kmem_free(qfs);
|
||||
kmem_free(qfe);
|
||||
return (xfs_lsn_t)-1;
|
||||
}
|
||||
|
||||
|
@ -192,8 +192,8 @@ xfs_qm_destroy(
|
||||
xfs_qm_list_destroy(&(xqm->qm_usr_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_grp_dqhtable, hsize * sizeof(xfs_dqhash_t));
|
||||
kmem_free(xqm->qm_usr_dqhtable);
|
||||
kmem_free(xqm->qm_grp_dqhtable);
|
||||
xqm->qm_usr_dqhtable = NULL;
|
||||
xqm->qm_grp_dqhtable = NULL;
|
||||
xqm->qm_dqhashmask = 0;
|
||||
@ -201,7 +201,7 @@ xfs_qm_destroy(
|
||||
#ifdef DEBUG
|
||||
mutex_destroy(&qcheck_lock);
|
||||
#endif
|
||||
kmem_free(xqm, sizeof(xfs_qm_t));
|
||||
kmem_free(xqm);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -445,11 +445,11 @@ xfs_qm_unmount_quotas(
|
||||
}
|
||||
}
|
||||
if (uqp) {
|
||||
XFS_PURGE_INODE(uqp);
|
||||
IRELE(uqp);
|
||||
mp->m_quotainfo->qi_uquotaip = NULL;
|
||||
}
|
||||
if (gqp) {
|
||||
XFS_PURGE_INODE(gqp);
|
||||
IRELE(gqp);
|
||||
mp->m_quotainfo->qi_gquotaip = NULL;
|
||||
}
|
||||
out:
|
||||
@ -631,7 +631,7 @@ xfs_qm_dqpurge_int(
|
||||
* freelist in INACTIVE state.
|
||||
*/
|
||||
nextdqp = dqp->MPL_NEXT;
|
||||
nmisses += xfs_qm_dqpurge(dqp, flags);
|
||||
nmisses += xfs_qm_dqpurge(dqp);
|
||||
dqp = nextdqp;
|
||||
}
|
||||
xfs_qm_mplist_unlock(mp);
|
||||
@ -1134,7 +1134,7 @@ xfs_qm_init_quotainfo(
|
||||
* and change the superblock accordingly.
|
||||
*/
|
||||
if ((error = xfs_qm_init_quotainos(mp))) {
|
||||
kmem_free(qinf, sizeof(xfs_quotainfo_t));
|
||||
kmem_free(qinf);
|
||||
mp->m_quotainfo = NULL;
|
||||
return error;
|
||||
}
|
||||
@ -1240,15 +1240,15 @@ xfs_qm_destroy_quotainfo(
|
||||
xfs_qm_list_destroy(&qi->qi_dqlist);
|
||||
|
||||
if (qi->qi_uquotaip) {
|
||||
XFS_PURGE_INODE(qi->qi_uquotaip);
|
||||
IRELE(qi->qi_uquotaip);
|
||||
qi->qi_uquotaip = NULL; /* paranoia */
|
||||
}
|
||||
if (qi->qi_gquotaip) {
|
||||
XFS_PURGE_INODE(qi->qi_gquotaip);
|
||||
IRELE(qi->qi_gquotaip);
|
||||
qi->qi_gquotaip = NULL;
|
||||
}
|
||||
mutex_destroy(&qi->qi_quotaofflock);
|
||||
kmem_free(qi, sizeof(xfs_quotainfo_t));
|
||||
kmem_free(qi);
|
||||
mp->m_quotainfo = NULL;
|
||||
}
|
||||
|
||||
@ -1394,7 +1394,7 @@ xfs_qm_qino_alloc(
|
||||
* locked exclusively and joined to the transaction already.
|
||||
*/
|
||||
ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL));
|
||||
VN_HOLD(XFS_ITOV((*ip)));
|
||||
IHOLD(*ip);
|
||||
|
||||
/*
|
||||
* Make the changes in the superblock, and log those too.
|
||||
@ -1623,7 +1623,7 @@ xfs_qm_dqiterate(
|
||||
break;
|
||||
} while (nmaps > 0);
|
||||
|
||||
kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map));
|
||||
kmem_free(map);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -362,11 +362,11 @@ xfs_qm_scall_quotaoff(
|
||||
* if we don't need them anymore.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
out_error:
|
||||
@ -1449,14 +1449,14 @@ xfs_qm_internalqcheck(
|
||||
for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
|
||||
xfs_dqtest_cmp(d);
|
||||
e = (xfs_dqtest_t *) d->HL_NEXT;
|
||||
kmem_free(d, sizeof(xfs_dqtest_t));
|
||||
kmem_free(d);
|
||||
d = e;
|
||||
}
|
||||
h1 = &qmtest_gdqtab[i];
|
||||
for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) {
|
||||
xfs_dqtest_cmp(d);
|
||||
e = (xfs_dqtest_t *) d->HL_NEXT;
|
||||
kmem_free(d, sizeof(xfs_dqtest_t));
|
||||
kmem_free(d);
|
||||
d = e;
|
||||
}
|
||||
}
|
||||
@ -1467,8 +1467,8 @@ xfs_qm_internalqcheck(
|
||||
} else {
|
||||
cmn_err(CE_DEBUG, "******** quotacheck successful! ********");
|
||||
}
|
||||
kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
|
||||
kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t));
|
||||
kmem_free(qmtest_udqtab);
|
||||
kmem_free(qmtest_gdqtab);
|
||||
mutex_unlock(&qcheck_lock);
|
||||
return (qmtest_nfails);
|
||||
}
|
||||
|
@ -158,9 +158,6 @@ for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
|
||||
#define XFS_IS_SUSER_DQUOT(dqp) \
|
||||
(!((dqp)->q_core.d_id))
|
||||
|
||||
#define XFS_PURGE_INODE(ip) \
|
||||
IRELE(ip);
|
||||
|
||||
#define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
|
||||
(((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \
|
||||
(((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???")))
|
||||
|
@ -89,7 +89,7 @@ ktrace_alloc(int nentries, unsigned int __nocast sleep)
|
||||
if (sleep & KM_SLEEP)
|
||||
panic("ktrace_alloc: NULL memory on KM_SLEEP request!");
|
||||
|
||||
kmem_free(ktp, sizeof(*ktp));
|
||||
kmem_free(ktp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -126,7 +126,7 @@ ktrace_free(ktrace_t *ktp)
|
||||
} else {
|
||||
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);
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
#include <xfs.h>
|
||||
|
||||
static mutex_t uuid_monitor;
|
||||
static DEFINE_MUTEX(uuid_monitor);
|
||||
static int uuid_table_size;
|
||||
static uuid_t *uuid_table;
|
||||
|
||||
@ -132,9 +132,3 @@ uuid_table_remove(uuid_t *uuid)
|
||||
ASSERT(i < uuid_table_size);
|
||||
mutex_unlock(&uuid_monitor);
|
||||
}
|
||||
|
||||
void __init
|
||||
uuid_init(void)
|
||||
{
|
||||
mutex_init(&uuid_monitor);
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ typedef struct {
|
||||
unsigned char __u_bits[16];
|
||||
} uuid_t;
|
||||
|
||||
extern void uuid_init(void);
|
||||
extern void uuid_create_nil(uuid_t *uuid);
|
||||
extern int uuid_is_nil(uuid_t *uuid);
|
||||
extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2);
|
||||
|
@ -341,8 +341,7 @@ xfs_acl_iaccess(
|
||||
|
||||
/* If the file has no ACL return -1. */
|
||||
rval = sizeof(xfs_acl_t);
|
||||
if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval,
|
||||
ATTR_ROOT | ATTR_KERNACCESS)) {
|
||||
if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval, ATTR_ROOT)) {
|
||||
_ACL_FREE(acl);
|
||||
return -1;
|
||||
}
|
||||
@ -720,7 +719,7 @@ xfs_acl_setmode(
|
||||
xfs_acl_t *acl,
|
||||
int *basicperms)
|
||||
{
|
||||
bhv_vattr_t va;
|
||||
struct iattr iattr;
|
||||
xfs_acl_entry_t *ap;
|
||||
xfs_acl_entry_t *gap = NULL;
|
||||
int i, nomask = 1;
|
||||
@ -734,25 +733,25 @@ xfs_acl_setmode(
|
||||
* Copy the u::, g::, o::, and m:: bits from the ACL into the
|
||||
* mode. The m:: bits take precedence over the g:: bits.
|
||||
*/
|
||||
va.va_mask = XFS_AT_MODE;
|
||||
va.va_mode = xfs_vtoi(vp)->i_d.di_mode;
|
||||
va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
iattr.ia_valid = ATTR_MODE;
|
||||
iattr.ia_mode = xfs_vtoi(vp)->i_d.di_mode;
|
||||
iattr.ia_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
ap = acl->acl_entry;
|
||||
for (i = 0; i < acl->acl_cnt; ++i) {
|
||||
switch (ap->ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
va.va_mode |= ap->ae_perm << 6;
|
||||
iattr.ia_mode |= ap->ae_perm << 6;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
gap = ap;
|
||||
break;
|
||||
case ACL_MASK: /* more than just standard modes */
|
||||
nomask = 0;
|
||||
va.va_mode |= ap->ae_perm << 3;
|
||||
iattr.ia_mode |= ap->ae_perm << 3;
|
||||
*basicperms = 0;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
va.va_mode |= ap->ae_perm;
|
||||
iattr.ia_mode |= ap->ae_perm;
|
||||
break;
|
||||
default: /* more than just standard modes */
|
||||
*basicperms = 0;
|
||||
@ -763,9 +762,9 @@ xfs_acl_setmode(
|
||||
|
||||
/* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -46,6 +46,8 @@ typedef struct xfs_acl {
|
||||
#define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-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
|
||||
|
||||
@ -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_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_INHERIT(c,m,d) (xfs_acl_inherit(c,m,d))
|
||||
|
@ -16,8 +16,6 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
|
||||
#include "xfs.h"
|
||||
#include "xfs_fs.h"
|
||||
#include "xfs_types.h"
|
||||
@ -57,11 +55,6 @@
|
||||
* 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.
|
||||
*========================================================================*/
|
||||
@ -116,6 +109,17 @@ xfs_attr_name_to_xname(
|
||||
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.
|
||||
*========================================================================*/
|
||||
@ -127,10 +131,8 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name,
|
||||
xfs_da_args_t args;
|
||||
int error;
|
||||
|
||||
if ((XFS_IFORK_Q(ip) == 0) ||
|
||||
(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
||||
ip->i_d.di_anextents == 0))
|
||||
return(ENOATTR);
|
||||
if (!xfs_inode_hasattr(ip))
|
||||
return ENOATTR;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (XFS_IFORK_Q(ip) == 0 ||
|
||||
(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) {
|
||||
if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
||||
error = xfs_attr_shortform_getvalue(&args);
|
||||
} else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
|
||||
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.flist = &flist;
|
||||
args.whichfork = XFS_ATTR_FORK;
|
||||
args.addname = 1;
|
||||
args.oknoent = 1;
|
||||
args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (XFS_IFORK_Q(dp) == 0 ||
|
||||
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
||||
dp->i_d.di_anextents == 0)) {
|
||||
if (!xfs_inode_hasattr(dp)) {
|
||||
error = XFS_ERROR(ENOATTR);
|
||||
goto out;
|
||||
}
|
||||
@ -601,29 +596,33 @@ xfs_attr_remove(
|
||||
return error;
|
||||
|
||||
xfs_ilock(dp, XFS_ILOCK_SHARED);
|
||||
if (XFS_IFORK_Q(dp) == 0 ||
|
||||
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
||||
dp->i_d.di_anextents == 0)) {
|
||||
if (!xfs_inode_hasattr(dp)) {
|
||||
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
||||
return(XFS_ERROR(ENOATTR));
|
||||
return XFS_ERROR(ENOATTR);
|
||||
}
|
||||
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
||||
|
||||
return xfs_attr_remove_int(dp, &xname, flags);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
int
|
||||
xfs_attr_list_int(xfs_attr_list_context_t *context)
|
||||
{
|
||||
int error;
|
||||
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.
|
||||
*/
|
||||
if (XFS_IFORK_Q(dp) == 0 ||
|
||||
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
||||
dp->i_d.di_anextents == 0)) {
|
||||
if (!xfs_inode_hasattr(dp)) {
|
||||
error = 0;
|
||||
} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
||||
error = xfs_attr_shortform_list(context);
|
||||
@ -632,6 +631,10 @@ xfs_attr_list_int(xfs_attr_list_context_t *context)
|
||||
} else {
|
||||
error = xfs_attr_node_list(context);
|
||||
}
|
||||
|
||||
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
||||
xfs_attr_trace_l_c("syscall end", context);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -648,74 +651,50 @@ xfs_attr_list_int(xfs_attr_list_context_t *context)
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
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,
|
||||
int valuelen, char *value)
|
||||
{
|
||||
struct attrlist *alist = (struct attrlist *)context->alist;
|
||||
attrlist_ent_t *aep;
|
||||
int arraytop;
|
||||
|
||||
ASSERT(!(context->flags & ATTR_KERNOVAL));
|
||||
ASSERT(context->count >= 0);
|
||||
ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
|
||||
ASSERT(context->firstu >= sizeof(*context->alist));
|
||||
ASSERT(context->firstu >= sizeof(*alist));
|
||||
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);
|
||||
if (context->firstu < arraytop) {
|
||||
xfs_attr_trace_l_c("buffer full", context);
|
||||
context->alist->al_more = 1;
|
||||
alist->al_more = 1;
|
||||
context->seen_enough = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
|
||||
aep = (attrlist_ent_t *)&context->alist[context->firstu];
|
||||
aep->a_valuelen = valuelen;
|
||||
memcpy(aep->a_name, name, namelen);
|
||||
aep->a_name[ namelen ] = 0;
|
||||
context->alist->al_offset[ context->count++ ] = context->firstu;
|
||||
context->alist->al_count = context->count;
|
||||
aep->a_name[namelen] = 0;
|
||||
alist->al_offset[context->count++] = context->firstu;
|
||||
alist->al_count = context->count;
|
||||
xfs_attr_trace_l_c("add", context);
|
||||
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
|
||||
* also value lengths. Positive return value follows the XFS
|
||||
@ -732,10 +711,9 @@ xfs_attr_list(
|
||||
attrlist_cursor_kern_t *cursor)
|
||||
{
|
||||
xfs_attr_list_context_t context;
|
||||
struct attrlist *alist;
|
||||
int error;
|
||||
|
||||
XFS_STATS_INC(xs_attr_list);
|
||||
|
||||
/*
|
||||
* Validate the cursor.
|
||||
*/
|
||||
@ -756,52 +734,23 @@ xfs_attr_list(
|
||||
/*
|
||||
* Initialize the output buffer.
|
||||
*/
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.dp = dp;
|
||||
context.cursor = cursor;
|
||||
context.count = 0;
|
||||
context.dupcnt = 0;
|
||||
context.resynch = 1;
|
||||
context.flags = flags;
|
||||
context.seen_enough = 0;
|
||||
context.alist = (attrlist_t *)buffer;
|
||||
context.put_value = 0;
|
||||
context.alist = buffer;
|
||||
context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
|
||||
context.firstu = context.bufsize;
|
||||
context.put_listent = xfs_attr_put_listent;
|
||||
|
||||
if (flags & ATTR_KERNAMELS) {
|
||||
context.bufsize = bufsize;
|
||||
context.firstu = context.bufsize;
|
||||
if (flags & ATTR_KERNOVAL)
|
||||
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);
|
||||
alist = (struct attrlist *)context.alist;
|
||||
alist->al_count = 0;
|
||||
alist->al_more = 0;
|
||||
alist->al_offset[0] = context.bufsize;
|
||||
|
||||
error = xfs_attr_list_int(&context);
|
||||
|
||||
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);
|
||||
|
||||
ASSERT(error >= 0);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -816,12 +765,10 @@ xfs_attr_inactive(xfs_inode_t *dp)
|
||||
ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
|
||||
|
||||
xfs_ilock(dp, XFS_ILOCK_SHARED);
|
||||
if ((XFS_IFORK_Q(dp) == 0) ||
|
||||
(dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
|
||||
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
||||
dp->i_d.di_anextents == 0)) {
|
||||
if (!xfs_inode_hasattr(dp) ||
|
||||
dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
||||
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
if ((XFS_IFORK_Q(dp) == 0) ||
|
||||
(dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
|
||||
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
||||
dp->i_d.di_anextents == 0)) {
|
||||
if (!xfs_inode_hasattr(dp) ||
|
||||
dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
||||
error = 0;
|
||||
goto out;
|
||||
}
|
||||
@ -974,7 +919,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
|
||||
xfs_da_brelse(args->trans, bp);
|
||||
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->index2 = args->index;
|
||||
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
|
||||
* 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
|
||||
* "old" attr and clear the incomplete flag on the "new" attr.
|
||||
@ -1307,7 +1252,7 @@ restart:
|
||||
} else if (retval == EEXIST) {
|
||||
if (args->flags & ATTR_CREATE)
|
||||
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->index2 = args->index;
|
||||
args->rmtblkno2 = args->rmtblkno;
|
||||
@ -1425,7 +1370,7 @@ restart:
|
||||
* so that one disappears and one appears atomically. Then we
|
||||
* 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
|
||||
* "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
|
||||
xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context)
|
||||
{
|
||||
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where,
|
||||
(__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,
|
||||
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, context,
|
||||
(__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,
|
||||
struct xfs_da_intnode *node)
|
||||
{
|
||||
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where,
|
||||
(__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,
|
||||
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, context,
|
||||
(__psunsigned_t)be16_to_cpu(node->hdr.count),
|
||||
(__psunsigned_t)be32_to_cpu(node->btree[0].hashval),
|
||||
(__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,
|
||||
struct xfs_da_node_entry *btree)
|
||||
{
|
||||
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where,
|
||||
(__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,
|
||||
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, context,
|
||||
(__psunsigned_t)be32_to_cpu(btree->hashval),
|
||||
(__psunsigned_t)be32_to_cpu(btree->before),
|
||||
(__psunsigned_t)NULL);
|
||||
@ -2388,23 +2285,7 @@ void
|
||||
xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
|
||||
struct xfs_attr_leafblock *leaf)
|
||||
{
|
||||
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where,
|
||||
(__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,
|
||||
xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, context,
|
||||
(__psunsigned_t)be16_to_cpu(leaf->hdr.count),
|
||||
(__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval),
|
||||
(__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
|
||||
xfs_attr_trace_enter(int type, char *where,
|
||||
__psunsigned_t a2, __psunsigned_t a3,
|
||||
__psunsigned_t a4, __psunsigned_t a5,
|
||||
__psunsigned_t a6, __psunsigned_t a7,
|
||||
__psunsigned_t a8, __psunsigned_t a9,
|
||||
__psunsigned_t a10, __psunsigned_t a11,
|
||||
__psunsigned_t a12, __psunsigned_t a13,
|
||||
__psunsigned_t a14, __psunsigned_t a15)
|
||||
struct xfs_attr_list_context *context,
|
||||
__psunsigned_t a13, __psunsigned_t a14,
|
||||
__psunsigned_t a15)
|
||||
{
|
||||
ASSERT(xfs_attr_trace_buf);
|
||||
ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type),
|
||||
(void *)where,
|
||||
(void *)a2, (void *)a3, (void *)a4,
|
||||
(void *)a5, (void *)a6, (void *)a7,
|
||||
(void *)a8, (void *)a9, (void *)a10,
|
||||
(void *)a11, (void *)a12, (void *)a13,
|
||||
(void *)a14, (void *)a15);
|
||||
(void *)((__psunsigned_t)where),
|
||||
(void *)((__psunsigned_t)context->dp),
|
||||
(void *)((__psunsigned_t)context->cursor->hashval),
|
||||
(void *)((__psunsigned_t)context->cursor->blkno),
|
||||
(void *)((__psunsigned_t)context->cursor->offset),
|
||||
(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 */
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* 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 };
|
||||
|
@ -18,9 +18,11 @@
|
||||
#ifndef __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
|
||||
* 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
|
||||
@ -35,35 +37,6 @@
|
||||
* 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_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_CREATE 0x0010 /* pure create: fail if attr already exists */
|
||||
#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_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
|
||||
@ -118,22 +84,6 @@ typedef struct attrlist_ent { /* data from attr_list() */
|
||||
((attrlist_ent_t *) \
|
||||
&((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.
|
||||
*/
|
||||
@ -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;
|
||||
struct xfs_da_args;
|
||||
|
||||
typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int,
|
||||
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.
|
||||
*/
|
||||
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_rmtval_get(struct xfs_da_args *args);
|
||||
int xfs_attr_list_int(struct xfs_attr_list_context *);
|
||||
|
||||
#endif /* __XFS_ATTR_H__ */
|
||||
|
@ -94,13 +94,6 @@ STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
|
||||
* 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 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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).
|
||||
@ -369,9 +343,10 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
|
||||
* Fix up the start offset of the attribute fork
|
||||
*/
|
||||
totsize -= size;
|
||||
if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname &&
|
||||
(mp->m_flags & XFS_MOUNT_ATTR2) &&
|
||||
(dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) {
|
||||
if (totsize == sizeof(xfs_attr_sf_hdr_t) &&
|
||||
!(args->op_flags & XFS_DA_OP_ADDNAME) &&
|
||||
(mp->m_flags & XFS_MOUNT_ATTR2) &&
|
||||
(dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) {
|
||||
/*
|
||||
* Last attribute now removed, revert to original
|
||||
* 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);
|
||||
dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);
|
||||
ASSERT(dp->i_d.di_forkoff);
|
||||
ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname ||
|
||||
!(mp->m_flags & XFS_MOUNT_ATTR2) ||
|
||||
dp->i_d.di_format == XFS_DINODE_FMT_BTREE);
|
||||
ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) ||
|
||||
(args->op_flags & XFS_DA_OP_ADDNAME) ||
|
||||
!(mp->m_flags & XFS_MOUNT_ATTR2) ||
|
||||
dp->i_d.di_format == XFS_DINODE_FMT_BTREE);
|
||||
dp->i_afp->if_ext_max =
|
||||
XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
|
||||
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.whichfork = XFS_ATTR_FORK;
|
||||
nargs.trans = args->trans;
|
||||
nargs.oknoent = 1;
|
||||
nargs.op_flags = XFS_DA_OP_OKNOENT;
|
||||
|
||||
sfe = &sf->list[0];
|
||||
for (i = 0; i < sf->hdr.count; i++) {
|
||||
@ -555,7 +531,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
|
||||
out:
|
||||
if(bp)
|
||||
xfs_da_buf_done(bp);
|
||||
kmem_free(tmpbuffer, size);
|
||||
kmem_free(tmpbuffer);
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -624,15 +600,8 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
|
||||
(XFS_ISRESET_CURSOR(cursor) &&
|
||||
(dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
|
||||
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,
|
||||
namesp,
|
||||
sfe->flags,
|
||||
(char *)sfe->nameval,
|
||||
(int)sfe->namelen,
|
||||
(int)sfe->valuelen,
|
||||
@ -676,13 +645,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
|
||||
XFS_ERRLEVEL_LOW,
|
||||
context->dp->i_mount, sfe);
|
||||
xfs_attr_trace_l_c("sf corrupted", context);
|
||||
kmem_free(sbuf, sbsize);
|
||||
kmem_free(sbuf);
|
||||
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->hash = xfs_da_hashname((char *)sfe->nameval, sfe->namelen);
|
||||
sbp->name = (char *)sfe->nameval;
|
||||
@ -717,7 +683,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
|
||||
}
|
||||
}
|
||||
if (i == nsbuf) {
|
||||
kmem_free(sbuf, sbsize);
|
||||
kmem_free(sbuf);
|
||||
xfs_attr_trace_l_c("blk end", context);
|
||||
return(0);
|
||||
}
|
||||
@ -726,16 +692,12 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
|
||||
* Loop putting entries into the user buffer.
|
||||
*/
|
||||
for ( ; i < nsbuf; i++, sbp++) {
|
||||
attrnames_t *namesp;
|
||||
|
||||
namesp = xfs_attr_flags_namesp(sbp->flags);
|
||||
|
||||
if (cursor->hashval != sbp->hash) {
|
||||
cursor->hashval = sbp->hash;
|
||||
cursor->offset = 0;
|
||||
}
|
||||
error = context->put_listent(context,
|
||||
namesp,
|
||||
sbp->flags,
|
||||
sbp->name,
|
||||
sbp->namelen,
|
||||
sbp->valuelen,
|
||||
@ -747,7 +709,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
|
||||
cursor->offset++;
|
||||
}
|
||||
|
||||
kmem_free(sbuf, sbsize);
|
||||
kmem_free(sbuf);
|
||||
xfs_attr_trace_l_c("sf E-O-F", context);
|
||||
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.whichfork = XFS_ATTR_FORK;
|
||||
nargs.trans = args->trans;
|
||||
nargs.oknoent = 1;
|
||||
nargs.op_flags = XFS_DA_OP_OKNOENT;
|
||||
entry = &leaf->entries[0];
|
||||
for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) {
|
||||
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;
|
||||
|
||||
out:
|
||||
kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount));
|
||||
kmem_free(tmpbuffer);
|
||||
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->flags = tmp ? XFS_ATTR_LOCAL : 0;
|
||||
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;
|
||||
if ((args->blkno2 == args->blkno) &&
|
||||
(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);
|
||||
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);
|
||||
}
|
||||
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,
|
||||
@ -2400,8 +2362,6 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
|
||||
*/
|
||||
retval = 0;
|
||||
for ( ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) {
|
||||
attrnames_t *namesp;
|
||||
|
||||
if (be32_to_cpu(entry->hashval) != cursor->hashval) {
|
||||
cursor->hashval = be32_to_cpu(entry->hashval);
|
||||
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)
|
||||
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) {
|
||||
xfs_attr_leaf_name_local_t *name_loc =
|
||||
XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
|
||||
|
||||
retval = context->put_listent(context,
|
||||
namesp,
|
||||
entry->flags,
|
||||
(char *)name_loc->nameval,
|
||||
(int)name_loc->namelen,
|
||||
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)
|
||||
return retval;
|
||||
retval = context->put_listent(context,
|
||||
namesp,
|
||||
entry->flags,
|
||||
(char *)name_rmt->name,
|
||||
(int)name_rmt->namelen,
|
||||
valuelen,
|
||||
(char*)args.value);
|
||||
kmem_free(args.value, valuelen);
|
||||
}
|
||||
else {
|
||||
kmem_free(args.value);
|
||||
} else {
|
||||
retval = context->put_listent(context,
|
||||
namesp,
|
||||
entry->flags,
|
||||
(char *)name_rmt->name,
|
||||
(int)name_rmt->namelen,
|
||||
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 */
|
||||
}
|
||||
|
||||
kmem_free((xfs_caddr_t)list, size);
|
||||
kmem_free((xfs_caddr_t)list);
|
||||
return(error);
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
struct attrlist;
|
||||
struct attrlist_cursor_kern;
|
||||
struct attrnames;
|
||||
struct xfs_attr_list_context;
|
||||
struct xfs_dabuf;
|
||||
struct xfs_da_args;
|
||||
struct xfs_da_state;
|
||||
@ -204,33 +204,6 @@ static inline int xfs_attr_leaf_entsize_local_max(int bsize)
|
||||
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.
|
||||
*/
|
||||
|
@ -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,
|
||||
struct xfs_attr_leafblock *leaf);
|
||||
void xfs_attr_trace_enter(int type, char *where,
|
||||
__psunsigned_t a2, __psunsigned_t a3,
|
||||
__psunsigned_t a4, __psunsigned_t a5,
|
||||
__psunsigned_t a6, __psunsigned_t a7,
|
||||
__psunsigned_t a8, __psunsigned_t a9,
|
||||
__psunsigned_t a10, __psunsigned_t a11,
|
||||
__psunsigned_t a12, __psunsigned_t a13,
|
||||
__psunsigned_t a14, __psunsigned_t a15);
|
||||
struct xfs_attr_list_context *context,
|
||||
__psunsigned_t a13, __psunsigned_t a14,
|
||||
__psunsigned_t a15);
|
||||
#else
|
||||
#define xfs_attr_trace_l_c(w,c)
|
||||
#define xfs_attr_trace_l_cn(w,c,n)
|
||||
|
@ -428,7 +428,8 @@ xfs_bmap_add_attrfork_btree(
|
||||
cur->bc_private.b.firstblock = *firstblock;
|
||||
if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat)))
|
||||
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)))
|
||||
goto error0;
|
||||
if (stat == 0) {
|
||||
@ -816,13 +817,13 @@ xfs_bmap_add_extent_delay_real(
|
||||
RIGHT.br_startblock,
|
||||
RIGHT.br_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_delete(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
|
||||
LEFT.br_startblock,
|
||||
LEFT.br_blockcount +
|
||||
@ -860,7 +861,7 @@ xfs_bmap_add_extent_delay_real(
|
||||
LEFT.br_startblock, LEFT.br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
|
||||
LEFT.br_startblock,
|
||||
LEFT.br_blockcount +
|
||||
@ -895,7 +896,7 @@ xfs_bmap_add_extent_delay_real(
|
||||
RIGHT.br_startblock,
|
||||
RIGHT.br_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
|
||||
new->br_startblock,
|
||||
PREV.br_blockcount +
|
||||
@ -928,11 +929,11 @@ xfs_bmap_add_extent_delay_real(
|
||||
new->br_startblock, new->br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 0);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
*dnew = 0;
|
||||
/* 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,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
|
||||
LEFT.br_startblock,
|
||||
LEFT.br_blockcount +
|
||||
@ -1004,11 +1005,11 @@ xfs_bmap_add_extent_delay_real(
|
||||
new->br_startblock, new->br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 0);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
|
||||
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_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, new->br_startoff,
|
||||
new->br_startblock,
|
||||
new->br_blockcount +
|
||||
@ -1094,11 +1095,11 @@ xfs_bmap_add_extent_delay_real(
|
||||
new->br_startblock, new->br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 0);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
|
||||
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,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 0);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
|
||||
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_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_delete(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_delete(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
|
||||
LEFT.br_startblock,
|
||||
LEFT.br_blockcount + PREV.br_blockcount +
|
||||
@ -1426,13 +1427,13 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
PREV.br_startblock, PREV.br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_delete(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, LEFT.br_startoff,
|
||||
LEFT.br_startblock,
|
||||
LEFT.br_blockcount + PREV.br_blockcount,
|
||||
@ -1469,13 +1470,13 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
RIGHT.br_startblock,
|
||||
RIGHT.br_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_delete(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, new->br_startoff,
|
||||
new->br_startblock,
|
||||
new->br_blockcount + RIGHT.br_blockcount,
|
||||
@ -1508,7 +1509,7 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
new->br_startblock, new->br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, new->br_startoff,
|
||||
new->br_startblock, new->br_blockcount,
|
||||
newext)))
|
||||
@ -1549,7 +1550,7 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
PREV.br_startblock, PREV.br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur,
|
||||
PREV.br_startoff + 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,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur,
|
||||
PREV.br_startoff + new->br_blockcount,
|
||||
PREV.br_startblock + new->br_blockcount,
|
||||
@ -1606,7 +1607,7 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
cur->bc_rec.b = *new;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
/* DELTA: One in-core extent is split in two. */
|
||||
temp = PREV.br_startoff;
|
||||
@ -1640,7 +1641,7 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
PREV.br_startblock,
|
||||
PREV.br_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
|
||||
PREV.br_startblock,
|
||||
PREV.br_blockcount - new->br_blockcount,
|
||||
@ -1682,7 +1683,7 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
PREV.br_startblock, PREV.br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, PREV.br_startoff,
|
||||
PREV.br_startblock,
|
||||
PREV.br_blockcount - new->br_blockcount,
|
||||
@ -1692,11 +1693,11 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
new->br_startblock, new->br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 0);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
/* DELTA: One in-core extent is split in two. */
|
||||
temp = PREV.br_startoff;
|
||||
@ -1732,27 +1733,34 @@ xfs_bmap_add_extent_unwritten_real(
|
||||
PREV.br_startblock, PREV.br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
/* new right extent - oldext */
|
||||
if ((error = xfs_bmbt_update(cur, r[1].br_startoff,
|
||||
r[1].br_startblock, r[1].br_blockcount,
|
||||
r[1].br_state)))
|
||||
goto done;
|
||||
/* new left extent - oldext */
|
||||
PREV.br_blockcount =
|
||||
new->br_startoff - PREV.br_startoff;
|
||||
cur->bc_rec.b = PREV;
|
||||
cur->bc_rec.b.br_blockcount =
|
||||
new->br_startoff - PREV.br_startoff;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
if ((error = xfs_bmbt_increment(cur, 0, &i)))
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
/*
|
||||
* 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;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
/* 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)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
/* DELTA: One in-core extent is split in three. */
|
||||
temp = PREV.br_startoff;
|
||||
@ -2097,13 +2105,13 @@ xfs_bmap_add_extent_hole_real(
|
||||
right.br_startblock,
|
||||
right.br_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_delete(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_decrement(cur, 0, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, left.br_startoff,
|
||||
left.br_startblock,
|
||||
left.br_blockcount +
|
||||
@ -2139,7 +2147,7 @@ xfs_bmap_add_extent_hole_real(
|
||||
left.br_startblock,
|
||||
left.br_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, left.br_startoff,
|
||||
left.br_startblock,
|
||||
left.br_blockcount +
|
||||
@ -2174,7 +2182,7 @@ xfs_bmap_add_extent_hole_real(
|
||||
right.br_startblock,
|
||||
right.br_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
if ((error = xfs_bmbt_update(cur, new->br_startoff,
|
||||
new->br_startblock,
|
||||
new->br_blockcount +
|
||||
@ -2208,11 +2216,11 @@ xfs_bmap_add_extent_hole_real(
|
||||
new->br_startblock,
|
||||
new->br_blockcount, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 0);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = new->br_state;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
/* DELTA: A new extent was added in a hole. */
|
||||
temp = new->br_startoff;
|
||||
@ -3131,7 +3139,7 @@ xfs_bmap_del_extent(
|
||||
got.br_startblock, got.br_blockcount,
|
||||
&i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
da_old = da_new = 0;
|
||||
} else {
|
||||
@ -3164,7 +3172,7 @@ xfs_bmap_del_extent(
|
||||
}
|
||||
if ((error = xfs_bmbt_delete(cur, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@ -3268,7 +3276,7 @@ xfs_bmap_del_extent(
|
||||
got.br_startblock,
|
||||
temp, &i)))
|
||||
goto done;
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
/*
|
||||
* Update the btree record back
|
||||
* to the original value.
|
||||
@ -3289,7 +3297,7 @@ xfs_bmap_del_extent(
|
||||
error = XFS_ERROR(ENOSPC);
|
||||
goto done;
|
||||
}
|
||||
ASSERT(i == 1);
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
} else
|
||||
flags |= XFS_ILOG_FEXT(whichfork);
|
||||
XFS_IFORK_NEXT_SET(ip, whichfork,
|
||||
@ -5970,7 +5978,7 @@ unlock_and_return:
|
||||
xfs_iunlock_map_shared(ip, lock);
|
||||
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
|
||||
|
||||
kmem_free(map, subnex * sizeof(*map));
|
||||
kmem_free(map);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -54,12 +54,23 @@ typedef struct xfs_bmap_free_item
|
||||
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */
|
||||
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;
|
||||
|
||||
#define XFS_BMAP_MAX_NMAP 4
|
||||
|
@ -1493,12 +1493,27 @@ xfs_bmbt_split(
|
||||
left = XFS_BUF_TO_BMBT_BLOCK(lbp);
|
||||
args.fsbno = cur->bc_private.b.firstblock;
|
||||
args.firstblock = args.fsbno;
|
||||
args.minleft = 0;
|
||||
if (args.fsbno == NULLFSBLOCK) {
|
||||
args.fsbno = lbno;
|
||||
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.mod = args.minleft = args.alignment = args.total = args.isfl =
|
||||
args.mod = args.alignment = args.total = args.isfl =
|
||||
args.userdata = args.minalignslop = 0;
|
||||
args.minlen = args.maxlen = args.prod = 1;
|
||||
args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL;
|
||||
@ -1510,6 +1525,21 @@ xfs_bmbt_split(
|
||||
XFS_BMBT_TRACE_CURSOR(cur, 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) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
|
||||
*stat = 0;
|
||||
@ -2029,22 +2059,8 @@ xfs_bmbt_increment(
|
||||
* Insert the current record at the point referenced by cur.
|
||||
*
|
||||
* 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
|
||||
* always valid. Hence if we do a multi-level split we need to revalidate the
|
||||
* 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.
|
||||
* cursor. All callers of this function should assume that the cursor is
|
||||
* no longer valid and revalidate it.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmbt_insert(
|
||||
@ -2057,14 +2073,11 @@ xfs_bmbt_insert(
|
||||
xfs_fsblock_t nbno;
|
||||
xfs_btree_cur_t *ncur;
|
||||
xfs_bmbt_rec_t nrec;
|
||||
xfs_bmbt_irec_t oirec; /* original irec */
|
||||
xfs_btree_cur_t *pcur;
|
||||
int splits = 0;
|
||||
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
|
||||
level = 0;
|
||||
nbno = NULLFSBLOCK;
|
||||
oirec = cur->bc_rec.b;
|
||||
xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b);
|
||||
ncur = NULL;
|
||||
pcur = cur;
|
||||
@ -2073,13 +2086,11 @@ xfs_bmbt_insert(
|
||||
&i))) {
|
||||
if (pcur != cur)
|
||||
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);
|
||||
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_private.b.allocated +=
|
||||
pcur->bc_private.b.allocated;
|
||||
@ -2093,21 +2104,10 @@ xfs_bmbt_insert(
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR);
|
||||
}
|
||||
if (ncur) {
|
||||
splits++;
|
||||
pcur = ncur;
|
||||
ncur = NULL;
|
||||
}
|
||||
} 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);
|
||||
*stat = i;
|
||||
return 0;
|
||||
@ -2254,7 +2254,9 @@ xfs_bmbt_newroot(
|
||||
#endif
|
||||
args.fsbno = be64_to_cpu(*pp);
|
||||
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;
|
||||
if ((error = xfs_alloc_vextent(&args))) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
|
@ -889,9 +889,9 @@ xfs_buf_item_relse(
|
||||
}
|
||||
|
||||
#ifdef XFS_TRANS_DEBUG
|
||||
kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp));
|
||||
kmem_free(bip->bli_orig);
|
||||
bip->bli_orig = NULL;
|
||||
kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY);
|
||||
kmem_free(bip->bli_logged);
|
||||
bip->bli_logged = NULL;
|
||||
#endif /* XFS_TRANS_DEBUG */
|
||||
|
||||
@ -1138,9 +1138,9 @@ xfs_buf_iodone(
|
||||
xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip);
|
||||
|
||||
#ifdef XFS_TRANS_DEBUG
|
||||
kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp));
|
||||
kmem_free(bip->bli_orig);
|
||||
bip->bli_orig = NULL;
|
||||
kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY);
|
||||
kmem_free(bip->bli_logged);
|
||||
bip->bli_logged = NULL;
|
||||
#endif /* XFS_TRANS_DEBUG */
|
||||
|
||||
|
@ -78,6 +78,7 @@ struct xfs_mount_args {
|
||||
#define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */
|
||||
#define XFSMNT_OSYNCISOSYNC 0x00004000 /* o_sync is REALLY o_sync */
|
||||
/* (osyncisdsync is default) */
|
||||
#define XFSMNT_NOATTR2 0x00008000 /* turn off ATTR2 EA format */
|
||||
#define XFSMNT_32BITINODES 0x00200000 /* restrict inodes to 32
|
||||
* bits of address space */
|
||||
#define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */
|
||||
|
@ -1431,7 +1431,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
|
||||
}
|
||||
if (level < 0) {
|
||||
*result = XFS_ERROR(ENOENT); /* we're out of our tree */
|
||||
ASSERT(args->oknoent);
|
||||
ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
|
||||
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.
|
||||
* 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,
|
||||
&mapp[mapi], &nmap, args->flist,
|
||||
NULL))) {
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
kmem_free(mapp);
|
||||
return error;
|
||||
}
|
||||
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 !=
|
||||
bno + count) {
|
||||
if (mapp != &map)
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
kmem_free(mapp);
|
||||
return XFS_ERROR(ENOSPC);
|
||||
}
|
||||
if (mapp != &map)
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
kmem_free(mapp);
|
||||
*new_blkno = (xfs_dablk_t)bno;
|
||||
return 0;
|
||||
}
|
||||
@ -2090,10 +2112,10 @@ xfs_da_do_buf(
|
||||
}
|
||||
}
|
||||
if (bplist) {
|
||||
kmem_free(bplist, sizeof(*bplist) * nmap);
|
||||
kmem_free(bplist);
|
||||
}
|
||||
if (mapp != &map) {
|
||||
kmem_free(mapp, sizeof(*mapp) * nfsb);
|
||||
kmem_free(mapp);
|
||||
}
|
||||
if (bpp)
|
||||
*bpp = rbp;
|
||||
@ -2102,11 +2124,11 @@ exit1:
|
||||
if (bplist) {
|
||||
for (i = 0; i < nbplist; i++)
|
||||
xfs_trans_brelse(trans, bplist[i]);
|
||||
kmem_free(bplist, sizeof(*bplist) * nmap);
|
||||
kmem_free(bplist);
|
||||
}
|
||||
exit0:
|
||||
if (mapp != &map)
|
||||
kmem_free(mapp, sizeof(*mapp) * nfsb);
|
||||
kmem_free(mapp);
|
||||
if (bpp)
|
||||
*bpp = NULL;
|
||||
return error;
|
||||
@ -2218,7 +2240,7 @@ xfs_da_state_free(xfs_da_state_t *state)
|
||||
|
||||
#ifdef XFS_DABUF_DEBUG
|
||||
xfs_dabuf_t *xfs_dabuf_global_list;
|
||||
spinlock_t xfs_dabuf_global_lock;
|
||||
static DEFINE_SPINLOCK(xfs_dabuf_global_lock);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -2315,7 +2337,7 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf)
|
||||
if (dabuf->dirty)
|
||||
xfs_da_buf_clean(dabuf);
|
||||
if (dabuf->nbuf > 1)
|
||||
kmem_free(dabuf->data, BBTOB(dabuf->bbcount));
|
||||
kmem_free(dabuf->data);
|
||||
#ifdef XFS_DABUF_DEBUG
|
||||
{
|
||||
spin_lock(&xfs_dabuf_global_lock);
|
||||
@ -2332,7 +2354,7 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf)
|
||||
if (dabuf->nbuf == 1)
|
||||
kmem_zone_free(xfs_dabuf_zone, dabuf);
|
||||
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++)
|
||||
xfs_trans_brelse(tp, bplist[i]);
|
||||
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++)
|
||||
xfs_trans_binval(tp, bplist[i]);
|
||||
if (bplist != &bp)
|
||||
kmem_free(bplist, nbuf * sizeof(*bplist));
|
||||
kmem_free(bplist);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -98,6 +98,15 @@ typedef struct xfs_da_node_entry xfs_da_node_entry_t;
|
||||
* 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.
|
||||
*/
|
||||
@ -123,12 +132,19 @@ typedef struct xfs_da_args {
|
||||
int index2; /* index of 2nd attr in blk */
|
||||
xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */
|
||||
int rmtblkcnt2; /* remote attr value block count */
|
||||
unsigned char justcheck; /* T/F: check for ok with no space */
|
||||
unsigned char rename; /* T/F: this is an atomic rename op */
|
||||
unsigned char addname; /* T/F: this is an add operation */
|
||||
unsigned char oknoent; /* T/F: ok to return ENOENT, else die */
|
||||
int op_flags; /* operation flags */
|
||||
enum xfs_dacmp cmpresult; /* name compare result for lookups */
|
||||
} 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.
|
||||
* 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)+(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__
|
||||
/*========================================================================
|
||||
@ -249,6 +273,10 @@ int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
|
||||
xfs_dabuf_t *dead_buf);
|
||||
|
||||
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);
|
||||
void xfs_da_state_free(xfs_da_state_t *state);
|
||||
|
||||
|
@ -116,7 +116,7 @@ xfs_swapext(
|
||||
out_put_file:
|
||||
fput(file);
|
||||
out_free_sxp:
|
||||
kmem_free(sxp, sizeof(xfs_swapext_t));
|
||||
kmem_free(sxp);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
@ -381,6 +381,6 @@ xfs_swap_extents(
|
||||
xfs_iunlock(tip, lock_flags);
|
||||
}
|
||||
if (tempifp != NULL)
|
||||
kmem_free(tempifp, sizeof(xfs_ifork_t));
|
||||
kmem_free(tempifp);
|
||||
return error;
|
||||
}
|
||||
|
@ -46,6 +46,54 @@
|
||||
|
||||
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
|
||||
xfs_dir_mount(
|
||||
xfs_mount_t *mp)
|
||||
@ -65,6 +113,10 @@ xfs_dir_mount(
|
||||
(mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
|
||||
(uint)sizeof(xfs_da_node_entry_t);
|
||||
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;
|
||||
XFS_STATS_INC(xs_dir_create);
|
||||
|
||||
memset(&args, 0, sizeof(xfs_da_args_t));
|
||||
args.name = name->name;
|
||||
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.dp = dp;
|
||||
args.firstblock = first;
|
||||
@ -172,8 +225,7 @@ xfs_dir_createname(
|
||||
args.total = total;
|
||||
args.whichfork = XFS_DATA_FORK;
|
||||
args.trans = tp;
|
||||
args.justcheck = 0;
|
||||
args.addname = args.oknoent = 1;
|
||||
args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
|
||||
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
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
|
||||
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_trans_t *tp,
|
||||
xfs_inode_t *dp,
|
||||
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;
|
||||
int rval;
|
||||
@ -206,15 +287,17 @@ xfs_dir_lookup(
|
||||
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
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.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.whichfork = XFS_DATA_FORK;
|
||||
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)
|
||||
rval = xfs_dir2_sf_lookup(&args);
|
||||
@ -230,8 +313,13 @@ xfs_dir_lookup(
|
||||
rval = xfs_dir2_node_lookup(&args);
|
||||
if (rval == EEXIST)
|
||||
rval = 0;
|
||||
if (rval == 0)
|
||||
if (!rval) {
|
||||
*inum = args.inumber;
|
||||
if (ci_name) {
|
||||
ci_name->name = args.value;
|
||||
ci_name->len = args.valuelen;
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
@ -255,9 +343,10 @@ xfs_dir_removename(
|
||||
ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
|
||||
XFS_STATS_INC(xs_dir_remove);
|
||||
|
||||
memset(&args, 0, sizeof(xfs_da_args_t));
|
||||
args.name = name->name;
|
||||
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.dp = dp;
|
||||
args.firstblock = first;
|
||||
@ -265,7 +354,6 @@ xfs_dir_removename(
|
||||
args.total = total;
|
||||
args.whichfork = XFS_DATA_FORK;
|
||||
args.trans = tp;
|
||||
args.justcheck = args.addname = args.oknoent = 0;
|
||||
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
rval = xfs_dir2_sf_removename(&args);
|
||||
@ -338,9 +426,10 @@ xfs_dir_replace(
|
||||
if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
|
||||
return rval;
|
||||
|
||||
memset(&args, 0, sizeof(xfs_da_args_t));
|
||||
args.name = name->name;
|
||||
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.dp = dp;
|
||||
args.firstblock = first;
|
||||
@ -348,7 +437,6 @@ xfs_dir_replace(
|
||||
args.total = total;
|
||||
args.whichfork = XFS_DATA_FORK;
|
||||
args.trans = tp;
|
||||
args.justcheck = args.addname = args.oknoent = 0;
|
||||
|
||||
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
|
||||
rval = xfs_dir2_sf_replace(&args);
|
||||
@ -384,15 +472,16 @@ xfs_dir_canenter(
|
||||
return 0;
|
||||
|
||||
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.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.whichfork = XFS_DATA_FORK;
|
||||
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)
|
||||
rval = xfs_dir2_sf_addname(&args);
|
||||
@ -493,7 +582,7 @@ xfs_dir2_grow_inode(
|
||||
args->firstblock, args->total,
|
||||
&mapp[mapi], &nmap, args->flist,
|
||||
NULL))) {
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
kmem_free(mapp);
|
||||
return error;
|
||||
}
|
||||
if (nmap < 1)
|
||||
@ -525,14 +614,14 @@ xfs_dir2_grow_inode(
|
||||
mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
|
||||
bno + count) {
|
||||
if (mapp != &map)
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
kmem_free(mapp);
|
||||
return XFS_ERROR(ENOSPC);
|
||||
}
|
||||
/*
|
||||
* Done with the temporary mapping table.
|
||||
*/
|
||||
if (mapp != &map)
|
||||
kmem_free(mapp, sizeof(*mapp) * count);
|
||||
kmem_free(mapp);
|
||||
*dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
|
||||
/*
|
||||
* Update file's size if this is the data space and it grew.
|
||||
|
@ -74,7 +74,8 @@ extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
|
||||
xfs_fsblock_t *first,
|
||||
struct xfs_bmap_free *flist, xfs_extlen_t tot);
|
||||
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,
|
||||
struct xfs_name *name, xfs_ino_t ino,
|
||||
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,
|
||||
struct xfs_dabuf *bp);
|
||||
|
||||
extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const char *name,
|
||||
int len);
|
||||
|
||||
#endif /* __XFS_DIR2_H__ */
|
||||
|
@ -215,7 +215,7 @@ xfs_dir2_block_addname(
|
||||
/*
|
||||
* 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);
|
||||
/*
|
||||
* 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
|
||||
* 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);
|
||||
/*
|
||||
* Convert to the next larger format.
|
||||
@ -240,7 +240,7 @@ xfs_dir2_block_addname(
|
||||
/*
|
||||
* Just checking, and it would work, so say so.
|
||||
*/
|
||||
if (args->justcheck)
|
||||
if (args->op_flags & XFS_DA_OP_JUSTCHECK)
|
||||
return 0;
|
||||
needlog = needscan = 0;
|
||||
/*
|
||||
@ -610,14 +610,15 @@ xfs_dir2_block_lookup(
|
||||
/*
|
||||
* Get the offset from the leaf entry, to point to the data.
|
||||
*/
|
||||
dep = (xfs_dir2_data_entry_t *)
|
||||
((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
|
||||
dep = (xfs_dir2_data_entry_t *)((char *)block +
|
||||
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);
|
||||
error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
|
||||
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 */
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
xfs_trans_t *tp; /* transaction pointer */
|
||||
enum xfs_dacmp cmp; /* comparison result */
|
||||
|
||||
dp = args->dp;
|
||||
tp = args->trans;
|
||||
@ -673,7 +675,7 @@ xfs_dir2_block_lookup_int(
|
||||
else
|
||||
high = mid - 1;
|
||||
if (low > high) {
|
||||
ASSERT(args->oknoent);
|
||||
ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
|
||||
xfs_da_brelse(tp, bp);
|
||||
return XFS_ERROR(ENOENT);
|
||||
}
|
||||
@ -697,20 +699,31 @@ xfs_dir2_block_lookup_int(
|
||||
dep = (xfs_dir2_data_entry_t *)
|
||||
((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 &&
|
||||
dep->name[0] == args->name[0] &&
|
||||
memcmp(dep->name, args->name, args->namelen) == 0) {
|
||||
cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
|
||||
if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
|
||||
args->cmpresult = cmp;
|
||||
*bpp = bp;
|
||||
*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.
|
||||
*/
|
||||
ASSERT(args->oknoent);
|
||||
xfs_da_brelse(tp, bp);
|
||||
return XFS_ERROR(ENOENT);
|
||||
}
|
||||
@ -1033,6 +1046,7 @@ xfs_dir2_sf_to_block(
|
||||
xfs_dir2_sf_t *sfp; /* shortform structure */
|
||||
__be16 *tagp; /* end of data entry */
|
||||
xfs_trans_t *tp; /* transaction pointer */
|
||||
struct xfs_name name;
|
||||
|
||||
xfs_dir2_trace_args("sf_to_block", args);
|
||||
dp = args->dp;
|
||||
@ -1071,7 +1085,7 @@ xfs_dir2_sf_to_block(
|
||||
*/
|
||||
error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno);
|
||||
if (error) {
|
||||
kmem_free(buf, buf_len);
|
||||
kmem_free(buf);
|
||||
return error;
|
||||
}
|
||||
/*
|
||||
@ -1079,7 +1093,7 @@ xfs_dir2_sf_to_block(
|
||||
*/
|
||||
error = xfs_dir2_data_init(args, blkno, &bp);
|
||||
if (error) {
|
||||
kmem_free(buf, buf_len);
|
||||
kmem_free(buf);
|
||||
return error;
|
||||
}
|
||||
block = bp->data;
|
||||
@ -1187,8 +1201,10 @@ xfs_dir2_sf_to_block(
|
||||
tagp = xfs_dir2_data_entry_tag_p(dep);
|
||||
*tagp = cpu_to_be16((char *)dep - (char *)block);
|
||||
xfs_dir2_data_log_entry(tp, bp, dep);
|
||||
blp[2 + i].hashval = cpu_to_be32(xfs_da_hashname(
|
||||
(char *)sfep->name, sfep->namelen));
|
||||
name.name = sfep->name;
|
||||
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,
|
||||
(char *)dep - (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);
|
||||
}
|
||||
/* Done with the temporary buffer */
|
||||
kmem_free(buf, buf_len);
|
||||
kmem_free(buf);
|
||||
/*
|
||||
* Sort the leaf entries by hash value.
|
||||
*/
|
||||
|
@ -65,6 +65,7 @@ xfs_dir2_data_check(
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
char *p; /* current data position */
|
||||
int stale; /* count of stale leaves */
|
||||
struct xfs_name name;
|
||||
|
||||
mp = dp->i_mount;
|
||||
d = bp->data;
|
||||
@ -140,7 +141,9 @@ xfs_dir2_data_check(
|
||||
addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
|
||||
(xfs_dir2_data_aoff_t)
|
||||
((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++) {
|
||||
if (be32_to_cpu(lep[i].address) == addr &&
|
||||
be32_to_cpu(lep[i].hashval) == hash)
|
||||
|
@ -263,20 +263,21 @@ xfs_dir2_leaf_addname(
|
||||
* If we don't have enough free bytes but we can make enough
|
||||
* by compacting out stale entries, we'll do that.
|
||||
*/
|
||||
if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] < needbytes &&
|
||||
be16_to_cpu(leaf->hdr.stale) > 1) {
|
||||
if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <
|
||||
needbytes && be16_to_cpu(leaf->hdr.stale) > 1) {
|
||||
compact = 1;
|
||||
}
|
||||
/*
|
||||
* Otherwise if we don't have enough free bytes we need to
|
||||
* convert to node form.
|
||||
*/
|
||||
else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <
|
||||
needbytes) {
|
||||
else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(
|
||||
leaf->hdr.count)] < needbytes) {
|
||||
/*
|
||||
* 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);
|
||||
return XFS_ERROR(ENOSPC);
|
||||
}
|
||||
@ -301,7 +302,7 @@ xfs_dir2_leaf_addname(
|
||||
* If just checking, then it will fit unless we needed to allocate
|
||||
* a new data block.
|
||||
*/
|
||||
if (args->justcheck) {
|
||||
if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
|
||||
xfs_da_brelse(tp, lbp);
|
||||
return use_block == -1 ? XFS_ERROR(ENOSPC) : 0;
|
||||
}
|
||||
@ -1110,7 +1111,7 @@ xfs_dir2_leaf_getdents(
|
||||
*offset = XFS_DIR2_MAX_DATAPTR;
|
||||
else
|
||||
*offset = xfs_dir2_byte_to_dataptr(mp, curoff);
|
||||
kmem_free(map, map_size * sizeof(*map));
|
||||
kmem_free(map);
|
||||
if (bp)
|
||||
xfs_da_brelse(NULL, bp);
|
||||
return error;
|
||||
@ -1298,12 +1299,13 @@ xfs_dir2_leaf_lookup(
|
||||
((char *)dbp->data +
|
||||
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);
|
||||
error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
|
||||
xfs_da_brelse(tp, dbp);
|
||||
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 */
|
||||
xfs_dabuf_t **dbpp) /* out: data buffer */
|
||||
{
|
||||
xfs_dir2_db_t curdb; /* current data block number */
|
||||
xfs_dabuf_t *dbp; /* data buffer */
|
||||
xfs_dir2_db_t curdb = -1; /* current data block number */
|
||||
xfs_dabuf_t *dbp = NULL; /* data buffer */
|
||||
xfs_dir2_data_entry_t *dep; /* data entry */
|
||||
xfs_inode_t *dp; /* incore directory inode */
|
||||
int error; /* error return code */
|
||||
@ -1331,6 +1333,8 @@ xfs_dir2_leaf_lookup_int(
|
||||
xfs_mount_t *mp; /* filesystem mount point */
|
||||
xfs_dir2_db_t newdb; /* new data block number */
|
||||
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;
|
||||
tp = args->trans;
|
||||
@ -1338,11 +1342,10 @@ xfs_dir2_leaf_lookup_int(
|
||||
/*
|
||||
* Read the leaf block into the buffer.
|
||||
*/
|
||||
if ((error =
|
||||
xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp,
|
||||
XFS_DATA_FORK))) {
|
||||
error = xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp,
|
||||
XFS_DATA_FORK);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
*lbpp = lbp;
|
||||
leaf = lbp->data;
|
||||
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
|
||||
* looking to match the name.
|
||||
*/
|
||||
for (lep = &leaf->ents[index], dbp = NULL, curdb = -1;
|
||||
index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval;
|
||||
lep++, index++) {
|
||||
for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) &&
|
||||
be32_to_cpu(lep->hashval) == args->hashval;
|
||||
lep++, index++) {
|
||||
/*
|
||||
* Skip over stale leaf entries.
|
||||
*/
|
||||
@ -1373,10 +1376,10 @@ xfs_dir2_leaf_lookup_int(
|
||||
if (newdb != curdb) {
|
||||
if (dbp)
|
||||
xfs_da_brelse(tp, dbp);
|
||||
if ((error =
|
||||
xfs_da_read_buf(tp, dp,
|
||||
xfs_dir2_db_to_da(mp, newdb), -1, &dbp,
|
||||
XFS_DATA_FORK))) {
|
||||
error = xfs_da_read_buf(tp, dp,
|
||||
xfs_dir2_db_to_da(mp, newdb),
|
||||
-1, &dbp, XFS_DATA_FORK);
|
||||
if (error) {
|
||||
xfs_da_brelse(tp, lbp);
|
||||
return error;
|
||||
}
|
||||
@ -1386,24 +1389,50 @@ xfs_dir2_leaf_lookup_int(
|
||||
/*
|
||||
* Point to the data entry.
|
||||
*/
|
||||
dep = (xfs_dir2_data_entry_t *)
|
||||
((char *)dbp->data +
|
||||
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
|
||||
dep = (xfs_dir2_data_entry_t *)((char *)dbp->data +
|
||||
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 &&
|
||||
dep->name[0] == args->name[0] &&
|
||||
memcmp(dep->name, args->name, args->namelen) == 0) {
|
||||
*dbpp = dbp;
|
||||
cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
|
||||
if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
|
||||
args->cmpresult = cmp;
|
||||
*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.
|
||||
*/
|
||||
ASSERT(args->oknoent);
|
||||
ASSERT(cidb == -1);
|
||||
if (dbp)
|
||||
xfs_da_brelse(tp, dbp);
|
||||
xfs_da_brelse(tp, lbp);
|
||||
|
@ -226,7 +226,7 @@ xfs_dir2_leafn_add(
|
||||
ASSERT(index == be16_to_cpu(leaf->hdr.count) ||
|
||||
be32_to_cpu(leaf->ents[index].hashval) >= args->hashval);
|
||||
|
||||
if (args->justcheck)
|
||||
if (args->op_flags & XFS_DA_OP_JUSTCHECK)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -387,28 +387,26 @@ xfs_dir2_leafn_lasthash(
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* Look up a leaf entry for space to add a name in a node-format leaf block.
|
||||
* The extrablk in state is a freespace block.
|
||||
*/
|
||||
int
|
||||
xfs_dir2_leafn_lookup_int(
|
||||
STATIC int
|
||||
xfs_dir2_leafn_lookup_for_addname(
|
||||
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; /* current data/free buffer */
|
||||
xfs_dir2_db_t curdb; /* current data block number */
|
||||
xfs_dir2_db_t curfdb; /* current free block number */
|
||||
xfs_dir2_data_entry_t *dep; /* data block entry */
|
||||
xfs_dabuf_t *curbp = NULL; /* current data/free buffer */
|
||||
xfs_dir2_db_t curdb = -1; /* current data block number */
|
||||
xfs_dir2_db_t curfdb = -1; /* current free block number */
|
||||
xfs_inode_t *dp; /* incore directory inode */
|
||||
int error; /* error return value */
|
||||
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 */
|
||||
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_mount_t *mp; /* filesystem mount point */
|
||||
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?
|
||||
*/
|
||||
if (state->extravalid)
|
||||
if (state->extravalid) {
|
||||
/* If so, it's a free block buffer, get the block number. */
|
||||
curbp = state->extrablk.bp;
|
||||
else
|
||||
curbp = NULL;
|
||||
/*
|
||||
* 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;
|
||||
curfdb = state->extrablk.blkno;
|
||||
free = curbp->data;
|
||||
ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
|
||||
}
|
||||
length = xfs_dir2_data_entsize(args->namelen);
|
||||
/*
|
||||
* 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++) {
|
||||
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.
|
||||
*/
|
||||
@ -471,160 +456,243 @@ xfs_dir2_leafn_lookup_int(
|
||||
* 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
|
||||
* 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
|
||||
* in hand, take a look at it.
|
||||
* Convert the data block to the free block
|
||||
* holding its freespace information.
|
||||
*/
|
||||
if (newdb != curdb) {
|
||||
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 {
|
||||
newfdb = xfs_dir2_db_to_fdb(mp, newdb);
|
||||
/*
|
||||
* 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)
|
||||
xfs_da_brelse(tp, curbp);
|
||||
/*
|
||||
* Read the data block.
|
||||
* Read the free block.
|
||||
*/
|
||||
if ((error =
|
||||
xfs_da_read_buf(tp, dp,
|
||||
xfs_dir2_db_to_da(mp, newdb), -1,
|
||||
&curbp, XFS_DATA_FORK))) {
|
||||
error = xfs_da_read_buf(tp, dp,
|
||||
xfs_dir2_db_to_da(mp, newfdb),
|
||||
-1, &curbp, XFS_DATA_FORK);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
xfs_dir2_data_check(dp, curbp);
|
||||
curdb = newdb;
|
||||
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));
|
||||
}
|
||||
/*
|
||||
* Point to the data entry.
|
||||
* Get the index for our entry.
|
||||
*/
|
||||
dep = (xfs_dir2_data_entry_t *)
|
||||
((char *)curbp->data +
|
||||
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
|
||||
fi = xfs_dir2_db_to_fdindex(mp, curdb);
|
||||
/*
|
||||
* Compare the entry, return it if it matches.
|
||||
* If it has room, return it.
|
||||
*/
|
||||
if (dep->namelen == args->namelen &&
|
||||
dep->name[0] == args->name[0] &&
|
||||
memcmp(dep->name, args->name, args->namelen) == 0) {
|
||||
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;
|
||||
return XFS_ERROR(EEXIST);
|
||||
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)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Didn't find a match.
|
||||
* If we are holding a buffer, give it back in case our caller
|
||||
* finds it useful.
|
||||
*/
|
||||
if ((state->extravalid = (curbp != NULL))) {
|
||||
/* Didn't find any space */
|
||||
fi = -1;
|
||||
out:
|
||||
ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
|
||||
if (curbp) {
|
||||
/* Giving back a free block. */
|
||||
state->extravalid = 1;
|
||||
state->extrablk.bp = curbp;
|
||||
state->extrablk.index = -1;
|
||||
/*
|
||||
* For addname, giving back a free block.
|
||||
*/
|
||||
if (args->addname) {
|
||||
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;
|
||||
}
|
||||
state->extrablk.index = fi;
|
||||
state->extrablk.blkno = curfdb;
|
||||
state->extrablk.magic = XFS_DIR2_FREE_MAGIC;
|
||||
} else {
|
||||
state->extravalid = 0;
|
||||
}
|
||||
/*
|
||||
* Return the final index, that will be the insertion point.
|
||||
* Return the index, that will be the insertion point.
|
||||
*/
|
||||
*indexp = index;
|
||||
ASSERT(index == be16_to_cpu(leaf->hdr.count) || args->oknoent);
|
||||
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.
|
||||
* Log entries and headers. Stale entries are preserved.
|
||||
@ -823,9 +891,10 @@ xfs_dir2_leafn_rebalance(
|
||||
*/
|
||||
if (!state->inleaf)
|
||||
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) {
|
||||
state->inleaf = 1;
|
||||
@ -1332,7 +1401,7 @@ xfs_dir2_node_addname(
|
||||
/*
|
||||
* 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);
|
||||
} else {
|
||||
/*
|
||||
@ -1515,7 +1584,8 @@ xfs_dir2_node_addname_int(
|
||||
/*
|
||||
* 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
|
||||
* caller.
|
||||
@ -1661,7 +1731,7 @@ xfs_dir2_node_addname_int(
|
||||
/*
|
||||
* If just checking, we succeeded.
|
||||
*/
|
||||
if (args->justcheck) {
|
||||
if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
|
||||
if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
|
||||
xfs_da_buf_done(fbp);
|
||||
return 0;
|
||||
@ -1767,6 +1837,14 @@ xfs_dir2_node_lookup(
|
||||
error = xfs_da_node_lookup_int(state, &rval);
|
||||
if (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.
|
||||
*/
|
||||
@ -1810,9 +1888,8 @@ xfs_dir2_node_removename(
|
||||
* Look up the entry we're deleting, set up the cursor.
|
||||
*/
|
||||
error = xfs_da_node_lookup_int(state, &rval);
|
||||
if (error) {
|
||||
if (error)
|
||||
rval = error;
|
||||
}
|
||||
/*
|
||||
* 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,
|
||||
&state->extrablk, &rval);
|
||||
if (error) {
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
/*
|
||||
* Fix the hash values up the btree.
|
||||
*/
|
||||
|
@ -255,7 +255,7 @@ xfs_dir2_block_to_sf(
|
||||
xfs_dir2_sf_check(args);
|
||||
out:
|
||||
xfs_trans_log_inode(args->trans, dp, logflags);
|
||||
kmem_free(block, mp->m_dirblksize);
|
||||
kmem_free(block);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -332,7 +332,7 @@ xfs_dir2_sf_addname(
|
||||
/*
|
||||
* 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);
|
||||
/*
|
||||
* Convert to block form then add the name.
|
||||
@ -345,7 +345,7 @@ xfs_dir2_sf_addname(
|
||||
/*
|
||||
* Just checking, it fits.
|
||||
*/
|
||||
if (args->justcheck)
|
||||
if (args->op_flags & XFS_DA_OP_JUSTCHECK)
|
||||
return 0;
|
||||
/*
|
||||
* 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);
|
||||
memcpy(sfep, oldsfep, old_isize - nbytes);
|
||||
}
|
||||
kmem_free(buf, old_isize);
|
||||
kmem_free(buf);
|
||||
dp->i_d.di_size = new_isize;
|
||||
xfs_dir2_sf_check(args);
|
||||
}
|
||||
@ -812,8 +812,11 @@ xfs_dir2_sf_lookup(
|
||||
{
|
||||
xfs_inode_t *dp; /* incore directory inode */
|
||||
int i; /* entry index */
|
||||
int error;
|
||||
xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
|
||||
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_sf_check(args);
|
||||
@ -836,6 +839,7 @@ xfs_dir2_sf_lookup(
|
||||
*/
|
||||
if (args->namelen == 1 && args->name[0] == '.') {
|
||||
args->inumber = dp->i_ino;
|
||||
args->cmpresult = XFS_CMP_EXACT;
|
||||
return XFS_ERROR(EEXIST);
|
||||
}
|
||||
/*
|
||||
@ -844,28 +848,41 @@ xfs_dir2_sf_lookup(
|
||||
if (args->namelen == 2 &&
|
||||
args->name[0] == '.' && args->name[1] == '.') {
|
||||
args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
|
||||
args->cmpresult = XFS_CMP_EXACT;
|
||||
return XFS_ERROR(EEXIST);
|
||||
}
|
||||
/*
|
||||
* Loop over all the entries trying to match ours.
|
||||
*/
|
||||
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
|
||||
i < sfp->hdr.count;
|
||||
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
|
||||
if (sfep->namelen == args->namelen &&
|
||||
sfep->name[0] == args->name[0] &&
|
||||
memcmp(args->name, sfep->name, args->namelen) == 0) {
|
||||
args->inumber =
|
||||
xfs_dir2_sf_get_inumber(sfp,
|
||||
xfs_dir2_sf_inumberp(sfep));
|
||||
return XFS_ERROR(EEXIST);
|
||||
ci_sfep = NULL;
|
||||
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
|
||||
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
|
||||
/*
|
||||
* Compare name and if it's an exact match, return the inode
|
||||
* number. If it's the first case-insensitive match, store the
|
||||
* inode number and continue looking for an exact match.
|
||||
*/
|
||||
cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name,
|
||||
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);
|
||||
return XFS_ERROR(ENOENT);
|
||||
if (!ci_sfep)
|
||||
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.
|
||||
* Find the one we're deleting.
|
||||
*/
|
||||
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
|
||||
i < sfp->hdr.count;
|
||||
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
|
||||
if (sfep->namelen == args->namelen &&
|
||||
sfep->name[0] == args->name[0] &&
|
||||
memcmp(sfep->name, args->name, args->namelen) == 0) {
|
||||
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
|
||||
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
|
||||
if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
|
||||
XFS_CMP_EXACT) {
|
||||
ASSERT(xfs_dir2_sf_get_inumber(sfp,
|
||||
xfs_dir2_sf_inumberp(sfep)) ==
|
||||
args->inumber);
|
||||
xfs_dir2_sf_inumberp(sfep)) ==
|
||||
args->inumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Didn't find it.
|
||||
*/
|
||||
if (i == sfp->hdr.count) {
|
||||
if (i == sfp->hdr.count)
|
||||
return XFS_ERROR(ENOENT);
|
||||
}
|
||||
/*
|
||||
* Calculate sizes.
|
||||
*/
|
||||
@ -1042,11 +1056,10 @@ xfs_dir2_sf_replace(
|
||||
*/
|
||||
else {
|
||||
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
|
||||
i < sfp->hdr.count;
|
||||
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
|
||||
if (sfep->namelen == args->namelen &&
|
||||
sfep->name[0] == args->name[0] &&
|
||||
memcmp(args->name, sfep->name, args->namelen) == 0) {
|
||||
i < sfp->hdr.count;
|
||||
i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
|
||||
if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
|
||||
XFS_CMP_EXACT) {
|
||||
#if XFS_BIG_INUMS || defined(DEBUG)
|
||||
ino = xfs_dir2_sf_get_inumber(sfp,
|
||||
xfs_dir2_sf_inumberp(sfep));
|
||||
@ -1061,7 +1074,7 @@ xfs_dir2_sf_replace(
|
||||
* Didn't find it.
|
||||
*/
|
||||
if (i == sfp->hdr.count) {
|
||||
ASSERT(args->oknoent);
|
||||
ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
|
||||
#if XFS_BIG_INUMS
|
||||
if (i8elevated)
|
||||
xfs_dir2_sf_toino4(args);
|
||||
@ -1174,7 +1187,7 @@ xfs_dir2_sf_toino4(
|
||||
/*
|
||||
* Clean up the inode.
|
||||
*/
|
||||
kmem_free(buf, oldsize);
|
||||
kmem_free(buf);
|
||||
dp->i_d.di_size = newsize;
|
||||
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.
|
||||
*/
|
||||
kmem_free(buf, oldsize);
|
||||
kmem_free(buf);
|
||||
dp->i_d.di_size = newsize;
|
||||
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ typedef union {
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
@ -76,14 +76,14 @@ typedef struct xfs_dir2_sf_hdr {
|
||||
__uint8_t count; /* count of entries */
|
||||
__uint8_t i8count; /* count of 8-byte inode #s */
|
||||
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 {
|
||||
__uint8_t namelen; /* actual name length */
|
||||
xfs_dir2_sf_off_t offset; /* saved offset */
|
||||
__uint8_t name[1]; /* name, variable size */
|
||||
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 {
|
||||
xfs_dir2_sf_hdr_t hdr; /* shortform header */
|
||||
|
@ -85,7 +85,8 @@ xfs_dir2_trace_args(
|
||||
(void *)((unsigned long)(args->inumber >> 32)),
|
||||
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
|
||||
(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
|
||||
@ -100,7 +101,7 @@ xfs_dir2_trace_args_b(
|
||||
(void *)((unsigned long)(args->inumber >> 32)),
|
||||
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
|
||||
(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);
|
||||
}
|
||||
|
||||
@ -117,7 +118,7 @@ xfs_dir2_trace_args_bb(
|
||||
(void *)((unsigned long)(args->inumber >> 32)),
|
||||
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
|
||||
(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 *)(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 & 0xFFFFFFFF)),
|
||||
(void *)args->dp, (void *)args->trans,
|
||||
(void *)(unsigned long)args->justcheck, (void *)(long)db,
|
||||
(void *)dbp);
|
||||
(void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
|
||||
(void *)(long)db, (void *)dbp);
|
||||
}
|
||||
|
||||
void
|
||||
@ -173,7 +174,7 @@ xfs_dir2_trace_args_i(
|
||||
(void *)((unsigned long)(args->inumber >> 32)),
|
||||
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
|
||||
(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 & 0xFFFFFFFF)));
|
||||
}
|
||||
@ -190,7 +191,8 @@ xfs_dir2_trace_args_s(
|
||||
(void *)((unsigned long)(args->inumber >> 32)),
|
||||
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
|
||||
(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
|
||||
@ -208,7 +210,7 @@ xfs_dir2_trace_args_sb(
|
||||
(void *)((unsigned long)(args->inumber >> 32)),
|
||||
(void *)((unsigned long)(args->inumber & 0xFFFFFFFF)),
|
||||
(void *)args->dp, (void *)args->trans,
|
||||
(void *)(unsigned long)args->justcheck, (void *)(long)s,
|
||||
(void *)dbp);
|
||||
(void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK),
|
||||
(void *)(long)s, (void *)dbp);
|
||||
}
|
||||
#endif /* XFS_DIR2_TRACE */
|
||||
|
@ -166,6 +166,6 @@ typedef enum {
|
||||
|
||||
#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \
|
||||
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__ */
|
||||
|
@ -66,14 +66,6 @@ int xfs_etest[XFS_NUM_INJECT_ERROR];
|
||||
int64_t xfs_etest_fsid[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
|
||||
xfs_error_test(int error_tag, int *fsidp, char *expression,
|
||||
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] = 0;
|
||||
xfs_etest_fsid[i] = 0LL;
|
||||
kmem_free(xfs_etest_fsname[i],
|
||||
strlen(xfs_etest_fsname[i]) + 1);
|
||||
kmem_free(xfs_etest_fsname[i]);
|
||||
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);
|
||||
sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt);
|
||||
icmn_err(level, newfmt, ap);
|
||||
kmem_free(newfmt, len);
|
||||
kmem_free(newfmt);
|
||||
} else {
|
||||
icmn_err(level, fmt, ap);
|
||||
}
|
||||
|
@ -127,7 +127,6 @@ extern void xfs_corruption_error(char *tag, int level, struct xfs_mount *mp,
|
||||
|
||||
#if (defined(DEBUG) || defined(INDUCE_IO_ERROR))
|
||||
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
|
||||
|
||||
|
@ -41,8 +41,7 @@ xfs_efi_item_free(xfs_efi_log_item_t *efip)
|
||||
int nexts = efip->efi_format.efi_nextents;
|
||||
|
||||
if (nexts > XFS_EFI_MAX_FAST_EXTENTS) {
|
||||
kmem_free(efip, sizeof(xfs_efi_log_item_t) +
|
||||
(nexts - 1) * sizeof(xfs_extent_t));
|
||||
kmem_free(efip);
|
||||
} else {
|
||||
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;
|
||||
|
||||
if (nexts > XFS_EFD_MAX_FAST_EXTENTS) {
|
||||
kmem_free(efdp, sizeof(xfs_efd_log_item_t) +
|
||||
(nexts - 1) * sizeof(xfs_extent_t));
|
||||
kmem_free(efdp);
|
||||
} else {
|
||||
kmem_zone_free(xfs_efd_zone, efdp);
|
||||
}
|
||||
|
@ -397,10 +397,12 @@ int
|
||||
xfs_filestream_init(void)
|
||||
{
|
||||
item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item");
|
||||
if (!item_zone)
|
||||
return -ENOMEM;
|
||||
#ifdef XFS_FILESTREAMS_TRACE
|
||||
xfs_filestreams_trace_buf = ktrace_alloc(XFS_FSTRM_KTRACE_SIZE, KM_SLEEP);
|
||||
#endif
|
||||
return item_zone ? 0 : -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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_SECTOR 0x0200 /* sector sizes >1BB */
|
||||
#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 */
|
||||
|
||||
|
||||
@ -371,6 +372,9 @@ typedef struct xfs_fsop_attrlist_handlereq {
|
||||
|
||||
typedef struct xfs_attr_multiop {
|
||||
__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;
|
||||
void __user *am_attrname;
|
||||
void __user *am_attrvalue;
|
||||
|
@ -95,6 +95,8 @@ xfs_fs_geometry(
|
||||
XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |
|
||||
(xfs_sb_version_hassector(&mp->m_sb) ?
|
||||
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_FSOP_GEOM_FLAGS_LAZYSB : 0) |
|
||||
(xfs_sb_version_hasattr2(&mp->m_sb) ?
|
||||
@ -625,7 +627,7 @@ xfs_fs_goingdown(
|
||||
xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
|
||||
thaw_bdev(sb->s_bdev, sb);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
|
||||
|
@ -1763,67 +1763,6 @@ xfs_itruncate_finish(
|
||||
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.
|
||||
* 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);
|
||||
}
|
||||
|
||||
kmem_free(ip_found, ninodes * sizeof(xfs_inode_t *));
|
||||
kmem_free(ip_found);
|
||||
xfs_put_perag(mp, pag);
|
||||
}
|
||||
|
||||
@ -2470,7 +2409,7 @@ xfs_iroot_realloc(
|
||||
(int)new_size);
|
||||
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_bytes = (int)new_size;
|
||||
ASSERT(ifp->if_broot_bytes <=
|
||||
@ -2514,7 +2453,7 @@ xfs_idata_realloc(
|
||||
|
||||
if (new_size == 0) {
|
||||
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;
|
||||
real_size = 0;
|
||||
@ -2529,7 +2468,7 @@ xfs_idata_realloc(
|
||||
ASSERT(ifp->if_real_bytes != 0);
|
||||
memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
|
||||
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;
|
||||
}
|
||||
real_size = 0;
|
||||
@ -2636,7 +2575,7 @@ xfs_idestroy_fork(
|
||||
|
||||
ifp = XFS_IFORK_PTR(ip, whichfork);
|
||||
if (ifp->if_broot != NULL) {
|
||||
kmem_free(ifp->if_broot, ifp->if_broot_bytes);
|
||||
kmem_free(ifp->if_broot);
|
||||
ifp->if_broot = NULL;
|
||||
}
|
||||
|
||||
@ -2650,7 +2589,7 @@ xfs_idestroy_fork(
|
||||
if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) &&
|
||||
(ifp->if_u1.if_data != NULL)) {
|
||||
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_real_bytes = 0;
|
||||
}
|
||||
@ -3058,7 +2997,7 @@ xfs_iflush_cluster(
|
||||
|
||||
out_free:
|
||||
read_unlock(&pag->pag_ici_lock);
|
||||
kmem_free(ilist, ilist_size);
|
||||
kmem_free(ilist);
|
||||
return 0;
|
||||
|
||||
|
||||
@ -3102,7 +3041,7 @@ cluster_corrupt_out:
|
||||
* Unlocks the flush lock
|
||||
*/
|
||||
xfs_iflush_abort(iq);
|
||||
kmem_free(ilist, ilist_size);
|
||||
kmem_free(ilist);
|
||||
return XFS_ERROR(EFSCORRUPTED);
|
||||
}
|
||||
|
||||
@ -3143,8 +3082,6 @@ xfs_iflush(
|
||||
* flush lock and do nothing.
|
||||
*/
|
||||
if (xfs_inode_clean(ip)) {
|
||||
ASSERT((iip != NULL) ?
|
||||
!(iip->ili_item.li_flags & XFS_LI_IN_AIL) : 1);
|
||||
xfs_ifunlock(ip);
|
||||
return 0;
|
||||
}
|
||||
@ -3836,7 +3773,7 @@ xfs_iext_add_indirect_multi(
|
||||
erp = xfs_iext_irec_new(ifp, erp_idx);
|
||||
}
|
||||
memmove(&erp->er_extbuf[i], nex2_ep, byte_diff);
|
||||
kmem_free(nex2_ep, byte_diff);
|
||||
kmem_free(nex2_ep);
|
||||
erp->er_extcount += 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,
|
||||
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_real_bytes = 0;
|
||||
}
|
||||
@ -4186,7 +4123,7 @@ xfs_iext_indirect_to_direct(
|
||||
ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
|
||||
|
||||
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_u1.if_extents = ep;
|
||||
ifp->if_bytes = size;
|
||||
@ -4212,7 +4149,7 @@ xfs_iext_destroy(
|
||||
}
|
||||
ifp->if_flags &= ~XFS_IFEXTIREC;
|
||||
} 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) {
|
||||
memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
|
||||
sizeof(xfs_bmbt_rec_t));
|
||||
@ -4483,7 +4420,7 @@ xfs_iext_irec_remove(
|
||||
if (erp->er_extbuf) {
|
||||
xfs_iext_irec_update_extoffs(ifp, erp_idx + 1,
|
||||
-erp->er_extcount);
|
||||
kmem_free(erp->er_extbuf, XFS_IEXT_BUFSZ);
|
||||
kmem_free(erp->er_extbuf);
|
||||
}
|
||||
/* Compact extent records */
|
||||
erp = ifp->if_u1.if_ext_irec;
|
||||
@ -4501,8 +4438,7 @@ xfs_iext_irec_remove(
|
||||
xfs_iext_realloc_indirect(ifp,
|
||||
nlists * sizeof(xfs_ext_irec_t));
|
||||
} else {
|
||||
kmem_free(ifp->if_u1.if_ext_irec,
|
||||
sizeof(xfs_ext_irec_t));
|
||||
kmem_free(ifp->if_u1.if_ext_irec);
|
||||
}
|
||||
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
|
||||
* xfs_iext_irec_remove.
|
||||
*/
|
||||
kmem_free(erp_next->er_extbuf, XFS_IEXT_BUFSZ);
|
||||
kmem_free(erp_next->er_extbuf);
|
||||
erp_next->er_extbuf = NULL;
|
||||
xfs_iext_irec_remove(ifp, erp_idx + 1);
|
||||
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) */
|
||||
|
||||
ASSERT(ifp->if_flags & XFS_IFEXTIREC);
|
||||
|
||||
nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
|
||||
erp = ifp->if_u1.if_ext_irec;
|
||||
ep = &erp->er_extbuf[erp->er_extcount];
|
||||
erp_next = erp + 1;
|
||||
ep_next = erp_next->er_extbuf;
|
||||
|
||||
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_diff = MIN(ext_avail, erp_next->er_extcount);
|
||||
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) {
|
||||
if (ext_avail) {
|
||||
|
||||
/*
|
||||
* Free page before removing extent record
|
||||
* so er_extoffs don't get modified in
|
||||
* xfs_iext_irec_remove.
|
||||
* Copy over as many as possible extent records into
|
||||
* the previous page.
|
||||
*/
|
||||
kmem_free(erp_next->er_extbuf,
|
||||
erp_next->er_extcount * sizeof(xfs_bmbt_rec_t));
|
||||
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;
|
||||
/* Update next page */
|
||||
} else {
|
||||
/* Move rest of page up to become next new page */
|
||||
memmove(erp_next->er_extbuf, ep_next,
|
||||
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));
|
||||
ext_diff = MIN(ext_avail, erp_next->er_extcount);
|
||||
memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t));
|
||||
erp->er_extcount += ext_diff;
|
||||
erp_next->er_extcount -= ext_diff;
|
||||
|
||||
/*
|
||||
* If the next irec is empty now we can simply
|
||||
* remove it.
|
||||
*/
|
||||
if (erp_next->er_extcount == 0) {
|
||||
/*
|
||||
* Free page before removing extent record
|
||||
* so er_extoffs don't get modified in
|
||||
* xfs_iext_irec_remove.
|
||||
*/
|
||||
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) {
|
||||
erp_idx++;
|
||||
if (erp_idx < nlists)
|
||||
|
@ -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 *,
|
||||
xfs_fsize_t, int, int);
|
||||
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(xfs_inode_t *);
|
||||
|
@ -686,7 +686,7 @@ xfs_inode_item_unlock(
|
||||
ASSERT(ip->i_d.di_nextents > 0);
|
||||
ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT);
|
||||
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;
|
||||
}
|
||||
if (iip->ili_aextents_buf != NULL) {
|
||||
@ -694,7 +694,7 @@ xfs_inode_item_unlock(
|
||||
ASSERT(ip->i_d.di_anextents > 0);
|
||||
ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -957,8 +957,7 @@ xfs_inode_item_destroy(
|
||||
{
|
||||
#ifdef XFS_TRANS_DEBUG
|
||||
if (ip->i_itemp->ili_root_size != 0) {
|
||||
kmem_free(ip->i_itemp->ili_orig_root,
|
||||
ip->i_itemp->ili_root_size);
|
||||
kmem_free(ip->i_itemp->ili_orig_root);
|
||||
}
|
||||
#endif
|
||||
kmem_zone_free(xfs_ili_zone, ip->i_itemp);
|
||||
|
@ -889,6 +889,16 @@ xfs_iomap_write_unwritten(
|
||||
count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
|
||||
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;
|
||||
|
||||
do {
|
||||
|
@ -257,7 +257,7 @@ xfs_bulkstat_one(
|
||||
*ubused = error;
|
||||
|
||||
out_free:
|
||||
kmem_free(buf, sizeof(*buf));
|
||||
kmem_free(buf);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -708,7 +708,7 @@ xfs_bulkstat(
|
||||
/*
|
||||
* Done, we're either out of filesystem or space to put the data.
|
||||
*/
|
||||
kmem_free(irbuf, irbsize);
|
||||
kmem_free(irbuf);
|
||||
*ubcountp = ubelem;
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
kmem_free(buffer, bcount * sizeof(*buffer));
|
||||
kmem_free(buffer);
|
||||
if (cur)
|
||||
xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR :
|
||||
XFS_BTREE_NOERROR));
|
||||
|
@ -226,20 +226,24 @@ xlog_grant_sub_space(struct log *log, int bytes)
|
||||
static void
|
||||
xlog_grant_add_space_write(struct log *log, int bytes)
|
||||
{
|
||||
log->l_grant_write_bytes += bytes;
|
||||
if (log->l_grant_write_bytes > log->l_logsize) {
|
||||
log->l_grant_write_bytes -= log->l_logsize;
|
||||
int tmp = log->l_logsize - log->l_grant_write_bytes;
|
||||
if (tmp > bytes)
|
||||
log->l_grant_write_bytes += bytes;
|
||||
else {
|
||||
log->l_grant_write_cycle++;
|
||||
log->l_grant_write_bytes = bytes - tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xlog_grant_add_space_reserve(struct log *log, int bytes)
|
||||
{
|
||||
log->l_grant_reserve_bytes += bytes;
|
||||
if (log->l_grant_reserve_bytes > log->l_logsize) {
|
||||
log->l_grant_reserve_bytes -= log->l_logsize;
|
||||
int tmp = log->l_logsize - log->l_grant_reserve_bytes;
|
||||
if (tmp > bytes)
|
||||
log->l_grant_reserve_bytes += bytes;
|
||||
else {
|
||||
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_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 */
|
||||
ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0);
|
||||
@ -1570,10 +1574,9 @@ xlog_dealloc_log(xlog_t *log)
|
||||
}
|
||||
#endif
|
||||
next_iclog = iclog->ic_next;
|
||||
kmem_free(iclog, sizeof(xlog_in_core_t));
|
||||
kmem_free(iclog);
|
||||
iclog = next_iclog;
|
||||
}
|
||||
freesema(&log->l_flushsema);
|
||||
spinlock_destroy(&log->l_icloglock);
|
||||
spinlock_destroy(&log->l_grant_lock);
|
||||
|
||||
@ -1587,7 +1590,7 @@ xlog_dealloc_log(xlog_t *log)
|
||||
}
|
||||
#endif
|
||||
log->l_mp->m_log = NULL;
|
||||
kmem_free(log, sizeof(xlog_t));
|
||||
kmem_free(log);
|
||||
} /* xlog_dealloc_log */
|
||||
|
||||
/*
|
||||
@ -2097,6 +2100,7 @@ xlog_state_do_callback(
|
||||
int funcdidcallbacks; /* flag: function did callbacks */
|
||||
int repeats; /* for issuing console warnings if
|
||||
* looping too many times */
|
||||
int wake = 0;
|
||||
|
||||
spin_lock(&log->l_icloglock);
|
||||
first_iclog = iclog = log->l_iclog;
|
||||
@ -2278,15 +2282,13 @@ xlog_state_do_callback(
|
||||
}
|
||||
#endif
|
||||
|
||||
flushcnt = 0;
|
||||
if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) {
|
||||
flushcnt = log->l_flushcnt;
|
||||
log->l_flushcnt = 0;
|
||||
}
|
||||
if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR))
|
||||
wake = 1;
|
||||
spin_unlock(&log->l_icloglock);
|
||||
while (flushcnt--)
|
||||
vsema(&log->l_flushsema);
|
||||
} /* xlog_state_do_callback */
|
||||
|
||||
if (wake)
|
||||
sv_broadcast(&log->l_flush_wait);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -2384,16 +2386,15 @@ restart:
|
||||
}
|
||||
|
||||
iclog = log->l_iclog;
|
||||
if (! (iclog->ic_state == XLOG_STATE_ACTIVE)) {
|
||||
log->l_flushcnt++;
|
||||
spin_unlock(&log->l_icloglock);
|
||||
if (iclog->ic_state != XLOG_STATE_ACTIVE) {
|
||||
xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH);
|
||||
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;
|
||||
}
|
||||
ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE);
|
||||
|
||||
head = &iclog->ic_header;
|
||||
|
||||
atomic_inc(&iclog->ic_refcnt); /* prevents sync */
|
||||
|
@ -423,10 +423,8 @@ typedef struct log {
|
||||
int l_logBBsize; /* size of log in BB chunks */
|
||||
|
||||
/* The following block of fields are changed while holding icloglock */
|
||||
sema_t l_flushsema ____cacheline_aligned_in_smp;
|
||||
/* iclog flushing semaphore */
|
||||
int l_flushcnt; /* # of procs waiting on this
|
||||
* sema */
|
||||
sv_t l_flush_wait ____cacheline_aligned_in_smp;
|
||||
/* waiting for iclog flush */
|
||||
int l_covered_state;/* state of "covering disk
|
||||
* log entries" */
|
||||
xlog_in_core_t *l_iclog; /* head log queue */
|
||||
|
@ -1715,8 +1715,7 @@ xlog_check_buffer_cancelled(
|
||||
} else {
|
||||
prevp->bc_next = bcp->bc_next;
|
||||
}
|
||||
kmem_free(bcp,
|
||||
sizeof(xfs_buf_cancel_t));
|
||||
kmem_free(bcp);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
@ -2519,7 +2518,7 @@ write_inode_buffer:
|
||||
|
||||
error:
|
||||
if (need_free)
|
||||
kmem_free(in_f, sizeof(*in_f));
|
||||
kmem_free(in_f);
|
||||
return XFS_ERROR(error);
|
||||
}
|
||||
|
||||
@ -2830,16 +2829,14 @@ xlog_recover_free_trans(
|
||||
item = item->ri_next;
|
||||
/* Free the regions in the item. */
|
||||
for (i = 0; i < free_item->ri_cnt; i++) {
|
||||
kmem_free(free_item->ri_buf[i].i_addr,
|
||||
free_item->ri_buf[i].i_len);
|
||||
kmem_free(free_item->ri_buf[i].i_addr);
|
||||
}
|
||||
/* Free the item itself */
|
||||
kmem_free(free_item->ri_buf,
|
||||
(free_item->ri_total * sizeof(xfs_log_iovec_t)));
|
||||
kmem_free(free_item, sizeof(xlog_recover_item_t));
|
||||
kmem_free(free_item->ri_buf);
|
||||
kmem_free(free_item);
|
||||
} while (first_item != item);
|
||||
/* Free the transaction recover structure */
|
||||
kmem_free(trans, sizeof(xlog_recover_t));
|
||||
kmem_free(trans);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
@ -3786,8 +3783,7 @@ xlog_do_log_recovery(
|
||||
error = xlog_do_recovery_pass(log, head_blk, tail_blk,
|
||||
XLOG_RECOVER_PASS1);
|
||||
if (error != 0) {
|
||||
kmem_free(log->l_buf_cancel_table,
|
||||
XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*));
|
||||
kmem_free(log->l_buf_cancel_table);
|
||||
log->l_buf_cancel_table = NULL;
|
||||
return error;
|
||||
}
|
||||
@ -3806,8 +3802,7 @@ xlog_do_log_recovery(
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
kmem_free(log->l_buf_cancel_table,
|
||||
XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*));
|
||||
kmem_free(log->l_buf_cancel_table);
|
||||
log->l_buf_cancel_table = NULL;
|
||||
|
||||
return error;
|
||||
|
@ -47,12 +47,10 @@
|
||||
|
||||
STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_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 *);
|
||||
|
||||
|
||||
#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,
|
||||
int);
|
||||
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
|
||||
|
||||
#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_locked(mp, a, b) 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 }
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
* the structure was initially zeroed, so we can tell which fields got
|
||||
* initialized.
|
||||
*/
|
||||
void
|
||||
STATIC void
|
||||
xfs_mount_free(
|
||||
xfs_mount_t *mp)
|
||||
{
|
||||
@ -161,11 +136,8 @@ xfs_mount_free(
|
||||
|
||||
for (agno = 0; agno < mp->m_maxagi; agno++)
|
||||
if (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,
|
||||
sizeof(xfs_perag_t) * mp->m_sb.sb_agcount);
|
||||
kmem_free(mp->m_perag[agno].pagb_list);
|
||||
kmem_free(mp->m_perag);
|
||||
}
|
||||
|
||||
spinlock_destroy(&mp->m_ail_lock);
|
||||
@ -176,13 +148,11 @@ xfs_mount_free(
|
||||
XFS_QM_DONE(mp);
|
||||
|
||||
if (mp->m_fsname != NULL)
|
||||
kmem_free(mp->m_fsname, mp->m_fsname_len);
|
||||
kmem_free(mp->m_fsname);
|
||||
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)
|
||||
kmem_free(mp->m_logname, strlen(mp->m_logname) + 1);
|
||||
|
||||
xfs_icsb_destroy_counters(mp);
|
||||
kmem_free(mp->m_logname);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -288,6 +258,19 @@ xfs_mount_validate_sb(
|
||||
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) ||
|
||||
xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
|
||||
xfs_fs_mount_cmn_err(flags,
|
||||
@ -309,19 +292,6 @@ xfs_mount_validate_sb(
|
||||
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;
|
||||
}
|
||||
|
||||
@ -994,9 +964,19 @@ xfs_mountfs(
|
||||
* Re-check for ATTR2 in case it was found in bad_features2
|
||||
* 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;
|
||||
}
|
||||
|
||||
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:
|
||||
for (agno = 0; agno < sbp->sb_agcount; agno++)
|
||||
if (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, sbp->sb_agcount * sizeof(xfs_perag_t));
|
||||
kmem_free(mp->m_perag[agno].pagb_list);
|
||||
kmem_free(mp->m_perag);
|
||||
mp->m_perag = NULL;
|
||||
/* FALLTHROUGH */
|
||||
error1:
|
||||
if (uuid_mounted)
|
||||
xfs_uuid_unmount(mp);
|
||||
xfs_freesb(mp);
|
||||
uuid_table_remove(&mp->m_sb.sb_uuid);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1274,7 +1252,7 @@ xfs_mountfs(
|
||||
* log and makes sure that incore structures are freed.
|
||||
*/
|
||||
int
|
||||
xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
|
||||
xfs_unmountfs(xfs_mount_t *mp)
|
||||
{
|
||||
__uint64_t resblks;
|
||||
int error = 0;
|
||||
@ -1341,9 +1319,8 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
|
||||
*/
|
||||
ASSERT(mp->m_inodes == NULL);
|
||||
|
||||
xfs_unmountfs_close(mp, cr);
|
||||
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)
|
||||
xfs_errortag_clearall(mp, 0);
|
||||
@ -1352,16 +1329,6 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
|
||||
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
|
||||
xfs_unmountfs_wait(xfs_mount_t *mp)
|
||||
{
|
||||
@ -1904,16 +1871,6 @@ xfs_uuid_mount(
|
||||
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
|
||||
* be altered by the mount options, as well as any potential sb_features2
|
||||
@ -1928,7 +1885,8 @@ xfs_mount_log_sb(
|
||||
int error;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
STATIC void
|
||||
void
|
||||
xfs_icsb_destroy_counters(
|
||||
xfs_mount_t *mp)
|
||||
{
|
||||
|
@ -61,6 +61,7 @@ struct xfs_bmap_free;
|
||||
struct xfs_extdelta;
|
||||
struct xfs_swapext;
|
||||
struct xfs_mru_cache;
|
||||
struct xfs_nameops;
|
||||
|
||||
/*
|
||||
* 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 void xfs_icsb_reinit_counters(struct xfs_mount *);
|
||||
extern void xfs_icsb_destroy_counters(struct xfs_mount *);
|
||||
extern void xfs_icsb_sync_counters(struct xfs_mount *, int);
|
||||
extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int);
|
||||
|
||||
#else
|
||||
#define xfs_icsb_init_counters(mp) (0)
|
||||
#define xfs_icsb_reinit_counters(mp) do { } while (0)
|
||||
#define xfs_icsb_init_counters(mp) (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_locked(mp, flags) do { } while (0)
|
||||
#endif
|
||||
@ -313,6 +316,7 @@ typedef struct xfs_mount {
|
||||
__uint8_t m_inode_quiesce;/* call quiesce on new inodes.
|
||||
field governed by m_ilock */
|
||||
__uint8_t m_sectbb_log; /* sectlog - BBSHIFT */
|
||||
const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */
|
||||
int m_dirblksize; /* directory block sz--bytes */
|
||||
int m_dirblkfsbs; /* directory block sz--fsbs */
|
||||
xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */
|
||||
@ -378,6 +382,7 @@ typedef struct xfs_mount {
|
||||
counters */
|
||||
#define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams
|
||||
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_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 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 void xfs_mountfs_check_barriers(xfs_mount_t *mp);
|
||||
|
||||
extern int xfs_unmountfs(xfs_mount_t *, struct cred *);
|
||||
extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *);
|
||||
extern int xfs_unmountfs(xfs_mount_t *);
|
||||
extern int xfs_unmountfs_writesb(xfs_mount_t *);
|
||||
extern int xfs_unmount_flush(xfs_mount_t *, int);
|
||||
extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
|
||||
@ -544,9 +546,6 @@ extern void xfs_qmops_put(struct xfs_mount *);
|
||||
|
||||
extern struct xfs_dmops xfs_dmcore_xfs;
|
||||
|
||||
extern int xfs_init(void);
|
||||
extern void xfs_cleanup(void);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __XFS_MOUNT_H__ */
|
||||
|
@ -307,15 +307,18 @@ xfs_mru_cache_init(void)
|
||||
xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t),
|
||||
"xfs_mru_cache_elem");
|
||||
if (!xfs_mru_elem_zone)
|
||||
return ENOMEM;
|
||||
goto out;
|
||||
|
||||
xfs_mru_reap_wq = create_singlethread_workqueue("xfs_mru_cache");
|
||||
if (!xfs_mru_reap_wq) {
|
||||
kmem_zone_destroy(xfs_mru_elem_zone);
|
||||
return ENOMEM;
|
||||
}
|
||||
if (!xfs_mru_reap_wq)
|
||||
goto out_destroy_mru_elem_zone;
|
||||
|
||||
return 0;
|
||||
|
||||
out_destroy_mru_elem_zone:
|
||||
kmem_zone_destroy(xfs_mru_elem_zone);
|
||||
out:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void
|
||||
@ -382,9 +385,9 @@ xfs_mru_cache_create(
|
||||
|
||||
exit:
|
||||
if (err && mru && mru->lists)
|
||||
kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists));
|
||||
kmem_free(mru->lists);
|
||||
if (err && mru)
|
||||
kmem_free(mru, sizeof(*mru));
|
||||
kmem_free(mru);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -424,8 +427,8 @@ xfs_mru_cache_destroy(
|
||||
|
||||
xfs_mru_cache_flush(mru);
|
||||
|
||||
kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists));
|
||||
kmem_free(mru, sizeof(*mru));
|
||||
kmem_free(mru->lists);
|
||||
kmem_free(mru);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -336,21 +336,17 @@ xfs_rename(
|
||||
ASSERT(error != EEXIST);
|
||||
if (error)
|
||||
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
|
||||
* renaming a directory, either within one parent when
|
||||
|
@ -2062,7 +2062,7 @@ xfs_growfs_rt(
|
||||
/*
|
||||
* Free the fake mp structure.
|
||||
*/
|
||||
kmem_free(nmp, sizeof(*nmp));
|
||||
kmem_free(nmp);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -46,10 +46,12 @@ struct xfs_mount;
|
||||
#define XFS_SB_VERSION_SECTORBIT 0x0800
|
||||
#define XFS_SB_VERSION_EXTFLGBIT 0x1000
|
||||
#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_OKSASHFBITS \
|
||||
(XFS_SB_VERSION_EXTFLGBIT | \
|
||||
XFS_SB_VERSION_DIRV2BIT)
|
||||
XFS_SB_VERSION_DIRV2BIT | \
|
||||
XFS_SB_VERSION_BORGBIT)
|
||||
#define XFS_SB_VERSION_OKREALFBITS \
|
||||
(XFS_SB_VERSION_ATTRBIT | \
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)));
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -889,7 +889,7 @@ shut_us_down:
|
||||
|
||||
tp->t_commit_lsn = commit_lsn;
|
||||
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));
|
||||
xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag);
|
||||
next_licp = licp->lic_next;
|
||||
kmem_free(licp, sizeof(xfs_log_item_chunk_t));
|
||||
kmem_free(licp);
|
||||
licp = next_licp;
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ xfs_trans_inode_broot_debug(
|
||||
iip = ip->i_itemp;
|
||||
if (iip->ili_root_size != 0) {
|
||||
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_orig_root = NULL;
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
|
||||
licpp = &((*licpp)->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;
|
||||
}
|
||||
}
|
||||
@ -314,7 +314,7 @@ xfs_trans_free_items(
|
||||
ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
|
||||
(void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN);
|
||||
next_licp = licp->lic_next;
|
||||
kmem_free(licp, sizeof(xfs_log_item_chunk_t));
|
||||
kmem_free(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;
|
||||
if (XFS_LIC_ARE_ALL_FREE(licp)) {
|
||||
*licpp = next_licp;
|
||||
kmem_free(licp, sizeof(xfs_log_item_chunk_t));
|
||||
kmem_free(licp);
|
||||
freed -= XFS_LIC_NUM_SLOTS;
|
||||
} else {
|
||||
licpp = &(licp->lic_next);
|
||||
@ -530,7 +530,7 @@ xfs_trans_free_busy(xfs_trans_t *tp)
|
||||
lbcp = tp->t_busy.lbc_next;
|
||||
while (lbcp != NULL) {
|
||||
lbcq = lbcp->lbc_next;
|
||||
kmem_free(lbcp, sizeof(xfs_log_busy_chunk_t));
|
||||
kmem_free(lbcp);
|
||||
lbcp = lbcq;
|
||||
}
|
||||
|
||||
|
@ -58,586 +58,6 @@
|
||||
#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
|
||||
xfs_quiesce_fs(
|
||||
xfs_mount_t *mp)
|
||||
@ -694,30 +114,6 @@ xfs_attr_quiesce(
|
||||
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
|
||||
* 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)) {
|
||||
XFS_MOUNT_IUNLOCK(mp);
|
||||
kmem_free(ipointer, sizeof(xfs_iptr_t));
|
||||
kmem_free(ipointer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1194,7 +590,7 @@ xfs_sync_inodes(
|
||||
}
|
||||
XFS_MOUNT_IUNLOCK(mp);
|
||||
ASSERT(ipointer_in == B_FALSE);
|
||||
kmem_free(ipointer, sizeof(xfs_iptr_t));
|
||||
kmem_free(ipointer);
|
||||
return XFS_ERROR(error);
|
||||
}
|
||||
|
||||
@ -1224,7 +620,7 @@ xfs_sync_inodes(
|
||||
|
||||
ASSERT(ipointer_in == B_FALSE);
|
||||
|
||||
kmem_free(ipointer, sizeof(xfs_iptr_t));
|
||||
kmem_free(ipointer);
|
||||
return XFS_ERROR(last_error);
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,6 @@ struct kstatfs;
|
||||
struct xfs_mount;
|
||||
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);
|
||||
void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname,
|
||||
int lnnum);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,9 +2,9 @@
|
||||
#define _XFS_VNODEOPS_H 1
|
||||
|
||||
struct attrlist_cursor_kern;
|
||||
struct bhv_vattr;
|
||||
struct cred;
|
||||
struct file;
|
||||
struct iattr;
|
||||
struct inode;
|
||||
struct iovec;
|
||||
struct kiocb;
|
||||
@ -15,14 +15,18 @@ struct xfs_iomap;
|
||||
|
||||
|
||||
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);
|
||||
#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_fsync(struct xfs_inode *ip);
|
||||
int xfs_release(struct xfs_inode *ip);
|
||||
int xfs_inactive(struct xfs_inode *ip);
|
||||
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,
|
||||
xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp);
|
||||
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);
|
||||
int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name,
|
||||
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,
|
||||
xfs_off_t *offset, filldir_t filldir);
|
||||
int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
|
||||
|
@ -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_anon(struct inode *);
|
||||
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_parent(struct dentry *);
|
||||
extern void shrink_dcache_for_umount(struct super_block *);
|
||||
|
Loading…
Reference in New Issue
Block a user