Merge branch 'xfs-misc-fixes-for-4.4-2' into for-next

This commit is contained in:
Dave Chinner 2015-11-03 13:27:58 +11:00
commit 2da5c4b05a
14 changed files with 101 additions and 16 deletions

View File

@ -1495,9 +1495,13 @@ struct xfs_acl {
sizeof(struct xfs_acl_entry) \
: 25)
#define XFS_ACL_MAX_SIZE(mp) \
#define XFS_ACL_SIZE(cnt) \
(sizeof(struct xfs_acl) + \
sizeof(struct xfs_acl_entry) * XFS_ACL_MAX_ENTRIES((mp)))
sizeof(struct xfs_acl_entry) * cnt)
#define XFS_ACL_MAX_SIZE(mp) \
XFS_ACL_SIZE(XFS_ACL_MAX_ENTRIES((mp)))
/* On-disk XFS extended attribute names */
#define SGI_ACL_FILE "SGI_ACL_FILE"

View File

@ -37,16 +37,19 @@
STATIC struct posix_acl *
xfs_acl_from_disk(
struct xfs_acl *aclp,
int max_entries)
const struct xfs_acl *aclp,
int len,
int max_entries)
{
struct posix_acl_entry *acl_e;
struct posix_acl *acl;
struct xfs_acl_entry *ace;
const struct xfs_acl_entry *ace;
unsigned int count, i;
if (len < sizeof(*aclp))
return ERR_PTR(-EFSCORRUPTED);
count = be32_to_cpu(aclp->acl_cnt);
if (count > max_entries)
if (count > max_entries || XFS_ACL_SIZE(count) != len)
return ERR_PTR(-EFSCORRUPTED);
acl = posix_acl_alloc(count, GFP_KERNEL);
@ -163,7 +166,7 @@ xfs_get_acl(struct inode *inode, int type)
goto out;
}
acl = xfs_acl_from_disk(xfs_acl, XFS_ACL_MAX_ENTRIES(ip->i_mount));
acl = xfs_acl_from_disk(xfs_acl, len, XFS_ACL_MAX_ENTRIES(ip->i_mount));
if (IS_ERR(acl))
goto out;

View File

@ -36,4 +36,7 @@ static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
# define posix_acl_access_exists(inode) 0
# define posix_acl_default_exists(inode) 0
#endif /* CONFIG_XFS_POSIX_ACL */
extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags);
#endif /* __XFS_ACL_H__ */

View File

@ -242,19 +242,30 @@ xfs_file_fsync(
}
/*
* All metadata updates are logged, which means that we just have
* to flush the log up to the latest LSN that touched the inode.
* All metadata updates are logged, which means that we just have to
* flush the log up to the latest LSN that touched the inode. If we have
* concurrent fsync/fdatasync() calls, we need them to all block on the
* log force before we clear the ili_fsync_fields field. This ensures
* that we don't get a racing sync operation that does not wait for the
* metadata to hit the journal before returning. If we race with
* clearing the ili_fsync_fields, then all that will happen is the log
* force will do nothing as the lsn will already be on disk. We can't
* race with setting ili_fsync_fields because that is done under
* XFS_ILOCK_EXCL, and that can't happen because we hold the lock shared
* until after the ili_fsync_fields is cleared.
*/
xfs_ilock(ip, XFS_ILOCK_SHARED);
if (xfs_ipincount(ip)) {
if (!datasync ||
(ip->i_itemp->ili_fields & ~XFS_ILOG_TIMESTAMP))
(ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP))
lsn = ip->i_itemp->ili_last_lsn;
}
xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (lsn)
if (lsn) {
error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);
ip->i_itemp->ili_fsync_fields = 0;
}
xfs_iunlock(ip, XFS_ILOCK_SHARED);
/*
* If we only have a single device, and the log force about was

View File

@ -2365,6 +2365,7 @@ retry:
iip->ili_last_fields = iip->ili_fields;
iip->ili_fields = 0;
iip->ili_fsync_fields = 0;
iip->ili_logged = 1;
xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
&iip->ili_item.li_lsn);
@ -3560,6 +3561,7 @@ xfs_iflush_int(
*/
iip->ili_last_fields = iip->ili_fields;
iip->ili_fields = 0;
iip->ili_fsync_fields = 0;
iip->ili_logged = 1;
xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,

View File

@ -719,6 +719,7 @@ xfs_iflush_abort(
* attempted.
*/
iip->ili_fields = 0;
iip->ili_fsync_fields = 0;
}
/*
* Release the inode's flush lock since we're done with it.

View File

@ -34,6 +34,7 @@ typedef struct xfs_inode_log_item {
unsigned short ili_logged; /* flushed logged data */
unsigned int ili_last_fields; /* fields when flushed */
unsigned int ili_fields; /* fields to be logged */
unsigned int ili_fsync_fields; /* logged since last fsync */
} xfs_inode_log_item_t;
static inline int xfs_inode_clean(xfs_inode_t *ip)

