diff options
author | Dave Chinner <david@fromorbit.com> | 2015-11-02 21:27:58 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2015-11-02 21:27:58 -0500 |
commit | 2da5c4b05ab55225f5d1fcc8c1c37d1918232bf4 (patch) | |
tree | f19bd87d6e66c251566be226fdf40c24c168e04a | |
parent | fcd8a399a9d44a637b5ded0eeea14c7933132121 (diff) | |
parent | fc0561cefc04e7803c0f6501ca4f310a502f65b8 (diff) |
Merge branch 'xfs-misc-fixes-for-4.4-2' into for-next
-rw-r--r-- | fs/xfs/libxfs/xfs_format.h | 8 | ||||
-rw-r--r-- | fs/xfs/xfs_acl.c | 13 | ||||
-rw-r--r-- | fs/xfs/xfs_acl.h | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_file.c | 21 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_inode_item.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_inode_item.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 15 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 10 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_super.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_ail.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_inode.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_xattr.c | 31 |
14 files changed, 101 insertions, 16 deletions
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 8568de163004..8774498ce0ff 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h | |||
@@ -1495,9 +1495,13 @@ struct xfs_acl { | |||
1495 | sizeof(struct xfs_acl_entry) \ | 1495 | sizeof(struct xfs_acl_entry) \ |
1496 | : 25) | 1496 | : 25) |
1497 | 1497 | ||
1498 | #define XFS_ACL_MAX_SIZE(mp) \ | 1498 | #define XFS_ACL_SIZE(cnt) \ |
1499 | (sizeof(struct xfs_acl) + \ | 1499 | (sizeof(struct xfs_acl) + \ |
1500 | sizeof(struct xfs_acl_entry) * XFS_ACL_MAX_ENTRIES((mp))) | 1500 | sizeof(struct xfs_acl_entry) * cnt) |
1501 | |||
1502 | #define XFS_ACL_MAX_SIZE(mp) \ | ||
1503 | XFS_ACL_SIZE(XFS_ACL_MAX_ENTRIES((mp))) | ||
1504 | |||
1501 | 1505 | ||
1502 | /* On-disk XFS extended attribute names */ | 1506 | /* On-disk XFS extended attribute names */ |
1503 | #define SGI_ACL_FILE "SGI_ACL_FILE" | 1507 | #define SGI_ACL_FILE "SGI_ACL_FILE" |
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 4b641676f258..763e36560681 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c | |||
@@ -37,16 +37,19 @@ | |||
37 | 37 | ||
38 | STATIC struct posix_acl * | 38 | STATIC struct posix_acl * |
39 | xfs_acl_from_disk( | 39 | xfs_acl_from_disk( |
40 | struct xfs_acl *aclp, | 40 | const struct xfs_acl *aclp, |
41 | int max_entries) | 41 | int len, |
42 | int max_entries) | ||
42 | { | 43 | { |
43 | struct posix_acl_entry *acl_e; | 44 | struct posix_acl_entry *acl_e; |
44 | struct posix_acl *acl; | 45 | struct posix_acl *acl; |
45 | struct xfs_acl_entry *ace; | 46 | const struct xfs_acl_entry *ace; |
46 | unsigned int count, i; | 47 | unsigned int count, i; |
47 | 48 | ||
49 | if (len < sizeof(*aclp)) | ||
50 | return ERR_PTR(-EFSCORRUPTED); | ||
48 | count = be32_to_cpu(aclp->acl_cnt); | 51 | count = be32_to_cpu(aclp->acl_cnt); |
49 | if (count > max_entries) | 52 | if (count > max_entries || XFS_ACL_SIZE(count) != len) |
50 | return ERR_PTR(-EFSCORRUPTED); | 53 | return ERR_PTR(-EFSCORRUPTED); |
51 | 54 | ||
52 | acl = posix_acl_alloc(count, GFP_KERNEL); | 55 | acl = posix_acl_alloc(count, GFP_KERNEL); |
@@ -163,7 +166,7 @@ xfs_get_acl(struct inode *inode, int type) | |||
163 | goto out; | 166 | goto out; |
164 | } | 167 | } |
165 | 168 | ||
166 | acl = xfs_acl_from_disk(xfs_acl, XFS_ACL_MAX_ENTRIES(ip->i_mount)); | 169 | acl = xfs_acl_from_disk(xfs_acl, len, XFS_ACL_MAX_ENTRIES(ip->i_mount)); |
167 | if (IS_ERR(acl)) | 170 | if (IS_ERR(acl)) |
168 | goto out; | 171 | goto out; |
169 | 172 | ||
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 3841b07f27bf..75af0a4d9028 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h | |||
@@ -36,4 +36,7 @@ static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type) | |||
36 | # define posix_acl_access_exists(inode) 0 | 36 | # define posix_acl_access_exists(inode) 0 |
37 | # define posix_acl_default_exists(inode) 0 | 37 | # define posix_acl_default_exists(inode) 0 |
38 | #endif /* CONFIG_XFS_POSIX_ACL */ | 38 | #endif /* CONFIG_XFS_POSIX_ACL */ |
39 | |||
40 | extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags); | ||
41 | |||
39 | #endif /* __XFS_ACL_H__ */ | 42 | #endif /* __XFS_ACL_H__ */ |
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 2f7b6bd39f61..a3bf4c099dd2 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -242,19 +242,30 @@ xfs_file_fsync( | |||
242 | } | 242 | } |
243 | 243 | ||
244 | /* | 244 | /* |
245 | * All metadata updates are logged, which means that we just have | 245 | * All metadata updates are logged, which means that we just have to |
246 | * to flush the log up to the latest LSN that touched the inode. | 246 | * flush the log up to the latest LSN that touched the inode. If we have |
247 | * concurrent fsync/fdatasync() calls, we need them to all block on the | ||
248 | * log force before we clear the ili_fsync_fields field. This ensures | ||
249 | * that we don't get a racing sync operation that does not wait for the | ||
250 | * metadata to hit the journal before returning. If we race with | ||
251 | * clearing the ili_fsync_fields, then all that will happen is the log | ||
252 | * force will do nothing as the lsn will already be on disk. We can't | ||
253 | * race with setting ili_fsync_fields because that is done under | ||
254 | * XFS_ILOCK_EXCL, and that can't happen because we hold the lock shared | ||
255 | * until after the ili_fsync_fields is cleared. | ||
247 | */ | 256 | */ |
248 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 257 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
249 | if (xfs_ipincount(ip)) { | 258 | if (xfs_ipincount(ip)) { |
250 | if (!datasync || | 259 | if (!datasync || |
251 | (ip->i_itemp->ili_fields & ~XFS_ILOG_TIMESTAMP)) | 260 | (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP)) |
252 | lsn = ip->i_itemp->ili_last_lsn; | 261 | lsn = ip->i_itemp->ili_last_lsn; |
253 | } | 262 | } |
254 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
255 | 263 | ||
256 | if (lsn) | 264 | if (lsn) { |
257 | error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed); | 265 | error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed); |
266 | ip->i_itemp->ili_fsync_fields = 0; | ||
267 | } | ||
268 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
258 | 269 | ||
259 | /* | 270 | /* |
260 | * If we only have a single device, and the log force about was | 271 | * If we only have a single device, and the log force about was |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index a0f2bae6dc1e..8ee393996b7d 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -2365,6 +2365,7 @@ retry: | |||
2365 | 2365 | ||
2366 | iip->ili_last_fields = iip->ili_fields; | 2366 | iip->ili_last_fields = iip->ili_fields; |
2367 | iip->ili_fields = 0; | 2367 | iip->ili_fields = 0; |
2368 | iip->ili_fsync_fields = 0; | ||
2368 | iip->ili_logged = 1; | 2369 | iip->ili_logged = 1; |
2369 | xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, | 2370 | xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, |
2370 | &iip->ili_item.li_lsn); | 2371 | &iip->ili_item.li_lsn); |
@@ -3560,6 +3561,7 @@ xfs_iflush_int( | |||
3560 | */ | 3561 | */ |
3561 | iip->ili_last_fields = iip->ili_fields; | 3562 | iip->ili_last_fields = iip->ili_fields; |
3562 | iip->ili_fields = 0; | 3563 | iip->ili_fields = 0; |
3564 | iip->ili_fsync_fields = 0; | ||
3563 | iip->ili_logged = 1; | 3565 | iip->ili_logged = 1; |
3564 | 3566 | ||
3565 | xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, | 3567 | xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, |
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 62bd80f4edd9..d14b12b8cfef 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
@@ -719,6 +719,7 @@ xfs_iflush_abort( | |||
719 | * attempted. | 719 | * attempted. |
720 | */ | 720 | */ |
721 | iip->ili_fields = 0; | 721 | iip->ili_fields = 0; |
722 | iip->ili_fsync_fields = 0; | ||
722 | } | 723 | } |
723 | /* | 724 | /* |
724 | * Release the inode's flush lock since we're done with it. | 725 | * Release the inode's flush lock since we're done with it. |
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h index 488d81254e28..4c7722e325b3 100644 --- a/fs/xfs/xfs_inode_item.h +++ b/fs/xfs/xfs_inode_item.h | |||
@@ -34,6 +34,7 @@ typedef struct xfs_inode_log_item { | |||
34 | unsigned short ili_logged; /* flushed logged data */ | 34 | unsigned short ili_logged; /* flushed logged data */ |
35 | unsigned int ili_last_fields; /* fields when flushed */ | 35 | unsigned int ili_last_fields; /* fields when flushed */ |
36 | unsigned int ili_fields; /* fields to be logged */ | 36 | unsigned int ili_fields; /* fields to be logged */ |
37 | unsigned int ili_fsync_fields; /* logged since last fsync */ | ||
37 | } xfs_inode_log_item_t; | 38 | } xfs_inode_log_item_t; |
38 | 39 | ||
39 | static inline int xfs_inode_clean(xfs_inode_t *ip) | 40 | static inline int xfs_inode_clean(xfs_inode_t *ip) |
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index c88ddcadd656..d42738deec6d 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "xfs_symlink.h" | 40 | #include "xfs_symlink.h" |
41 | #include "xfs_trans.h" | 41 | #include "xfs_trans.h" |
42 | #include "xfs_pnfs.h" | 42 | #include "xfs_pnfs.h" |
43 | #include "xfs_acl.h" | ||
43 | 44 | ||
44 | #include <linux/capability.h> | 45 | #include <linux/capability.h> |
45 | #include <linux/dcache.h> | 46 | #include <linux/dcache.h> |
@@ -482,6 +483,7 @@ xfs_attrmulti_attr_set( | |||
482 | __uint32_t flags) | 483 | __uint32_t flags) |
483 | { | 484 | { |
484 | unsigned char *kbuf; | 485 | unsigned char *kbuf; |
486 | int error; | ||
485 | 487 | ||
486 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 488 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
487 | return -EPERM; | 489 | return -EPERM; |
@@ -492,7 +494,11 @@ xfs_attrmulti_attr_set( | |||
492 | if (IS_ERR(kbuf)) | 494 | if (IS_ERR(kbuf)) |
493 | return PTR_ERR(kbuf); | 495 | return PTR_ERR(kbuf); |
494 | 496 | ||
495 | return xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); | 497 | error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); |
498 | if (!error) | ||
499 | xfs_forget_acl(inode, name, flags); | ||
500 | kfree(kbuf); | ||
501 | return error; | ||
496 | } | 502 | } |
497 | 503 | ||
498 | int | 504 | int |
@@ -501,9 +507,14 @@ xfs_attrmulti_attr_remove( | |||
501 | unsigned char *name, | 507 | unsigned char *name, |
502 | __uint32_t flags) | 508 | __uint32_t flags) |
503 | { | 509 | { |
510 | int error; | ||
511 | |||
504 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 512 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
505 | return -EPERM; | 513 | return -EPERM; |
506 | return xfs_attr_remove(XFS_I(inode), name, flags); | 514 | error = xfs_attr_remove(XFS_I(inode), name, flags); |
515 | if (!error) | ||
516 | xfs_forget_acl(inode, name, flags); | ||
517 | return error; | ||
507 | } | 518 | } |
508 | 519 | ||
509 | STATIC int | 520 | STATIC int |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index eb498ce39f4c..bb753b359bee 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -47,6 +47,16 @@ static DEFINE_MUTEX(xfs_uuid_table_mutex); | |||
47 | static int xfs_uuid_table_size; | 47 | static int xfs_uuid_table_size; |
48 | static uuid_t *xfs_uuid_table; | 48 | static uuid_t *xfs_uuid_table; |
49 | 49 | ||
50 | void | ||
51 | xfs_uuid_table_free(void) | ||
52 | { | ||
53 | if (xfs_uuid_table_size == 0) | ||
54 | return; | ||
55 | kmem_free(xfs_uuid_table); | ||
56 | xfs_uuid_table = NULL; | ||
57 | xfs_uuid_table_size = 0; | ||
58 | } | ||
59 | |||
50 | /* | 60 | /* |
51 | * See if the UUID is unique among mounted XFS filesystems. | 61 | * See if the UUID is unique among mounted XFS filesystems. |
52 | * Mount fails if UUID is nil or a FS with the same UUID is already mounted. | 62 | * Mount fails if UUID is nil or a FS with the same UUID is already mounted. |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 8795272cb662..6db5fc041d4f 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -313,6 +313,7 @@ typedef struct xfs_perag { | |||
313 | int pagb_count; /* pagb slots in use */ | 313 | int pagb_count; /* pagb slots in use */ |
314 | } xfs_perag_t; | 314 | } xfs_perag_t; |
315 | 315 | ||
316 | extern void xfs_uuid_table_free(void); | ||
316 | extern int xfs_log_sbcount(xfs_mount_t *); | 317 | extern int xfs_log_sbcount(xfs_mount_t *); |
317 | extern __uint64_t xfs_default_resblks(xfs_mount_t *mp); | 318 | extern __uint64_t xfs_default_resblks(xfs_mount_t *mp); |
318 | extern int xfs_mountfs(xfs_mount_t *mp); | 319 | extern int xfs_mountfs(xfs_mount_t *mp); |
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index b2c252cd7172..0378e22eeae1 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c | |||
@@ -1925,6 +1925,7 @@ exit_xfs_fs(void) | |||
1925 | xfs_mru_cache_uninit(); | 1925 | xfs_mru_cache_uninit(); |
1926 | xfs_destroy_workqueues(); | 1926 | xfs_destroy_workqueues(); |
1927 | xfs_destroy_zones(); | 1927 | xfs_destroy_zones(); |
1928 | xfs_uuid_table_free(); | ||
1928 | } | 1929 | } |
1929 | 1930 | ||
1930 | module_init(init_xfs_fs); | 1931 | module_init(init_xfs_fs); |
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 4f18fd92ca13..aa67339b9537 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
@@ -497,6 +497,7 @@ xfsaild( | |||
497 | long tout = 0; /* milliseconds */ | 497 | long tout = 0; /* milliseconds */ |
498 | 498 | ||
499 | current->flags |= PF_MEMALLOC; | 499 | current->flags |= PF_MEMALLOC; |
500 | set_freezable(); | ||
500 | 501 | ||
501 | while (!kthread_should_stop()) { | 502 | while (!kthread_should_stop()) { |
502 | if (tout && tout <= 20) | 503 | if (tout && tout <= 20) |
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index 17280cd71934..b97f1df910ab 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c | |||
@@ -108,6 +108,15 @@ xfs_trans_log_inode( | |||
108 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | 108 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
109 | 109 | ||
110 | /* | 110 | /* |
111 | * Record the specific change for fdatasync optimisation. This | ||
112 | * allows fdatasync to skip log forces for inodes that are only | ||
113 | * timestamp dirty. We do this before the change count so that | ||
114 | * the core being logged in this case does not impact on fdatasync | ||
115 | * behaviour. | ||
116 | */ | ||
117 | ip->i_itemp->ili_fsync_fields |= flags; | ||
118 | |||
119 | /* | ||
111 | * First time we log the inode in a transaction, bump the inode change | 120 | * First time we log the inode in a transaction, bump the inode change |
112 | * counter if it is configured for this to occur. We don't use | 121 | * counter if it is configured for this to occur. We don't use |
113 | * inode_inc_version() because there is no need for extra locking around | 122 | * inode_inc_version() because there is no need for extra locking around |
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index c036815183cb..8294f86441bf 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c | |||
@@ -53,11 +53,34 @@ xfs_xattr_get(struct dentry *dentry, const char *name, | |||
53 | return asize; | 53 | return asize; |
54 | } | 54 | } |
55 | 55 | ||
56 | void | ||
57 | xfs_forget_acl( | ||
58 | struct inode *inode, | ||
59 | const char *name, | ||
60 | int xflags) | ||
61 | { | ||
62 | /* | ||
63 | * Invalidate any cached ACLs if the user has bypassed the ACL | ||
64 | * interface. We don't validate the content whatsoever so it is caller | ||
65 | * responsibility to provide data in valid format and ensure i_mode is | ||
66 | * consistent. | ||
67 | */ | ||
68 | if (xflags & ATTR_ROOT) { | ||
69 | #ifdef CONFIG_XFS_POSIX_ACL | ||
70 | if (!strcmp(name, SGI_ACL_FILE)) | ||
71 | forget_cached_acl(inode, ACL_TYPE_ACCESS); | ||
72 | else if (!strcmp(name, SGI_ACL_DEFAULT)) | ||
73 | forget_cached_acl(inode, ACL_TYPE_DEFAULT); | ||
74 | #endif | ||
75 | } | ||
76 | } | ||
77 | |||
56 | static int | 78 | static int |
57 | xfs_xattr_set(struct dentry *dentry, const char *name, const void *value, | 79 | xfs_xattr_set(struct dentry *dentry, const char *name, const void *value, |
58 | size_t size, int flags, int xflags) | 80 | size_t size, int flags, int xflags) |
59 | { | 81 | { |
60 | struct xfs_inode *ip = XFS_I(d_inode(dentry)); | 82 | struct xfs_inode *ip = XFS_I(d_inode(dentry)); |
83 | int error; | ||
61 | 84 | ||
62 | if (strcmp(name, "") == 0) | 85 | if (strcmp(name, "") == 0) |
63 | return -EINVAL; | 86 | return -EINVAL; |
@@ -70,8 +93,12 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value, | |||
70 | 93 | ||
71 | if (!value) | 94 | if (!value) |
72 | return xfs_attr_remove(ip, (unsigned char *)name, xflags); | 95 | return xfs_attr_remove(ip, (unsigned char *)name, xflags); |
73 | return xfs_attr_set(ip, (unsigned char *)name, | 96 | error = xfs_attr_set(ip, (unsigned char *)name, |
74 | (void *)value, size, xflags); | 97 | (void *)value, size, xflags); |
98 | if (!error) | ||
99 | xfs_forget_acl(d_inode(dentry), name, xflags); | ||
100 | |||
101 | return error; | ||
75 | } | 102 | } |
76 | 103 | ||
77 | static const struct xattr_handler xfs_xattr_user_handler = { | 104 | static const struct xattr_handler xfs_xattr_user_handler = { |