[PATCH] Add 32-bit compatibility for NFSv4 mount

This adds 32-bit compatibility for mounting an NFSv4 mount on a 64-bit
kernel (such as happens with PPC64).

The problem is that the mount data for the NFS4 mount process includes
auxilliary data pointers, probably because the NFS4 mount data may
conceivably exceed PAGE_SIZE in size - thus breaking against the hard
limit imposed by sys_mount().

Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by David Howells and committed by Linus Torvalds 9a9947bf 219f0817

+74
+74
fs/compat.c
··· 31 #include <linux/smb.h> 32 #include <linux/smb_mount.h> 33 #include <linux/ncp_mount.h> 34 #include <linux/smp_lock.h> 35 #include <linux/syscalls.h> 36 #include <linux/ctype.h> ··· 807 return raw_data; 808 } 809 810 extern int copy_mount_options (const void __user *, unsigned long *); 811 812 #define SMBFS_NAME "smbfs" 813 #define NCPFS_NAME "ncpfs" 814 815 asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, 816 char __user * type, unsigned long flags, ··· 915 do_smb_super_data_conv((void *)data_page); 916 } else if (!strcmp((char *)type_page, NCPFS_NAME)) { 917 do_ncp_super_data_conv((void *)data_page); 918 } 919 } 920 ··· 926 flags, (void*)data_page); 927 unlock_kernel(); 928 929 free_page(data_page); 930 out3: 931 free_page(dev_page);
··· 31 #include <linux/smb.h> 32 #include <linux/smb_mount.h> 33 #include <linux/ncp_mount.h> 34 + #include <linux/nfs4_mount.h> 35 #include <linux/smp_lock.h> 36 #include <linux/syscalls.h> 37 #include <linux/ctype.h> ··· 806 return raw_data; 807 } 808 809 + struct compat_nfs_string { 810 + compat_uint_t len; 811 + compat_uptr_t __user data; 812 + }; 813 + 814 + static inline void compat_nfs_string(struct nfs_string *dst, 815 + struct compat_nfs_string *src) 816 + { 817 + dst->data = compat_ptr(src->data); 818 + dst->len = src->len; 819 + } 820 + 821 + struct compat_nfs4_mount_data_v1 { 822 + compat_int_t version; 823 + compat_int_t flags; 824 + compat_int_t rsize; 825 + compat_int_t wsize; 826 + compat_int_t timeo; 827 + compat_int_t retrans; 828 + compat_int_t acregmin; 829 + compat_int_t acregmax; 830 + compat_int_t acdirmin; 831 + compat_int_t acdirmax; 832 + struct compat_nfs_string client_addr; 833 + struct compat_nfs_string mnt_path; 834 + struct compat_nfs_string hostname; 835 + compat_uint_t host_addrlen; 836 + compat_uptr_t __user host_addr; 837 + compat_int_t proto; 838 + compat_int_t auth_flavourlen; 839 + compat_uptr_t __user auth_flavours; 840 + }; 841 + 842 + static int do_nfs4_super_data_conv(void *raw_data) 843 + { 844 + int version = *(compat_uint_t *) raw_data; 845 + 846 + if (version == 1) { 847 + struct compat_nfs4_mount_data_v1 *raw = raw_data; 848 + struct nfs4_mount_data *real = raw_data; 849 + 850 + /* copy the fields backwards */ 851 + real->auth_flavours = compat_ptr(raw->auth_flavours); 852 + real->auth_flavourlen = raw->auth_flavourlen; 853 + real->proto = raw->proto; 854 + real->host_addr = compat_ptr(raw->host_addr); 855 + real->host_addrlen = raw->host_addrlen; 856 + compat_nfs_string(&real->hostname, &raw->hostname); 857 + compat_nfs_string(&real->mnt_path, &raw->mnt_path); 858 + compat_nfs_string(&real->client_addr, &raw->client_addr); 859 + real->acdirmax = raw->acdirmax; 860 + real->acdirmin = raw->acdirmin; 861 + real->acregmax = raw->acregmax; 862 + real->acregmin = raw->acregmin; 863 + real->retrans = raw->retrans; 864 + real->timeo = raw->timeo; 865 + real->wsize = raw->wsize; 866 + real->rsize = raw->rsize; 867 + real->flags = raw->flags; 868 + real->version = raw->version; 869 + } 870 + else { 871 + return -EINVAL; 872 + } 873 + 874 + return 0; 875 + } 876 + 877 extern int copy_mount_options (const void __user *, unsigned long *); 878 879 #define SMBFS_NAME "smbfs" 880 #define NCPFS_NAME "ncpfs" 881 + #define NFS4_NAME "nfs4" 882 883 asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, 884 char __user * type, unsigned long flags, ··· 845 do_smb_super_data_conv((void *)data_page); 846 } else if (!strcmp((char *)type_page, NCPFS_NAME)) { 847 do_ncp_super_data_conv((void *)data_page); 848 + } else if (!strcmp((char *)type_page, NFS4_NAME)) { 849 + if (do_nfs4_super_data_conv((void *) data_page)) 850 + goto out4; 851 } 852 } 853 ··· 853 flags, (void*)data_page); 854 unlock_kernel(); 855 856 + out4: 857 free_page(data_page); 858 out3: 859 free_page(dev_page);