View File

@ -40,6 +40,7 @@
#include "xfs_symlink.h"
#include "xfs_trans.h"
#include "xfs_pnfs.h"
#include "xfs_acl.h"
#include <linux/capability.h>
#include <linux/dcache.h>
@ -482,6 +483,7 @@ xfs_attrmulti_attr_set(
__uint32_t flags)
{
unsigned char *kbuf;
int error;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
@ -492,7 +494,11 @@ xfs_attrmulti_attr_set(
if (IS_ERR(kbuf))
return PTR_ERR(kbuf);
return xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
if (!error)
xfs_forget_acl(inode, name, flags);
kfree(kbuf);
return error;
}
int
@ -501,9 +507,14 @@ xfs_attrmulti_attr_remove(
unsigned char *name,
__uint32_t flags)
{
int error;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
return xfs_attr_remove(XFS_I(inode), name, flags);
error = xfs_attr_remove(XFS_I(inode), name, flags);
if (!error)
xfs_forget_acl(inode, name, flags);
return error;
}
STATIC int

View File

@ -47,6 +47,16 @@ static DEFINE_MUTEX(xfs_uuid_table_mutex);
static int xfs_uuid_table_size;
static uuid_t *xfs_uuid_table;
void
xfs_uuid_table_free(void)
{
if (xfs_uuid_table_size == 0)
return;
kmem_free(xfs_uuid_table);
xfs_uuid_table = NULL;
xfs_uuid_table_size = 0;
}
/*
* See if the UUID is unique among mounted XFS filesystems.
* Mount fails if UUID is nil or a FS with the same UUID is already mounted.

View File

@ -313,6 +313,7 @@ typedef struct xfs_perag {
int pagb_count; /* pagb slots in use */
} xfs_perag_t;
extern void xfs_uuid_table_free(void);
extern int xfs_log_sbcount(xfs_mount_t *);
extern __uint64_t xfs_default_resblks(xfs_mount_t *mp);
extern int xfs_mountfs(xfs_mount_t *mp);

View File

@ -1925,6 +1925,7 @@ exit_xfs_fs(void)
xfs_mru_cache_uninit();
xfs_destroy_workqueues();
xfs_destroy_zones();
xfs_uuid_table_free();
}
module_init(init_xfs_fs);

View File

@ -497,6 +497,7 @@ xfsaild(
long tout = 0; /* milliseconds */
current->flags |= PF_MEMALLOC;
set_freezable();
while (!kthread_should_stop()) {
if (tout && tout <= 20)

View File

@ -107,6 +107,15 @@ xfs_trans_log_inode(
ASSERT(ip->i_itemp != NULL);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
/*
* Record the specific change for fdatasync optimisation. This
* allows fdatasync to skip log forces for inodes that are only
* timestamp dirty. We do this before the change count so that
* the core being logged in this case does not impact on fdatasync
* behaviour.
*/
ip->i_itemp->ili_fsync_fields |= flags;
/*
* First time we log the inode in a transaction, bump the inode change
* counter if it is configured for this to occur. We don't use

View File

@ -53,11 +53,34 @@ xfs_xattr_get(struct dentry *dentry, const char *name,
return asize;
}
void
xfs_forget_acl(
struct inode *inode,
const char *name,
int xflags)
{
/*
* Invalidate any cached ACLs if the user has bypassed the ACL
* interface. We don't validate the content whatsoever so it is caller
* responsibility to provide data in valid format and ensure i_mode is
* consistent.
*/
if (xflags & ATTR_ROOT) {
#ifdef CONFIG_XFS_POSIX_ACL
if (!strcmp(name, SGI_ACL_FILE))
forget_cached_acl(inode, ACL_TYPE_ACCESS);
else if (!strcmp(name, SGI_ACL_DEFAULT))
forget_cached_acl(inode, ACL_TYPE_DEFAULT);
#endif
}
}
static int
xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags, int xflags)
{
struct xfs_inode *ip = XFS_I(d_inode(dentry));
struct xfs_inode *ip = XFS_I(d_inode(dentry));
int error;
if (strcmp(name, "") == 0)
return -EINVAL;
@ -70,8 +93,12 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
if (!value)
return xfs_attr_remove(ip, (unsigned char *)name, xflags);
return xfs_attr_set(ip, (unsigned char *)name,
error = xfs_attr_set(ip, (unsigned char *)name,
(void *)value, size, xflags);
if (!error)
xfs_forget_acl(d_inode(dentry), name, xflags);
return error;
}
static const struct xattr_handler xfs_xattr_user_handler = {