Commit 2da5c4b0 authored by Dave Chinner's avatar Dave Chinner

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

parents fcd8a399 fc0561ce
...@@ -1495,9 +1495,13 @@ struct xfs_acl { ...@@ -1495,9 +1495,13 @@ struct xfs_acl {
sizeof(struct xfs_acl_entry) \ sizeof(struct xfs_acl_entry) \
: 25) : 25)
#define XFS_ACL_MAX_SIZE(mp) \ #define XFS_ACL_SIZE(cnt) \
(sizeof(struct xfs_acl) + \ (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 */ /* On-disk XFS extended attribute names */
#define SGI_ACL_FILE "SGI_ACL_FILE" #define SGI_ACL_FILE "SGI_ACL_FILE"
......
...@@ -37,16 +37,19 @@ ...@@ -37,16 +37,19 @@
STATIC struct posix_acl * STATIC struct posix_acl *
xfs_acl_from_disk( xfs_acl_from_disk(
struct xfs_acl *aclp, const struct xfs_acl *aclp,
int len,
int max_entries) int max_entries)
{ {
struct posix_acl_entry *acl_e; struct posix_acl_entry *acl_e;
struct posix_acl *acl; struct posix_acl *acl;
struct xfs_acl_entry *ace; const struct xfs_acl_entry *ace;
unsigned int count, i; unsigned int count, i;
if (len < sizeof(*aclp))
return ERR_PTR(-EFSCORRUPTED);
count = be32_to_cpu(aclp->acl_cnt); count = be32_to_cpu(aclp->acl_cnt);
if (count > max_entries) if (count > max_entries || XFS_ACL_SIZE(count) != len)
return ERR_PTR(-EFSCORRUPTED); return ERR_PTR(-EFSCORRUPTED);
acl = posix_acl_alloc(count, GFP_KERNEL); acl = posix_acl_alloc(count, GFP_KERNEL);
...@@ -163,7 +166,7 @@ xfs_get_acl(struct inode *inode, int type) ...@@ -163,7 +166,7 @@ xfs_get_acl(struct inode *inode, int type)
goto out; 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)) if (IS_ERR(acl))
goto out; goto out;
......
...@@ -36,4 +36,7 @@ static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type) ...@@ -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_access_exists(inode) 0
# define posix_acl_default_exists(inode) 0 # define posix_acl_default_exists(inode) 0
#endif /* CONFIG_XFS_POSIX_ACL */ #endif /* CONFIG_XFS_POSIX_ACL */
extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags);
#endif /* __XFS_ACL_H__ */ #endif /* __XFS_ACL_H__ */
...@@ -242,19 +242,30 @@ xfs_file_fsync( ...@@ -242,19 +242,30 @@ xfs_file_fsync(
} }
/* /*
* All metadata updates are logged, which means that we just have * All metadata updates are logged, which means that we just have to
* to flush the log up to the latest LSN that touched the inode. * 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); xfs_ilock(ip, XFS_ILOCK_SHARED);
if (xfs_ipincount(ip)) { if (xfs_ipincount(ip)) {
if (!datasync || 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; 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); 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 * If we only have a single device, and the log force about was
......
...@@ -2365,6 +2365,7 @@ xfs_ifree_cluster( ...@@ -2365,6 +2365,7 @@ xfs_ifree_cluster(
iip->ili_last_fields = iip->ili_fields; iip->ili_last_fields = iip->ili_fields;
iip->ili_fields = 0; iip->ili_fields = 0;
iip->ili_fsync_fields = 0;
iip->ili_logged = 1; iip->ili_logged = 1;
xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
&iip->ili_item.li_lsn); &iip->ili_item.li_lsn);
...@@ -3560,6 +3561,7 @@ xfs_iflush_int( ...@@ -3560,6 +3561,7 @@ xfs_iflush_int(
*/ */
iip->ili_last_fields = iip->ili_fields; iip->ili_last_fields = iip->ili_fields;
iip->ili_fields = 0; iip->ili_fields = 0;
iip->ili_fsync_fields = 0;
iip->ili_logged = 1; iip->ili_logged = 1;
xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
......
...@@ -719,6 +719,7 @@ xfs_iflush_abort( ...@@ -719,6 +719,7 @@ xfs_iflush_abort(
* attempted. * attempted.
*/ */
iip->ili_fields = 0; iip->ili_fields = 0;
iip->ili_fsync_fields = 0;
} }
/* /*
* Release the inode's flush lock since we're done with it. * Release the inode's flush lock since we're done with it.
......
...@@ -34,6 +34,7 @@ typedef struct xfs_inode_log_item { ...@@ -34,6 +34,7 @@ typedef struct xfs_inode_log_item {
unsigned short ili_logged; /* flushed logged data */ unsigned short ili_logged; /* flushed logged data */
unsigned int ili_last_fields; /* fields when flushed */ unsigned int ili_last_fields; /* fields when flushed */
unsigned int ili_fields; /* fields to be logged */ unsigned int ili_fields; /* fields to be logged */
unsigned int ili_fsync_fields; /* logged since last fsync */
} xfs_inode_log_item_t; } xfs_inode_log_item_t;
static inline int xfs_inode_clean(xfs_inode_t *ip) static inline int xfs_inode_clean(xfs_inode_t *ip)
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "xfs_symlink.h" #include "xfs_symlink.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_pnfs.h" #include "xfs_pnfs.h"
#include "xfs_acl.h"
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/dcache.h> #include <linux/dcache.h>
...@@ -482,6 +483,7 @@ xfs_attrmulti_attr_set( ...@@ -482,6 +483,7 @@ xfs_attrmulti_attr_set(
__uint32_t flags) __uint32_t flags)
{ {
unsigned char *kbuf; unsigned char *kbuf;
int error;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM; return -EPERM;
...@@ -492,7 +494,11 @@ xfs_attrmulti_attr_set( ...@@ -492,7 +494,11 @@ xfs_attrmulti_attr_set(
if (IS_ERR(kbuf)) if (IS_ERR(kbuf))
return PTR_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 int
...@@ -501,9 +507,14 @@ xfs_attrmulti_attr_remove( ...@@ -501,9 +507,14 @@ xfs_attrmulti_attr_remove(
unsigned char *name, unsigned char *name,
__uint32_t flags) __uint32_t flags)
{ {
int error;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM; 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 STATIC int
......
...@@ -47,6 +47,16 @@ static DEFINE_MUTEX(xfs_uuid_table_mutex); ...@@ -47,6 +47,16 @@ static DEFINE_MUTEX(xfs_uuid_table_mutex);
static int xfs_uuid_table_size; static int xfs_uuid_table_size;
static uuid_t *xfs_uuid_table; 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. * 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. * Mount fails if UUID is nil or a FS with the same UUID is already mounted.
......
...@@ -313,6 +313,7 @@ typedef struct xfs_perag { ...@@ -313,6 +313,7 @@ typedef struct xfs_perag {
int pagb_count; /* pagb slots in use */ int pagb_count; /* pagb slots in use */
} xfs_perag_t; } xfs_perag_t;
extern void xfs_uuid_table_free(void);
extern int xfs_log_sbcount(xfs_mount_t *); extern int xfs_log_sbcount(xfs_mount_t *);
extern __uint64_t xfs_default_resblks(xfs_mount_t *mp); extern __uint64_t xfs_default_resblks(xfs_mount_t *mp);
extern int xfs_mountfs(xfs_mount_t *mp); extern int xfs_mountfs(xfs_mount_t *mp);
......
...@@ -1925,6 +1925,7 @@ exit_xfs_fs(void) ...@@ -1925,6 +1925,7 @@ exit_xfs_fs(void)
xfs_mru_cache_uninit(); xfs_mru_cache_uninit();
xfs_destroy_workqueues(); xfs_destroy_workqueues();
xfs_destroy_zones(); xfs_destroy_zones();
xfs_uuid_table_free();
} }
module_init(init_xfs_fs); module_init(init_xfs_fs);
......
...@@ -497,6 +497,7 @@ xfsaild( ...@@ -497,6 +497,7 @@ xfsaild(
long tout = 0; /* milliseconds */ long tout = 0; /* milliseconds */
current->flags |= PF_MEMALLOC; current->flags |= PF_MEMALLOC;
set_freezable();
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
if (tout && tout <= 20) if (tout && tout <= 20)
......
...@@ -107,6 +107,15 @@ xfs_trans_log_inode( ...@@ -107,6 +107,15 @@ xfs_trans_log_inode(
ASSERT(ip->i_itemp != NULL); ASSERT(ip->i_itemp != NULL);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); 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 * 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 * counter if it is configured for this to occur. We don't use
......
...@@ -53,11 +53,34 @@ xfs_xattr_get(struct dentry *dentry, const char *name, ...@@ -53,11 +53,34 @@ xfs_xattr_get(struct dentry *dentry, const char *name,
return asize; 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 static int
xfs_xattr_set(struct dentry *dentry, const char *name, const void *value, xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags, int xflags) 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) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
...@@ -70,8 +93,12 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value, ...@@ -70,8 +93,12 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
if (!value) if (!value)
return xfs_attr_remove(ip, (unsigned char *)name, xflags); 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); (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 = { static const struct xattr_handler xfs_xattr_user_handler = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment