aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-04-10 17:40:42 -0400
committerDave Airlie <airlied@redhat.com>2017-04-10 17:40:42 -0400
commitb769fefb68cd70385d68220ae341e5a10723fbc0 (patch)
treea2881410c9dc5a3474619d155fac981cfbd4ee8f /fs/xfs
parent1420f63b8207e966f54caec26d08abdc2ff37193 (diff)
parent39da7c509acff13fc8cb12ec1bb20337c988ed36 (diff)
Backmerge tag 'v4.11-rc6' into drm-next
Linux 4.11-rc6 drm-misc needs 4.11-rc5, may as well fix conflicts with rc6.
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/libxfs/xfs_dir2_priv.h3
-rw-r--r--fs/xfs/libxfs/xfs_dir2_sf.c63
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c35
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.h2
-rw-r--r--fs/xfs/xfs_bmap_util.c10
-rw-r--r--fs/xfs/xfs_inode.c19
-rw-r--r--fs/xfs/xfs_iops.c14
-rw-r--r--fs/xfs/xfs_itable.c2
8 files changed, 90 insertions, 58 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2_priv.h b/fs/xfs/libxfs/xfs_dir2_priv.h
index eb00bc133bca..39f8604f764e 100644
--- a/fs/xfs/libxfs/xfs_dir2_priv.h
+++ b/fs/xfs/libxfs/xfs_dir2_priv.h
@@ -125,8 +125,7 @@ extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino);
125extern int xfs_dir2_sf_lookup(struct xfs_da_args *args); 125extern int xfs_dir2_sf_lookup(struct xfs_da_args *args);
126extern int xfs_dir2_sf_removename(struct xfs_da_args *args); 126extern int xfs_dir2_sf_removename(struct xfs_da_args *args);
127extern int xfs_dir2_sf_replace(struct xfs_da_args *args); 127extern int xfs_dir2_sf_replace(struct xfs_da_args *args);
128extern int xfs_dir2_sf_verify(struct xfs_mount *mp, struct xfs_dir2_sf_hdr *sfp, 128extern int xfs_dir2_sf_verify(struct xfs_inode *ip);
129 int size);
130 129
131/* xfs_dir2_readdir.c */ 130/* xfs_dir2_readdir.c */
132extern int xfs_readdir(struct xfs_inode *dp, struct dir_context *ctx, 131extern int xfs_readdir(struct xfs_inode *dp, struct dir_context *ctx,
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 96b45cd6c63f..e84af093b2ab 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -632,36 +632,49 @@ xfs_dir2_sf_check(
632/* Verify the consistency of an inline directory. */ 632/* Verify the consistency of an inline directory. */
633int 633int
634xfs_dir2_sf_verify( 634xfs_dir2_sf_verify(
635 struct xfs_mount *mp, 635 struct xfs_inode *ip)
636 struct xfs_dir2_sf_hdr *sfp,
637 int size)
638{ 636{
637 struct xfs_mount *mp = ip->i_mount;
638 struct xfs_dir2_sf_hdr *sfp;
639 struct xfs_dir2_sf_entry *sfep; 639 struct xfs_dir2_sf_entry *sfep;
640 struct xfs_dir2_sf_entry *next_sfep; 640 struct xfs_dir2_sf_entry *next_sfep;
641 char *endp; 641 char *endp;
642 const struct xfs_dir_ops *dops; 642 const struct xfs_dir_ops *dops;
643 struct xfs_ifork *ifp;
643 xfs_ino_t ino; 644 xfs_ino_t ino;
644 int i; 645 int i;
645 int i8count; 646 int i8count;
646 int offset; 647 int offset;
648 int size;
649 int error;
647 __uint8_t filetype; 650 __uint8_t filetype;
648 651
652 ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL);
653 /*
654 * xfs_iread calls us before xfs_setup_inode sets up ip->d_ops,
655 * so we can only trust the mountpoint to have the right pointer.
656 */
649 dops = xfs_dir_get_ops(mp, NULL); 657 dops = xfs_dir_get_ops(mp, NULL);
650 658
659 ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
660 sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
661 size = ifp->if_bytes;
662
651 /* 663 /*
652 * Give up if the directory is way too short. 664 * Give up if the directory is way too short.
653 */ 665 */
654 XFS_WANT_CORRUPTED_RETURN(mp, size > 666 if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) ||
655 offsetof(struct xfs_dir2_sf_hdr, parent)); 667 size < xfs_dir2_sf_hdr_size(sfp->i8count))
656 XFS_WANT_CORRUPTED_RETURN(mp, size >= 668 return -EFSCORRUPTED;
657 xfs_dir2_sf_hdr_size(sfp->i8count));
658 669
659 endp = (char *)sfp + size; 670 endp = (char *)sfp + size;
660 671
661 /* Check .. entry */ 672 /* Check .. entry */
662 ino = dops->sf_get_parent_ino(sfp); 673 ino = dops->sf_get_parent_ino(sfp);
663 i8count = ino > XFS_DIR2_MAX_SHORT_INUM; 674 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
664 XFS_WANT_CORRUPTED_RETURN(mp, !xfs_dir_ino_validate(mp, ino)); 675 error = xfs_dir_ino_validate(mp, ino);
676 if (error)
677 return error;
665 offset = dops->data_first_offset; 678 offset = dops->data_first_offset;
666 679
667 /* Check all reported entries */ 680 /* Check all reported entries */
@@ -672,12 +685,12 @@ xfs_dir2_sf_verify(
672 * Check the fixed-offset parts of the structure are 685 * Check the fixed-offset parts of the structure are
673 * within the data buffer. 686 * within the data buffer.
674 */ 687 */
675 XFS_WANT_CORRUPTED_RETURN(mp, 688 if (((char *)sfep + sizeof(*sfep)) >= endp)
676 ((char *)sfep + sizeof(*sfep)) < endp); 689 return -EFSCORRUPTED;
677 690
678 /* Don't allow names with known bad length. */ 691 /* Don't allow names with known bad length. */
679 XFS_WANT_CORRUPTED_RETURN(mp, sfep->namelen > 0); 692 if (sfep->namelen == 0)
680 XFS_WANT_CORRUPTED_RETURN(mp, sfep->namelen < MAXNAMELEN); 693 return -EFSCORRUPTED;
681 694
682 /* 695 /*
683 * Check that the variable-length part of the structure is 696 * Check that the variable-length part of the structure is
@@ -685,33 +698,39 @@ xfs_dir2_sf_verify(
685 * name component, so nextentry is an acceptable test. 698 * name component, so nextentry is an acceptable test.
686 */ 699 */
687 next_sfep = dops->sf_nextentry(sfp, sfep); 700 next_sfep = dops->sf_nextentry(sfp, sfep);
688 XFS_WANT_CORRUPTED_RETURN(mp, endp >= (char *)next_sfep); 701 if (endp < (char *)next_sfep)
702 return -EFSCORRUPTED;
689 703
690 /* Check that the offsets always increase. */ 704 /* Check that the offsets always increase. */
691 XFS_WANT_CORRUPTED_RETURN(mp, 705 if (xfs_dir2_sf_get_offset(sfep) < offset)
692 xfs_dir2_sf_get_offset(sfep) >= offset); 706 return -EFSCORRUPTED;
693 707
694 /* Check the inode number. */ 708 /* Check the inode number. */
695 ino = dops->sf_get_ino(sfp, sfep); 709 ino = dops->sf_get_ino(sfp, sfep);
696 i8count += ino > XFS_DIR2_MAX_SHORT_INUM; 710 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
697 XFS_WANT_CORRUPTED_RETURN(mp, !xfs_dir_ino_validate(mp, ino)); 711 error = xfs_dir_ino_validate(mp, ino);
712 if (error)
713 return error;
698 714
699 /* Check the file type. */ 715 /* Check the file type. */
700 filetype = dops->sf_get_ftype(sfep); 716 filetype = dops->sf_get_ftype(sfep);
701 XFS_WANT_CORRUPTED_RETURN(mp, filetype < XFS_DIR3_FT_MAX); 717 if (filetype >= XFS_DIR3_FT_MAX)
718 return -EFSCORRUPTED;
702 719
703 offset = xfs_dir2_sf_get_offset(sfep) + 720 offset = xfs_dir2_sf_get_offset(sfep) +
704 dops->data_entsize(sfep->namelen); 721 dops->data_entsize(sfep->namelen);
705 722
706 sfep = next_sfep; 723 sfep = next_sfep;
707 } 724 }
708 XFS_WANT_CORRUPTED_RETURN(mp, i8count == sfp->i8count); 725 if (i8count != sfp->i8count)
709 XFS_WANT_CORRUPTED_RETURN(mp, (void *)sfep == (void *)endp); 726 return -EFSCORRUPTED;
727 if ((void *)sfep != (void *)endp)
728 return -EFSCORRUPTED;
710 729
711 /* Make sure this whole thing ought to be in local format. */ 730 /* Make sure this whole thing ought to be in local format. */
712 XFS_WANT_CORRUPTED_RETURN(mp, offset + 731 if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
713 (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + 732 (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize)
714 (uint)sizeof(xfs_dir2_block_tail_t) <= mp->m_dir_geo->blksize); 733 return -EFSCORRUPTED;
715 734
716 return 0; 735 return 0;
717} 736}
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 9653e964eda4..8a37efe04de3 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -212,6 +212,16 @@ xfs_iformat_fork(
212 if (error) 212 if (error)
213 return error; 213 return error;
214 214
215 /* Check inline dir contents. */
216 if (S_ISDIR(VFS_I(ip)->i_mode) &&
217 dip->di_format == XFS_DINODE_FMT_LOCAL) {
218 error = xfs_dir2_sf_verify(ip);
219 if (error) {
220 xfs_idestroy_fork(ip, XFS_DATA_FORK);
221 return error;
222 }
223 }
224
215 if (xfs_is_reflink_inode(ip)) { 225 if (xfs_is_reflink_inode(ip)) {
216 ASSERT(ip->i_cowfp == NULL); 226 ASSERT(ip->i_cowfp == NULL);
217 xfs_ifork_init_cow(ip); 227 xfs_ifork_init_cow(ip);
@@ -322,8 +332,6 @@ xfs_iformat_local(
322 int whichfork, 332 int whichfork,
323 int size) 333 int size)
324{ 334{
325 int error;
326
327 /* 335 /*
328 * If the size is unreasonable, then something 336 * If the size is unreasonable, then something
329 * is wrong and we just bail out rather than crash in 337 * is wrong and we just bail out rather than crash in
@@ -339,14 +347,6 @@ xfs_iformat_local(
339 return -EFSCORRUPTED; 347 return -EFSCORRUPTED;
340 } 348 }
341 349
342 if (S_ISDIR(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK) {
343 error = xfs_dir2_sf_verify(ip->i_mount,
344 (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip),
345 size);
346 if (error)
347 return error;
348 }
349
350 xfs_init_local_fork(ip, whichfork, XFS_DFORK_PTR(dip, whichfork), size); 350 xfs_init_local_fork(ip, whichfork, XFS_DFORK_PTR(dip, whichfork), size);
351 return 0; 351 return 0;
352} 352}
@@ -867,7 +867,7 @@ xfs_iextents_copy(
867 * In these cases, the format always takes precedence, because the 867 * In these cases, the format always takes precedence, because the
868 * format indicates the current state of the fork. 868 * format indicates the current state of the fork.
869 */ 869 */
870int 870void
871xfs_iflush_fork( 871xfs_iflush_fork(
872 xfs_inode_t *ip, 872 xfs_inode_t *ip,
873 xfs_dinode_t *dip, 873 xfs_dinode_t *dip,
@@ -877,7 +877,6 @@ xfs_iflush_fork(
877 char *cp; 877 char *cp;
878 xfs_ifork_t *ifp; 878 xfs_ifork_t *ifp;
879 xfs_mount_t *mp; 879 xfs_mount_t *mp;
880 int error;
881 static const short brootflag[2] = 880 static const short brootflag[2] =
882 { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; 881 { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT };
883 static const short dataflag[2] = 882 static const short dataflag[2] =
@@ -886,7 +885,7 @@ xfs_iflush_fork(
886 { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; 885 { XFS_ILOG_DEXT, XFS_ILOG_AEXT };
887 886
888 if (!iip) 887 if (!iip)
889 return 0; 888 return;
890 ifp = XFS_IFORK_PTR(ip, whichfork); 889 ifp = XFS_IFORK_PTR(ip, whichfork);
891 /* 890 /*
892 * This can happen if we gave up in iformat in an error path, 891 * This can happen if we gave up in iformat in an error path,
@@ -894,19 +893,12 @@ xfs_iflush_fork(
894 */ 893 */
895 if (!ifp) { 894 if (!ifp) {
896 ASSERT(whichfork == XFS_ATTR_FORK); 895 ASSERT(whichfork == XFS_ATTR_FORK);
897 return 0; 896 return;
898 } 897 }
899 cp = XFS_DFORK_PTR(dip, whichfork); 898 cp = XFS_DFORK_PTR(dip, whichfork);
900 mp = ip->i_mount; 899 mp = ip->i_mount;
901 switch (XFS_IFORK_FORMAT(ip, whichfork)) { 900 switch (XFS_IFORK_FORMAT(ip, whichfork)) {
902 case XFS_DINODE_FMT_LOCAL: 901 case XFS_DINODE_FMT_LOCAL:
903 if (S_ISDIR(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK) {
904 error = xfs_dir2_sf_verify(mp,
905 (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data,
906 ifp->if_bytes);
907 if (error)
908 return error;
909 }
910 if ((iip->ili_fields & dataflag[whichfork]) && 902 if ((iip->ili_fields & dataflag[whichfork]) &&
911 (ifp->if_bytes > 0)) { 903 (ifp->if_bytes > 0)) {
912 ASSERT(ifp->if_u1.if_data != NULL); 904 ASSERT(ifp->if_u1.if_data != NULL);
@@ -959,7 +951,6 @@ xfs_iflush_fork(
959 ASSERT(0); 951 ASSERT(0);
960 break; 952 break;
961 } 953 }
962 return 0;
963} 954}
964 955
965/* 956/*
diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
index 132dc59fdde6..7fb8365326d1 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.h
+++ b/fs/xfs/libxfs/xfs_inode_fork.h
@@ -140,7 +140,7 @@ typedef struct xfs_ifork {
140struct xfs_ifork *xfs_iext_state_to_fork(struct xfs_inode *ip, int state); 140struct xfs_ifork *xfs_iext_state_to_fork(struct xfs_inode *ip, int state);
141 141
142int xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *); 142int xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *);
143int xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *, 143void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *,
144 struct xfs_inode_log_item *, int); 144 struct xfs_inode_log_item *, int);
145void xfs_idestroy_fork(struct xfs_inode *, int); 145void xfs_idestroy_fork(struct xfs_inode *, int);
146void xfs_idata_realloc(struct xfs_inode *, int, int); 146void xfs_idata_realloc(struct xfs_inode *, int, int);
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 8b75dcea5966..828532ce0adc 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1311,8 +1311,16 @@ xfs_free_file_space(
1311 /* 1311 /*
1312 * Now that we've unmap all full blocks we'll have to zero out any 1312 * Now that we've unmap all full blocks we'll have to zero out any
1313 * partial block at the beginning and/or end. xfs_zero_range is 1313 * partial block at the beginning and/or end. xfs_zero_range is
1314 * smart enough to skip any holes, including those we just created. 1314 * smart enough to skip any holes, including those we just created,
1315 * but we must take care not to zero beyond EOF and enlarge i_size.
1315 */ 1316 */
1317
1318 if (offset >= XFS_ISIZE(ip))
1319 return 0;
1320
1321 if (offset + len > XFS_ISIZE(ip))
1322 len = XFS_ISIZE(ip) - offset;
1323
1316 return xfs_zero_range(ip, offset, len, NULL); 1324 return xfs_zero_range(ip, offset, len, NULL);
1317} 1325}
1318 1326
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index c7fe2c2123ab..7605d8396596 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -50,6 +50,7 @@
50#include "xfs_log.h" 50#include "xfs_log.h"
51#include "xfs_bmap_btree.h" 51#include "xfs_bmap_btree.h"
52#include "xfs_reflink.h" 52#include "xfs_reflink.h"
53#include "xfs_dir2_priv.h"
53 54
54kmem_zone_t *xfs_inode_zone; 55kmem_zone_t *xfs_inode_zone;
55 56
@@ -3475,7 +3476,6 @@ xfs_iflush_int(
3475 struct xfs_inode_log_item *iip = ip->i_itemp; 3476 struct xfs_inode_log_item *iip = ip->i_itemp;
3476 struct xfs_dinode *dip; 3477 struct xfs_dinode *dip;
3477 struct xfs_mount *mp = ip->i_mount; 3478 struct xfs_mount *mp = ip->i_mount;
3478 int error;
3479 3479
3480 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); 3480 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
3481 ASSERT(xfs_isiflocked(ip)); 3481 ASSERT(xfs_isiflocked(ip));
@@ -3547,6 +3547,12 @@ xfs_iflush_int(
3547 if (ip->i_d.di_version < 3) 3547 if (ip->i_d.di_version < 3)
3548 ip->i_d.di_flushiter++; 3548 ip->i_d.di_flushiter++;
3549 3549
3550 /* Check the inline directory data. */
3551 if (S_ISDIR(VFS_I(ip)->i_mode) &&
3552 ip->i_d.di_format == XFS_DINODE_FMT_LOCAL &&
3553 xfs_dir2_sf_verify(ip))
3554 goto corrupt_out;
3555
3550 /* 3556 /*
3551 * Copy the dirty parts of the inode into the on-disk inode. We always 3557 * Copy the dirty parts of the inode into the on-disk inode. We always
3552 * copy out the core of the inode, because if the inode is dirty at all 3558 * copy out the core of the inode, because if the inode is dirty at all
@@ -3558,14 +3564,9 @@ xfs_iflush_int(
3558 if (ip->i_d.di_flushiter == DI_MAX_FLUSH) 3564 if (ip->i_d.di_flushiter == DI_MAX_FLUSH)
3559 ip->i_d.di_flushiter = 0; 3565 ip->i_d.di_flushiter = 0;
3560 3566
3561 error = xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK); 3567 xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK);
3562 if (error) 3568 if (XFS_IFORK_Q(ip))
3563 return error; 3569 xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK);
3564 if (XFS_IFORK_Q(ip)) {
3565 error = xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK);
3566 if (error)
3567 return error;
3568 }
3569 xfs_inobp_check(mp, bp); 3570 xfs_inobp_check(mp, bp);
3570 3571
3571 /* 3572 /*
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 229cc6a6d8ef..ebfc13350f9a 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -516,6 +516,20 @@ xfs_vn_getattr(
516 stat->blocks = 516 stat->blocks =
517 XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); 517 XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
518 518
519 if (ip->i_d.di_version == 3) {
520 if (request_mask & STATX_BTIME) {
521 stat->result_mask |= STATX_BTIME;
522 stat->btime.tv_sec = ip->i_d.di_crtime.t_sec;
523 stat->btime.tv_nsec = ip->i_d.di_crtime.t_nsec;
524 }
525 }
526
527 if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE)
528 stat->attributes |= STATX_ATTR_IMMUTABLE;
529 if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
530 stat->attributes |= STATX_ATTR_APPEND;
531 if (ip->i_d.di_flags & XFS_DIFLAG_NODUMP)
532 stat->attributes |= STATX_ATTR_NODUMP;
519 533
520 switch (inode->i_mode & S_IFMT) { 534 switch (inode->i_mode & S_IFMT) {
521 case S_IFBLK: 535 case S_IFBLK:
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 2a6d9b1558e0..26d67ce3c18d 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -583,7 +583,7 @@ xfs_inumbers(
583 return error; 583 return error;
584 584
585 bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer))); 585 bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer)));
586 buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP); 586 buffer = kmem_zalloc(bcount * sizeof(*buffer), KM_SLEEP);
587 do { 587 do {
588 struct xfs_inobt_rec_incore r; 588 struct xfs_inobt_rec_incore r;
589 int stat; 589 int stat;