[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;
}