Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFSv4: Fix up mirror allocation

There are a number of callers of nfs_pageio_complete() that want to
continue using the nfs_pageio_descriptor without needing to call
nfs_pageio_init() again. Examples include nfs_pageio_resend() and
nfs_pageio_cond_complete().

The problem is that nfs_pageio_complete() also calls
nfs_pageio_cleanup_mirroring(), which frees up the array of mirrors.
This can lead to writeback errors, in the next call to
nfs_pageio_setup_mirroring().

Fix by simply moving the allocation of the mirrors to
nfs_pageio_setup_mirroring().

Link: https://bugzilla.kernel.org/show_bug.cgi?id=196709
Reported-by: JianhongYin <yin-jianhong@163.com>
Cc: stable@vger.kernel.org # 4.0+
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

+39 -34
+39 -34
fs/nfs/pagelist.c
··· 714 714 int io_flags, 715 715 gfp_t gfp_flags) 716 716 { 717 - struct nfs_pgio_mirror *new; 718 - int i; 719 - 720 717 desc->pg_moreio = 0; 721 718 desc->pg_inode = inode; 722 719 desc->pg_ops = pg_ops; ··· 729 732 desc->pg_mirror_count = 1; 730 733 desc->pg_mirror_idx = 0; 731 734 732 - if (pg_ops->pg_get_mirror_count) { 733 - /* until we have a request, we don't have an lseg and no 734 - * idea how many mirrors there will be */ 735 - new = kcalloc(NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX, 736 - sizeof(struct nfs_pgio_mirror), gfp_flags); 737 - desc->pg_mirrors_dynamic = new; 738 - desc->pg_mirrors = new; 739 - 740 - for (i = 0; i < NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX; i++) 741 - nfs_pageio_mirror_init(&desc->pg_mirrors[i], bsize); 742 - } else { 743 - desc->pg_mirrors_dynamic = NULL; 744 - desc->pg_mirrors = desc->pg_mirrors_static; 745 - nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize); 746 - } 735 + desc->pg_mirrors_dynamic = NULL; 736 + desc->pg_mirrors = desc->pg_mirrors_static; 737 + nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize); 747 738 } 748 739 EXPORT_SYMBOL_GPL(nfs_pageio_init); 749 740 ··· 850 865 return ret; 851 866 } 852 867 868 + static struct nfs_pgio_mirror * 869 + nfs_pageio_alloc_mirrors(struct nfs_pageio_descriptor *desc, 870 + unsigned int mirror_count) 871 + { 872 + struct nfs_pgio_mirror *ret; 873 + unsigned int i; 874 + 875 + kfree(desc->pg_mirrors_dynamic); 876 + desc->pg_mirrors_dynamic = NULL; 877 + if (mirror_count == 1) 878 + return desc->pg_mirrors_static; 879 + ret = kmalloc_array(mirror_count, sizeof(*ret), GFP_NOFS); 880 + if (ret != NULL) { 881 + for (i = 0; i < mirror_count; i++) 882 + nfs_pageio_mirror_init(&ret[i], desc->pg_bsize); 883 + desc->pg_mirrors_dynamic = ret; 884 + } 885 + return ret; 886 + } 887 + 853 888 /* 854 889 * nfs_pageio_setup_mirroring - determine if mirroring is to be used 855 890 * by calling the pg_get_mirror_count op 856 891 */ 857 - static int nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio, 892 + static void nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio, 858 893 struct nfs_page *req) 859 894 { 860 - int mirror_count = 1; 895 + unsigned int mirror_count = 1; 861 896 862 - if (!pgio->pg_ops->pg_get_mirror_count) 863 - return 0; 897 + if (pgio->pg_ops->pg_get_mirror_count) 898 + mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req); 899 + if (mirror_count == pgio->pg_mirror_count || pgio->pg_error < 0) 900 + return; 864 901 865 - mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req); 902 + if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX) { 903 + pgio->pg_error = -EINVAL; 904 + return; 905 + } 866 906 867 - if (pgio->pg_error < 0) 868 - return pgio->pg_error; 869 - 870 - if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX) 871 - return -EINVAL; 872 - 873 - if (WARN_ON_ONCE(!pgio->pg_mirrors_dynamic)) 874 - return -EINVAL; 875 - 907 + pgio->pg_mirrors = nfs_pageio_alloc_mirrors(pgio, mirror_count); 908 + if (pgio->pg_mirrors == NULL) { 909 + pgio->pg_error = -ENOMEM; 910 + pgio->pg_mirrors = pgio->pg_mirrors_static; 911 + mirror_count = 1; 912 + } 876 913 pgio->pg_mirror_count = mirror_count; 877 - 878 - return 0; 879 914 } 880 915 881 916 /*