[parisc-linux-cvs] fix for wide kernel nfsd

bame@riverrock.org bame@riverrock.org
Thu, 10 May 2001 14:18:49 -0600


kernel nfsd needed a much better nfsservctl() wrapper.  Also added
a quotactl() wrapper (borrowed from sparc64).

Index: syscall.S
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/syscall.S,v
retrieving revision 1.64
diff -u -r1.64 syscall.S
--- syscall.S	2001/04/30 20:39:25	1.64
+++ syscall.S	2001/05/10 20:07:06
@@ -486,7 +486,7 @@
 	/* struct kernel_sym contains a long. Linus never heard of size_t? */
 	ENTRY_DIFF(get_kernel_syms)	/* 130 */
 	/* time_t inside struct dqblk */
-	ENTRY_UHOH(quotactl)
+	ENTRY_DIFF(quotactl)
 	ENTRY_SAME(getpgid)
 	ENTRY_SAME(fchdir)
 	ENTRY_SAME(bdflush)
Index: sys_parisc32.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/sys_parisc32.c,v
retrieving revision 1.10
diff -u -r1.10 sys_parisc32.c
--- sys_parisc32.c	2001/04/30 20:39:25	1.10
+++ sys_parisc32.c	2001/05/10 20:07:06
@@ -2893,14 +2893,187 @@
        return sys_pwrite(fd, buf, count, (loff_t)high << 32 | low);
 }
 
+/* EXPORT/UNEXPORT */
+struct nfsctl_export32 {
+	char			ex_client[NFSCLNT_IDMAX+1];
+	char			ex_path[NFS_MAXPATHLEN+1];
+	__kernel_dev_t		ex_dev;
+	__kernel_ino_t32	ex_ino;
+	int			ex_flags;
+	__kernel_uid_t		ex_anon_uid;
+	__kernel_gid_t		ex_anon_gid;
+};
+
+/* GETFH */
+struct nfsctl_fhparm32 {
+	struct sockaddr		gf_addr;
+	__kernel_dev_t		gf_dev;
+	__kernel_ino_t32	gf_ino;
+	int			gf_version;
+};
+
+/* UGIDUPDATE */
+struct nfsctl_uidmap32 {
+	__kernel_caddr_t32	ug_ident;
+	__kernel_uid_t		ug_uidbase;
+	int			ug_uidlen;
+	__kernel_caddr_t32	ug_udimap;
+	__kernel_gid_t		ug_gidbase;
+	int			ug_gidlen;
+	__kernel_caddr_t32	ug_gdimap;
+};
+
+struct nfsctl_arg32 {
+	int			ca_version;	/* safeguard */
+	/* wide kernel places this union on 8-byte boundary, narrow on 4 */
+	union {
+		struct nfsctl_svc	u_svc;
+		struct nfsctl_client	u_client;
+		struct nfsctl_export32	u_export;
+		struct nfsctl_uidmap32	u_umap;
+		struct nfsctl_fhparm32	u_getfh;
+		struct nfsctl_fdparm	u_getfd;
+		struct nfsctl_fsparm	u_getfs;
+	} u;
+};
+
 asmlinkage int sys32_nfsservctl(int cmd, void *argp, void *resp)
 {
-	extern int sys_nfsservctl(int cmd, void *argp, void *resp);
+	int ret, tmp;
+	struct nfsctl_arg32 n32;
+	struct nfsctl_arg n;
+
+	ret = copy_from_user(&n, argp, sizeof n.ca_version);
+	if (ret != 0)
+		return ret;
+
+	/* adjust argp to point at the union inside the user's n32 struct */
+	tmp = (unsigned long)&n32.u - (unsigned long)&n32;
+	argp = (void *)((unsigned long)argp + tmp);
+	switch(cmd) {
+	case NFSCTL_SVC:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_svc);
+		break;
+
+	case NFSCTL_ADDCLIENT:
+	case NFSCTL_DELCLIENT:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_client);
+		break;
+
+	case NFSCTL_GETFD:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_getfd);
+		break;
+
+	case NFSCTL_GETFS:
+		ret = copy_from_user(&n.u, argp, sizeof n.u.u_getfs);
+		break;
+
+	case NFSCTL_GETFH:		/* nfsctl_fhparm */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_getfh);
+#undef CP
+#define CP(x)	n.u.u_getfh.gf_##x = n32.u.u_getfh.gf_##x
+		CP(addr);
+		CP(dev);
+		CP(ino);
+		CP(version);
+		break;
 
-	if (cmd == NFSCTL_UGIDUPDATE) {
-		printk("nfsservctl(NFSCTL_UGIDUPDATE) wrapper not yet supported\n");
-		return -ENOSYS;
+	case NFSCTL_UGIDUPDATE:		/* nfsctl_uidmap */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_umap);
+#undef CP
+#define CP(x)	n.u.u_umap.ug_##x = n32.u.u_umap.ug_##x
+		n.u.u_umap.ug_ident = (char *)(u_long)n32.u.u_umap.ug_ident;
+		CP(uidbase);
+		CP(uidlen);
+		n.u.u_umap.ug_udimap = (__kernel_uid_t *)(u_long)n32.u.u_umap.ug_udimap;
+		CP(gidbase);
+		CP(gidlen);
+		n.u.u_umap.ug_gdimap = (__kernel_gid_t *)(u_long)n32.u.u_umap.ug_gdimap;
+		break;
+
+	case NFSCTL_UNEXPORT:		/* nfsctl_export */
+	case NFSCTL_EXPORT:		/* nfsctl_export */
+		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_export);
+#undef CP
+#define CP(x)	n.u.u_export.ex_##x = n32.u.u_export.ex_##x
+		memcpy(n.u.u_export.ex_client, n32.u.u_export.ex_client, sizeof n32.u.u_export.ex_client);
+		memcpy(n.u.u_export.ex_path, n32.u.u_export.ex_path, sizeof n32.u.u_export.ex_path);
+		CP(dev);
+		CP(ino);
+		CP(flags);
+		CP(anon_uid);
+		CP(anon_gid);
+		break;
+
+	default:
+		BUG(); /* new cmd values to be translated... */
+		ret = -EINVAL;
+		break;
 	}
+
+	if (ret == 0) {
+		unsigned char rbuf[NFS_FHSIZE + sizeof (struct knfsd_fh)];
+		KERNEL_SYSCALL(ret, sys_nfsservctl, cmd, &n, &rbuf);
+		if (cmd == NFSCTL_GETFH || cmd == NFSCTL_GETFD) {
+			ret = copy_to_user(resp, rbuf, NFS_FHSIZE);
+		} else if (cmd == NFSCTL_GETFS) {
+			ret = copy_to_user(resp, rbuf, sizeof (struct knfsd_fh));
+		}
+	}
+
+	return ret;
+}
 
-	return sys_nfsservctl(cmd, argp, resp);
+#include <linux/quota.h>
+
+struct dqblk32 {
+    __u32 dqb_bhardlimit;
+    __u32 dqb_bsoftlimit;
+    __u32 dqb_curblocks;
+    __u32 dqb_ihardlimit;
+    __u32 dqb_isoftlimit;
+    __u32 dqb_curinodes;
+    __kernel_time_t32 dqb_btime;
+    __kernel_time_t32 dqb_itime;
+};
+                                
+
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+{
+	extern int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+	int cmds = cmd >> SUBCMDSHIFT;
+	int err;
+	struct dqblk d;
+	char *spec;
+	
+	switch (cmds) {
+	case Q_GETQUOTA:
+		break;
+	case Q_SETQUOTA:
+	case Q_SETUSE:
+	case Q_SETQLIM:
+		if (copy_from_user (&d, (struct dqblk32 *)addr,
+				    sizeof (struct dqblk32)))
+			return -EFAULT;
+		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
+		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+		break;
+	default:
+		return sys_quotactl(cmd, special,
+				    id, (caddr_t)addr);
+	}
+	spec = getname (special);
+	err = PTR_ERR(spec);
+	if (IS_ERR(spec)) return err;
+	KERNEL_SYSCALL(err, sys_quotactl, cmd, (const char *)spec, id, (caddr_t)&d);
+	putname (spec);
+	if (cmds == Q_GETQUOTA) {
+		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
+		((struct dqblk32 *)&d)->dqb_itime = i;
+		((struct dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user ((struct dqblk32 *)addr, &d,
+				  sizeof (struct dqblk32)))
+			return -EFAULT;
+	}
+	return err;
 }