[OpenAFS-devel] [PATCH] in-core AFS multiplexor and PAG support

David Howells dhowells@redhat.com
Tue, 13 May 2003 16:39:20 +0100


Hi Linus,

Here's a patch to add three things that are required for AFS and that may be
of use to other stuff (such as NFSv4 and Samba):

 (1) PAG (Process Authentication Group) support. A PAG is ID'd by a unique
     number, and is represented in memory as a structure that has a ring of
     associated authentication tokens.

     Each process can either be part of a PAG, or it can PAG-less - in which
     case it has no authentication tokens.

     Two new syscalls are added: setpag and getpag.

 (2) Authentication token support. An authentication token is a blob of binary
     data that is keyed by filesystem name and fs-specific key (such as AFS
     cell name or SMB workgroup).

     These are retained in two places: each PAG has a ring of tokens
     appropriate to the group of processes within that PAG; and each struct
     file has a pointer to the single token governing that file (if there is
     one).

 (3) AFS multiplexor support. Not complete at the moment, but implemented far
     enough to provide access to the PAG mechanism. Further patches will be
     forthcoming to make this fully functional.

It is my intention to add Trond's vfs_cred stuff in at some point, but that
has a lot greater impact than this patch (which has negligible impact).

David

diff -uNr linux-2.5.69/arch/i386/kernel/entry.S linux-2.5.69-cred/arch/i386/kernel/entry.S
--- linux-2.5.69/arch/i386/kernel/entry.S	2003-05-06 15:06:47.000000000 +0100
+++ linux-2.5.69-cred/arch/i386/kernel/entry.S	2003-05-13 11:16:17.000000000 +0100
@@ -721,7 +721,7 @@
 	.long sys_bdflush
 	.long sys_sysfs		/* 135 */
 	.long sys_personality
-	.long sys_ni_syscall	/* reserved for afs_syscall */
+	.long sys_afs
 	.long sys_setfsuid16
 	.long sys_setfsgid16
 	.long sys_llseek	/* 140 */
@@ -852,6 +852,7 @@
  	.long sys_clock_gettime		/* 265 */
  	.long sys_clock_getres
  	.long sys_clock_nanosleep
- 
+	.long sys_setpag
+	.long sys_getpag
  
 nr_syscalls=(.-sys_call_table)/4
diff -uNr linux-2.5.69/fs/afssyscall.c linux-2.5.69-cred/fs/afssyscall.c
--- linux-2.5.69/fs/afssyscall.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.69-cred/fs/afssyscall.c	2003-05-13 16:02:47.000000000 +0100
@@ -0,0 +1,223 @@
+/* afssyscall.c: AFS system call multiplexor
+ *
+ * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/afs_syscall.h>
+#include <linux/linkage.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/cred.h>
+#include <asm/uaccess.h>
+
+static const struct {
+	u_int8_t	flags;
+#define VIOC_PATH_YES		0x01	/* must be a path */
+#define VIOC_PATH_NO		0x02	/* must not be a path */
+#define VIOC_FOLLOW_OPT		0x00	/* followsymlinks can be anything */
+#define VIOC_FOLLOW_NO		0x04	/* followsymlinks must be false */
+#define VIOC_IN_OPT		0x00	/* input data optional */
+#define VIOC_IN_YES		0x08	/* input data required */
+#define VIOC_IN_NO		0x10	/* input data prohibited */
+#define VIOC_OUT_OPT		0x00	/* output buffer optional */  
+#define VIOC_OUT_YES		0x20	/* output buffer required */  
+#define VIOC_OUT_NO		0x40	/* output buffer prohibited */
+#define VIOC_VALID		0x80	/* entry is valid */
+
+} afs_vioc_table[] = {
+
+#define _v(NAME,P,F,I,O) [NAME] = \
+{ VIOC_VALID | VIOC_PATH_##P | VIOC_FOLLOW_##F | VIOC_IN_##I | VIOC_OUT_##O }
+
+	/* command name                  path folw  in  out */
+	_v(__VIOCSETAL			, YES, OPT, YES, NO ),
+	_v(__VIOCGETAL			, YES, OPT, NO , YES),
+	_v(__VIOCSETTOK			, NO , NO , YES, NO ),
+	_v(__VIOCGETVOLSTAT		, YES, OPT, NO , YES),
+	_v(__VIOCSETVOLSTAT		, YES, OPT, YES, NO ),
+	_v(__VIOCFLUSH			, YES, OPT, NO , NO ),
+	_v(__VIOCGETTOK			, NO , NO , YES, YES),
+	_v(__VIOCUNLOG			, NO , NO , NO , NO ),
+	_v(__VIOCCKSERV			, NO , NO , OPT, OPT),
+	_v(__VIOCCKBACK			, NO , NO , NO , NO ),
+	_v(__VIOCCKCONN			, NO , NO , NO , YES),
+	_v(__VIOCWHEREIS		, YES, OPT, NO , YES),
+	_v(__VIOCACCESS			, YES, OPT, YES, NO ),
+	_v(__VIOCUNPAG			, NO , NO , NO , NO ),
+	_v(__VIOCGETFID			, YES, OPT, NO , YES),
+	_v(__VIOCSETCACHESIZE		, NO , NO , YES, NO ),
+	_v(__VIOCFLUSHCB		, YES, OPT, NO , NO ),
+	_v(__VIOCNEWCELL		, NO , NO , YES, NO ),
+	_v(__VIOCGETCELL		, NO , NO , YES, YES),
+	_v(__VIOC_DELETE_MT_PT		, YES, NO , YES, NO ),
+	_v(__VIOC_STAT_MT_PT		, YES, OPT, YES, YES), /* !! can't use xattr */
+	_v(__VIOC_FILE_CELL_NAME	, YES, OPT, NO , YES),
+	_v(__VIOC_GET_WS_CELL		, NO , NO , NO , YES),
+	_v(__VIOC_AFS_MARINER_HOST	, NO , NO , YES, OPT),
+	_v(__VIOC_GET_PRIMARY_CELL	, NO , NO , NO , YES),
+	_v(__VIOC_VENUSLOG		, NO , NO , YES, OPT),
+	_v(__VIOC_GETCELLSTATUS		, NO , NO , YES, YES),
+	_v(__VIOC_SETCELLSTATUS		, NO , NO , YES, NO ),
+	_v(__VIOC_FLUSHVOLUME		, YES, OPT, NO , NO ),
+	_v(__VIOC_AFS_SYSNAME		, NO , NO , YES, OPT),
+	_v(__VIOC_EXPORTAFS		, NO , NO , YES, OPT),
+	_v(__VIOCGETCACHEPARMS		, NO , NO , NO , YES),
+
+};
+
+static int vfs_pioctl(const char __user *path, long cmd, void __user *arg, int followsymlinks);
+static int vfs_pioctl_inode(struct nameidata *nd, long cmd, struct afs_ioctl *ioc);
+static int vfs_pioctl_fs(long cmd, struct afs_ioctl *ioc);
+
+/*****************************************************************************/
+/*
+ * AFS syscall multiplexor
+ */
+int sys_afs(long subsyscall, long p1, long p2, long p3, long p4, long p5)
+{
+	switch (subsyscall) {
+	case AFS_SYSCALL_PIOCTL:	return vfs_pioctl((const char*)p1,p2,(void*)p3,p4);
+	case AFS_SYSCALL_SETPAG:	return sys_setpag(-1);
+	case AFS_SYSCALL_CALL:		return -ENOSYS;
+	case AFS_SYSCALL_ICL:		return -ENOSYS;
+	default:			return -ENOSYS;
+	}
+
+} /* end sys_afs() */
+
+/*****************************************************************************/
+/*
+ * handle path-based ioctl
+ */
+static int vfs_pioctl(const char __user *path, long cmd, void __user *arg, int followsymlinks)
+{
+	struct afs_ioctl uioc, ioc;
+	struct nameidata nd;
+	void *data;
+	char flags;
+	int err;
+
+	if (_IOC_NR(cmd) < 0 || _IOC_NR(cmd) >= sizeof(afs_vioc_table)/sizeof(afs_vioc_table[0]))
+		return -EINVAL;
+	flags = afs_vioc_table[_IOC_NR(cmd)].flags;
+
+	if (!(flags & VIOC_VALID))
+		return -EINVAL;
+
+	if ((flags & VIOC_PATH_NO	&& path			) ||
+	    (flags & VIOC_PATH_YES	&& !path		) ||
+	    (flags & VIOC_FOLLOW_NO	&& followsymlinks	))
+		return -EINVAL;
+
+	if (copy_from_user(&uioc,arg,sizeof(uioc)) != 0)
+		return -EFAULT;
+
+	if ((flags & VIOC_IN_YES	&& !uioc.in	) ||
+	    (flags & VIOC_IN_NO		&& uioc.in	) ||
+	    (flags & VIOC_OUT_YES	&& !uioc.out	) ||
+	    (flags & VIOC_OUT_NO	&& uioc.out	))
+		return -EINVAL;
+
+	if (uioc.in_size<0)
+		ioc.in_size = 0;
+	else if (uioc.in_size > PAGE_SIZE/2)
+		return -E2BIG;
+	else
+		ioc.in_size = uioc.in_size;
+
+	if (uioc.out_size<0)
+		ioc.out_size = 0;
+	else if (uioc.out_size > PAGE_SIZE/2)
+		return -E2BIG;
+	else
+		ioc.out_size = uioc.out_size;
+
+	if ((flags & VIOC_IN_YES	&& ioc.in_size<=0	) ||
+	    (flags & VIOC_IN_NO		&& ioc.in_size>0	) ||
+	    (flags & VIOC_OUT_YES	&& ioc.out_size<=0	) ||
+	    (flags & VIOC_OUT_NO	&& ioc.out_size>0	))
+		return -EINVAL;
+
+	data = (void*) get_zeroed_page(GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	ioc.in	= ioc.in_size>0  ? data : NULL;
+	ioc.out	= ioc.out_size>0 ? data + PAGE_SIZE/2 : NULL;
+
+	if (ioc.in && copy_from_user(ioc.in,uioc.in,ioc.in_size) != 0) {
+		free_page((unsigned long)data);
+		return -EFAULT;
+	}
+
+	/* perform the appropriate action */
+	if (!path) {
+		err = vfs_pioctl_fs(cmd,&ioc);
+	}
+	else {
+		unsigned flags = followsymlinks ? LOOKUP_FOLLOW : 0;
+
+		err = __user_walk(path,flags,&nd);
+		if (!err) {
+			err = vfs_pioctl_inode(&nd,cmd,&ioc);
+			path_release(&nd);
+		}
+	}
+
+	/* write back the result, zero padding to the size of the buffer */
+	if (err==0 || uioc.out_size) {
+		if (copy_to_user(uioc.out,ioc.out,uioc.out_size) != 0)
+			err = -EFAULT;
+	}
+
+	free_page((unsigned long)data);
+	return err;
+
+} /* end vfs_pioctl() */
+
+/*****************************************************************************/
+/*
+ * pioctls that require an inode
+ */
+static int vfs_pioctl_inode(struct nameidata *nd, long cmd, struct afs_ioctl *ioc)
+{
+#if 0
+	printk("vfs_pioctl_inode(%s,%ld,{is=%hd,os=%hd})\n",
+	       nd->dentry->d_name.name,_IOC_NR(cmd),ioc->in_size,ioc->out_size);
+#endif
+
+	return -EINVAL; /* not yet complete */
+
+} /* end vfs_pioctl_inode() */
+
+/*****************************************************************************/
+/*
+ * pioctls that don't require an inode, but rather work on the FS as a whole
+ */
+static int vfs_pioctl_fs(long cmd, struct afs_ioctl *ioc)
+{
+#if 0
+	printk("vfs_pioctl_fs(%ld,{is=%hd,os=%hd})\n",
+	       _IOC_NR(cmd),ioc->in_size,ioc->out_size);
+#endif
+
+	switch (cmd) {
+	case VIOCUNPAG:
+	case VIOCUNLOG:
+		ioc->out_size = 0;
+		vfs_unpag("afs");
+		return 0;
+	default:
+		return -EINVAL; /* not yet complete */
+	}
+
+} /* end vfs_pioctl_fs() */
diff -uNr linux-2.5.69/fs/file_table.c linux-2.5.69-cred/fs/file_table.c
--- linux-2.5.69/fs/file_table.c	2003-05-06 15:04:45.000000000 +0100
+++ linux-2.5.69-cred/fs/file_table.c	2003-05-13 13:54:58.000000000 +0100
@@ -166,6 +166,7 @@
 	if (file->f_op && file->f_op->release)
 		file->f_op->release(inode, file);
 	security_file_free(file);
+	if (file->f_token) vfs_token_put(file->f_token);
 	fops_put(file->f_op);
 	if (file->f_mode & FMODE_WRITE)
 		put_write_access(inode);
diff -uNr linux-2.5.69/fs/Makefile linux-2.5.69-cred/fs/Makefile
--- linux-2.5.69/fs/Makefile	2003-05-06 15:04:46.000000000 +0100
+++ linux-2.5.69-cred/fs/Makefile	2003-05-13 11:18:20.000000000 +0100
@@ -10,7 +10,8 @@
 		namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o dnotify.o \
 		filesystems.o namespace.o seq_file.o xattr.o libfs.o \
-		fs-writeback.o mpage.o direct-io.o aio.o eventpoll.o
+		fs-writeback.o mpage.o direct-io.o aio.o eventpoll.o \
+		afssyscall.o
 
 obj-$(CONFIG_COMPAT) += compat.o
 
diff -uNr linux-2.5.69/fs/open.c linux-2.5.69-cred/fs/open.c
--- linux-2.5.69/fs/open.c	2003-05-06 15:04:45.000000000 +0100
+++ linux-2.5.69-cred/fs/open.c	2003-05-13 11:28:08.000000000 +0100
@@ -46,7 +46,7 @@
 	struct nameidata nd;
 	int error;
 
-	error = user_path_walk(path, &nd);
+	error = user_path_walk(path,&nd);
 	if (!error) {
 		struct statfs tmp;
 		error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
diff -uNr linux-2.5.69/fs/proc/array.c linux-2.5.69-cred/fs/proc/array.c
--- linux-2.5.69/fs/proc/array.c	2003-05-06 15:07:08.000000000 +0100
+++ linux-2.5.69-cred/fs/proc/array.c	2003-05-13 10:58:56.000000000 +0100
@@ -154,13 +154,14 @@
 	read_lock(&tasklist_lock);
 	buffer += sprintf(buffer,
 		"State:\t%s\n"
+		"Pag:\t%d\n"
 		"Tgid:\t%d\n"
 		"Pid:\t%d\n"
 		"PPid:\t%d\n"
 		"TracerPid:\t%d\n"
 		"Uid:\t%d\t%d\t%d\t%d\n"
 		"Gid:\t%d\t%d\t%d\t%d\n",
-		get_task_state(p), p->tgid,
+		get_task_state(p), p->vfspag ? p->vfspag->pag : 0, p->tgid,
 		p->pid, p->pid ? p->real_parent->pid : 0,
 		p->pid && p->ptrace ? p->parent->pid : 0,
 		p->uid, p->euid, p->suid, p->fsuid,
diff -uNr linux-2.5.69/include/asm-i386/posix_types.h linux-2.5.69-cred/include/asm-i386/posix_types.h
--- linux-2.5.69/include/asm-i386/posix_types.h	2003-05-06 15:04:37.000000000 +0100
+++ linux-2.5.69-cred/include/asm-i386/posix_types.h	2003-05-12 10:19:15.000000000 +0100
@@ -13,6 +13,7 @@
 typedef unsigned short	__kernel_nlink_t;
 typedef long		__kernel_off_t;
 typedef int		__kernel_pid_t;
+typedef int		__kernel_pag_t;
 typedef unsigned short	__kernel_ipc_pid_t;
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
diff -uNr linux-2.5.69/include/asm-i386/unistd.h linux-2.5.69-cred/include/asm-i386/unistd.h
--- linux-2.5.69/include/asm-i386/unistd.h	2003-05-06 15:04:37.000000000 +0100
+++ linux-2.5.69-cred/include/asm-i386/unistd.h	2003-05-13 10:47:59.000000000 +0100
@@ -273,8 +273,10 @@
 #define __NR_clock_gettime	(__NR_timer_create+6)
 #define __NR_clock_getres	(__NR_timer_create+7)
 #define __NR_clock_nanosleep	(__NR_timer_create+8)
+#define __NR_setpag		268
+#define __NR_getpag		269
 
-#define NR_syscalls 268
+#define NR_syscalls 270
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -uNr linux-2.5.69/include/linux/afs_syscall.h linux-2.5.69-cred/include/linux/afs_syscall.h
--- linux-2.5.69/include/linux/afs_syscall.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.69-cred/include/linux/afs_syscall.h	2003-05-13 13:30:15.000000000 +0100
@@ -0,0 +1,159 @@
+/* afs_syscall.h: AFS system call constants and structures
+ *
+ * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _LINUX_AFS_SYSCALL_H
+#define _LINUX_AFS_SYSCALL_H
+
+/* level one multiplexor */
+#define AFS_SYSCALL_PIOCTL	20
+#define AFS_SYSCALL_SETPAG	21
+#define AFS_SYSCALL_CALL	28
+#define AFS_SYSCALL_ICL		30
+
+/* level two multiplexor for pioctl call */
+#define __VIOCSETAL			1	/* set the ACL on a directory */
+#define __VIOCGETAL			2	/* get the ACL on a directory */
+#define __VIOCSETTOK			3	/* set the caller's token for a cell */
+#define __VIOCGETVOLSTAT		4	/* get volume status */
+#define __VIOCSETVOLSTAT		5	/* set volume status */
+#define __VIOCFLUSH			6	/* flush an object from the cache */
+#define __VIOCGETTOK			8	/* get the caller's token for a cell */
+#define __VIOCUNLOG			9	/* discard authentication information */
+#define __VIOCCKSERV			10	/* check status of 1+ file servers */
+#define __VIOCCKBACK			11	/* mark cached volume info as stale */
+#define __VIOCCKCONN			12	/* check caller's tokens/connections */
+#define __VIOCWHEREIS			13	/* find host for a volume */
+#define __VIOCACCESS			20	/* check caller's access on an object */
+#define __VIOCUNPAG			21	/* discard authentication information */
+#define __VIOCGETFID			22	/* get FID for an object */
+#define __VIOCSETCACHESIZE		24	/* set max cache size*/
+#define __VIOCFLUSHCB			25	/* unilaterally drop a callback */
+#define __VIOCNEWCELL			26	/* set cell service information */
+#define __VIOCGETCELL			27	/* get cell configuration entry */
+#define __VIOC_DELETE_MT_PT		28	/* delete a mount point */
+#define __VIOC_STAT_MT_PT		29	/* get contents of a mount point */
+#define __VIOC_FILE_CELL_NAME		30	/* get cell hosting a given object */
+#define __VIOC_GET_WS_CELL		31	/* get caller's home cell name */
+#define __VIOC_AFS_MARINER_HOST		32	/* get/set file transfer monitoring o/p */
+#define __VIOC_GET_PRIMARY_CELL		33	/* get caller's primary cell */
+#define __VIOC_VENUSLOG			34	/* enable/disable CM logging */
+#define __VIOC_GETCELLSTATUS		35	/* get status info for a cell entry */
+#define __VIOC_SETCELLSTATUS		36	/* set status info for a cell entry */
+#define __VIOC_FLUSHVOLUME		37	/* flush cached data from a volume */
+#define __VIOC_AFS_SYSNAME		38	/* get/set the @sys mapping */
+#define __VIOC_EXPORTAFS		39	/* enable/disable NFS/AFS translation */
+#define __VIOCGETCACHEPARMS		40	/* get current cache parameter values */
+
+#define __VIOC(N)	_IOW('V',N,struct afs_ioctl)
+
+#define VIOCSETAL			__VIOC(__VIOCSETAL)
+#define VIOCGETAL			__VIOC(__VIOCGETAL)
+#define VIOCSETTOK			__VIOC(__VIOCSETTOK)
+#define VIOCGETVOLSTAT			__VIOC(__VIOCGETVOLSTAT)
+#define VIOCSETVOLSTAT			__VIOC(__VIOCSETVOLSTAT)
+#define VIOCFLUSH			__VIOC(__VIOCFLUSH)
+#define VIOCGETTOK			__VIOC(__VIOCGETTOK)
+#define VIOCUNLOG			__VIOC(__VIOCUNLOG)
+#define VIOCCKSERV			__VIOC(__VIOCCKSERV)
+#define VIOCCKBACK			__VIOC(__VIOCCKBACK)
+#define VIOCCKCONN			__VIOC(__VIOCCKCONN)
+#define VIOCWHEREIS			__VIOC(__VIOCWHEREIS)
+#define VIOCACCESS			__VIOC(__VIOCACCESS)
+#define VIOCUNPAG			__VIOC(__VIOCUNPAG)
+#define VIOCGETFID			__VIOC(__VIOCGETFID)
+#define VIOCSETCACHESIZE		__VIOC(__VIOCSETCACHESIZE)
+#define VIOCFLUSHCB			__VIOC(__VIOCFLUSHCB)
+#define VIOCNEWCELL			__VIOC(__VIOCNEWCELL)
+#define VIOCGETCELL			__VIOC(__VIOCGETCELL)
+#define VIOC_DELETE_MT_PT		__VIOC(__VIOC_DELETE_MT_PT)
+#define VIOC_STAT_MT_PT			__VIOC(__VIOC_STAT_MT_PT)
+#define VIOC_FILE_CELL_NAME		__VIOC(__VIOC_FILE_CELL_NAME)
+#define VIOC_GET_WS_CELL		__VIOC(__VIOC_GET_WS_CELL)
+#define VIOC_AFS_MARINER_HOST		__VIOC(__VIOC_AFS_MARINER_HOST)
+#define VIOC_GET_PRIMARY_CELL		__VIOC(__VIOC_GET_PRIMARY_CELL)
+#define VIOC_VENUSLOG			__VIOC(__VIOC_VENUSLOG)
+#define VIOC_GETCELLSTATUS		__VIOC(__VIOC_GETCELLSTATUS)
+#define VIOC_SETCELLSTATUS		__VIOC(__VIOC_SETCELLSTATUS)
+#define VIOC_FLUSHVOLUME		__VIOC(__VIOC_FLUSHVOLUME)
+#define VIOC_AFS_SYSNAME		__VIOC(__VIOC_AFS_SYSNAME)
+#define VIOC_EXPORTAFS			__VIOC(__VIOC_EXPORTAFS)
+#define VIOCGETCACHEPARMS		__VIOC(__VIOCGETCACHEPARMS)
+
+/* level two multiplexor for AFS control operations */
+#define	AFSOP_START_RXCALLBACK		0
+#define	AFSOP_START_AFS			1
+#define	AFSOP_START_BKG			2
+#define	AFSOP_START_TRUNCDAEMON		3
+#define AFSOP_START_CS			4
+#define	AFSOP_ADDCELL			5
+#define	AFSOP_CACHEINIT			6
+#define	AFSOP_CACHEINFO			7
+#define	AFSOP_VOLUMEINFO		8
+#define	AFSOP_CACHEFILE			9
+#define	AFSOP_CACHEINODE		10
+#define	AFSOP_AFSLOG			11
+#define	AFSOP_ROOTVOLUME		12
+#define	AFSOP_STARTLOG			14
+#define	AFSOP_ENDLOG			15
+#define AFSOP_AFS_VFSMOUNT		16
+#define AFSOP_ADVISEADDR		17
+#define AFSOP_CLOSEWAIT			18
+#define	AFSOP_RXEVENT_DAEMON		19
+#define	AFSOP_GETMTU			20
+#define	AFSOP_GETIFADDRS		21
+#define	AFSOP_ADDCELL2			29
+#define	AFSOP_AFSDB_HANDLER		30
+#define	AFSOP_SET_DYNROOT		31
+#define	AFSOP_ADDCELLALIAS		32
+#define	AFSOP_SET_FAKESTAT		33
+#define	AFSOP_CELLINFO			34
+#define	AFSOP_SET_THISCELL		35
+#define AFSOP_BASIC_INIT		36
+
+/* level two multiplexor for In Core Logging (ICL) call */
+#define AFS_ICL_OP_COPYOUT		1
+#define	AFS_ICL_OP_ENUMLOGS		2
+#define	AFS_ICL_OP_CLRLOG		3
+#define	AFS_ICL_OP_CLRSET		4
+#define AFS_ICL_OP_CLRALL		5
+#define AFS_ICL_OP_ENUMSETS		6
+#define	AFS_ICL_OP_SETSTAT		7
+#define	AFS_ICL_OP_SETSTATALL		8
+#define AFS_ICL_OP_SETLOGSIZE		9
+#define	AFS_ICL_OP_ENUMLOGSBYSET	10
+#define AFS_ICL_OP_GETSETINFO		11
+#define AFS_ICL_OP_GETLOGINFO		12
+#define AFS_ICL_OP_COPYOUTCLR		13
+#define AFS_ICL_OP_VERSION		14
+
+/*
+ * all AFS pioctls take the same sort of argument
+ */
+struct afs_ioctl
+{
+	char		*in;		/* input buffer */
+	char		*out;		/* output buffer */
+	int16_t		in_size;	/* size of input buffer */
+	int16_t		out_size;	/* maximum size of output buffer */
+};
+
+#define AFS_IOCTL_IN_SIZE_MAX	2048
+#define AFS_IOCTL_OUT_SIZE_MAX	2048
+
+/*
+ * but this is used if the kernel is 64-bit, which is really strange
+ */
+struct afs_ioctl32
+{
+	u_int32_t	in;		/* input buffer address (cast to pointer) */
+	u_int32_t	out;		/* output buffer address (cast to pointer) */
+	int16_t		in_size;	/* size of input buffer */
+	int16_t		out_size;	/* maximum size of output buffer */
+};
+
+
+
+#endif /* _LINUX_AFS_SYSCALL_H */
diff -uNr linux-2.5.69/include/linux/cred.h linux-2.5.69-cred/include/linux/cred.h
--- linux-2.5.69/include/linux/cred.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.69-cred/include/linux/cred.h	2003-05-13 13:20:06.000000000 +0100
@@ -0,0 +1,79 @@
+#ifndef _LINUX_CRED_H
+#define _LINUX_CRED_H
+
+#ifdef __KERNEL__
+
+#include <linux/param.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <asm/atomic.h>
+
+/*
+ * VFS session authentication token cache
+ *
+ * This is used to store the data required for extra levels of filesystem
+ * security (such as AFS/NFS kerberos keys, Samba workgroup/user/pass, or NTFS
+ * ACLs).
+ *
+ * VFS authentication tokens contain a single blob of data, consisting of three
+ * parts, all next to each other:
+ *   (1) An FS name
+ *   (2) A key
+ *   (3) An arbitrary chunk of data
+ *
+ * Token blobs must not be changed once passed to the core kernel for management
+ */
+struct vfs_pag
+{
+	struct rb_node		node;
+	atomic_t		usage;
+	pag_t			pag;	/* Process Authentication Group ID */
+	struct list_head	tokens;	/* authentication tokens */
+	rwlock_t		lock;
+};
+
+struct vfs_token
+{
+	atomic_t		usage;
+	struct list_head	link;	/* link in pag's list */
+	unsigned short		k_off;	/* offset of key in blob */
+	unsigned short		d_off;	/* offset of data in blob */
+	size_t			size;	/* size of blob */
+	void			*blob;	/* blob containing key + data */
+};
+
+extern int sys_setpag(pag_t);
+extern int sys_getpag(void);
+extern void vfs_unpag(const char *fsname);
+
+extern void vfs_pag_put(struct vfs_pag *);
+
+static inline struct vfs_pag *vfs_pag_get(struct vfs_pag *vfspag)
+{
+	atomic_inc(&vfspag->usage);
+	return vfspag;
+}
+
+static inline int is_vfs_token_valid(struct vfs_token *vtoken)
+{
+	return !list_empty(&vtoken->link);
+}
+
+extern int vfs_pag_add_token(const char *fsname,
+			     unsigned short klen,
+			     const void *key,
+			     size_t dlen,
+			     const void *data,
+			     struct vfs_token **_token);
+
+extern struct vfs_token *vfs_pag_find_token(const char *fsname,
+					    unsigned short klen,
+					    const void *key);
+
+extern void vfs_pag_withdraw_token(struct vfs_token *vtoken);
+
+extern void vfs_token_put(struct vfs_token *vtoken);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_CRED_H */
diff -uNr linux-2.5.69/include/linux/fs.h linux-2.5.69-cred/include/linux/fs.h
--- linux-2.5.69/include/linux/fs.h	2003-05-13 11:02:22.000000000 +0100
+++ linux-2.5.69-cred/include/linux/fs.h	2003-05-13 11:02:35.000000000 +0100
@@ -430,6 +430,7 @@
 	mode_t			f_mode;
 	loff_t			f_pos;
 	struct fown_struct	f_owner;
+	struct vfs_token	*f_token;	/* governing credential */
 	unsigned int		f_uid, f_gid;
 	int			f_error;
 	struct file_ra_state	f_ra;
diff -uNr linux-2.5.69/include/linux/sched.h linux-2.5.69-cred/include/linux/sched.h
--- linux-2.5.69/include/linux/sched.h	2003-05-06 15:07:12.000000000 +0100
+++ linux-2.5.69-cred/include/linux/sched.h	2003-05-13 10:29:18.000000000 +0100
@@ -28,6 +28,7 @@
 #include <linux/completion.h>
 #include <linux/pid.h>
 #include <linux/percpu.h>
+#include <linux/cred.h>
 
 struct exec_domain;
 
@@ -387,6 +388,7 @@
 	gid_t gid,egid,sgid,fsgid;
 	int ngroups;
 	gid_t	groups[NGROUPS];
+	struct vfs_pag *vfspag;
 	kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 	int keep_capabilities:1;
 	struct user_struct *user;
diff -uNr linux-2.5.69/include/linux/types.h linux-2.5.69-cred/include/linux/types.h
--- linux-2.5.69/include/linux/types.h	2003-05-06 15:04:31.000000000 +0100
+++ linux-2.5.69-cred/include/linux/types.h	2003-05-12 10:19:08.000000000 +0100
@@ -24,6 +24,7 @@
 typedef __kernel_nlink_t	nlink_t;
 typedef __kernel_off_t		off_t;
 typedef __kernel_pid_t		pid_t;
+typedef __kernel_pag_t		pag_t;
 typedef __kernel_daddr_t	daddr_t;
 typedef __kernel_key_t		key_t;
 typedef __kernel_suseconds_t	suseconds_t;
diff -uNr linux-2.5.69/init/main.c linux-2.5.69-cred/init/main.c
--- linux-2.5.69/init/main.c	2003-05-06 15:07:12.000000000 +0100
+++ linux-2.5.69-cred/init/main.c	2003-05-13 14:08:11.000000000 +0100
@@ -80,6 +80,7 @@
 extern void pidhash_init(void);
 extern void pidmap_init(void);
 extern void pte_chain_init(void);
+extern void credentials_init(void);
 extern void radix_tree_init(void);
 extern void free_initmem(void);
 extern void populate_rootfs(void);
@@ -434,6 +435,7 @@
 	pidmap_init();
 	pgtable_cache_init();
 	pte_chain_init();
+	credentials_init();
 	fork_init(num_physpages);
 	proc_caches_init();
 	security_scaffolding_startup();
diff -uNr linux-2.5.69/kernel/cred.c linux-2.5.69-cred/kernel/cred.c
--- linux-2.5.69/kernel/cred.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.5.69-cred/kernel/cred.c	2003-05-13 13:21:06.000000000 +0100
@@ -0,0 +1,367 @@
+/* cred.c: authentication credentials management
+ *
+ * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+
+static kmem_cache_t *vfs_token_cache;
+static kmem_cache_t *vfs_pag_cache;
+
+static struct rb_root	vfs_pag_tree;
+static spinlock_t	vfs_pag_lock = SPIN_LOCK_UNLOCKED;
+static pag_t		vfs_pag_next = 1;
+
+static void vfs_pag_init_once(void *_vfspag, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct vfs_pag *vfspag = _vfspag;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) {
+		memset(vfspag,0,sizeof(*vfspag));
+		INIT_LIST_HEAD(&vfspag->tokens);
+		rwlock_init(&vfspag->lock);
+	}
+}
+
+static void vfs_token_init_once(void *_vtoken, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct vfs_token *vtoken = _vtoken;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) {
+		memset(vtoken,0,sizeof(*vtoken));
+		INIT_LIST_HEAD(&vtoken->link);
+	}
+}
+
+void __init credentials_init(void)
+{
+	vfs_pag_cache = kmem_cache_create("vfs_pag",
+					      sizeof(struct vfs_pag),
+					      0,
+					      SLAB_HWCACHE_ALIGN,
+					      vfs_pag_init_once, NULL);
+	if (!vfs_pag_cache)
+		panic("Cannot create vfs pag SLAB cache");
+
+	vfs_token_cache = kmem_cache_create("vfs_token",
+					    sizeof(struct vfs_token),
+					    0,
+					    SLAB_HWCACHE_ALIGN,
+					    vfs_token_init_once, NULL);
+	if (!vfs_token_cache)
+		panic("Cannot create vfs token SLAB cache");
+}
+
+/*****************************************************************************/
+/*
+ * join an existing PAG (+ve), run without PAG (0), or create and join new PAG (-1)
+ * - returns ID of PAG joined or 0 if now running without a PAG
+ */
+int sys_setpag(pag_t pag)
+{
+	struct task_struct *tsk = current;
+	struct vfs_pag *vfspag, *xvfspag;
+	struct rb_node **p, *parent;
+
+	if (pag>0) {
+		/* join existing PAG */
+		if (tsk->vfspag->pag &&
+		    tsk->vfspag->pag==pag)
+			return pag;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		spin_lock(&vfs_pag_lock);
+
+		parent = NULL;
+		p = &vfs_pag_tree.rb_node;
+
+		while (*p) {
+			parent = *p;
+			vfspag = rb_entry(parent,struct vfs_pag,node);
+
+			if (pag < vfspag->pag)
+				p = &(*p)->rb_left;
+			else if (pag > vfspag->pag)
+				p = &(*p)->rb_right;
+			else
+				goto pag_found;
+		}
+
+		spin_unlock(&vfs_pag_lock);
+		return -ENOENT;
+
+	pag_found:
+		xvfspag = xchg(&current->vfspag,vfs_pag_get(vfspag));
+		spin_unlock(&vfs_pag_lock);
+
+		if (xvfspag) vfs_pag_put(xvfspag);
+		return pag;
+	}
+	else if (pag==0) {
+		/* run without a PAG */
+		xvfspag = xchg(&current->vfspag,NULL);
+
+		if (xvfspag) vfs_pag_put(xvfspag);
+		return 0;
+	}
+	else if (pag!=-1) {
+		     return -EINVAL;
+	}
+
+	/* start new PAG */
+	vfspag = kmem_cache_alloc(vfs_pag_cache,SLAB_KERNEL);
+	if (!vfspag)
+		return -ENOMEM;
+
+	atomic_set(&vfspag->usage,1);
+
+	/* PAG IDs must be +ve, >0 and unique */
+	spin_lock(&vfs_pag_lock);
+
+	vfspag->pag = vfs_pag_next++;
+	if (vfspag->pag<1)
+		vfspag->pag = 1;
+
+	parent = NULL;
+	p = &vfs_pag_tree.rb_node;
+
+	while (*p) {
+		parent = *p;
+		xvfspag = rb_entry(parent,struct vfs_pag,node);
+
+		if (vfspag->pag < xvfspag->pag)
+			p = &(*p)->rb_left;
+		else if (vfspag->pag > xvfspag->pag)
+			p = &(*p)->rb_right;
+		else
+			goto pag_exists;
+	}
+	goto insert_here;
+
+	/* we found a PAG of the same ID - walk the tree from that point
+	 * looking for the next unused PAG */
+ pag_exists:
+	for (;;) {
+		vfspag->pag = vfs_pag_next++;
+		if (vfspag->pag<1)
+			vfspag->pag = 1;
+
+		if (!parent->rb_parent)
+			p = &vfs_pag_tree.rb_node;
+		else if (parent->rb_parent->rb_left==parent)
+			p = &parent->rb_parent->rb_left;
+		else
+			p = &parent->rb_parent->rb_right;
+
+		parent = rb_next(parent);
+		if (!parent)
+			break;
+
+		xvfspag = rb_entry(parent,struct vfs_pag,node);
+		if (vfspag->pag < xvfspag->pag)
+			goto insert_here;
+	}
+
+ insert_here:
+	rb_link_node(&vfspag->node,parent,p);
+	rb_insert_color(&vfspag->node,&vfs_pag_tree);
+	spin_unlock(&vfs_pag_lock);
+
+	xvfspag = xchg(&current->vfspag,vfspag);
+	if (xvfspag) vfs_pag_put(xvfspag);
+
+	return vfspag->pag;
+} /* end sys_setpag() */
+
+/*****************************************************************************/
+/*
+ * get the PAG of the current process, or 0 if it doesn't have one
+ */
+int sys_getpag(void)
+{
+	struct vfs_pag *vfspag = current->vfspag;
+
+	return vfspag ? vfspag->pag : 0;
+
+} /* end sys_getpag() */
+
+/*****************************************************************************/
+/*
+ * dispose of a VFS pag
+ */
+void vfs_pag_put(struct vfs_pag *vfspag)
+{
+	struct vfs_token *vtoken;
+
+	if (atomic_dec_and_lock(&vfspag->usage,&vfs_pag_lock)) {
+		rb_erase(&vfspag->node,&vfs_pag_tree);
+		spin_unlock(&vfs_pag_lock);
+
+		while (!list_empty(&vfspag->tokens)) {
+			vtoken = list_entry(vfspag->tokens.next,struct vfs_token,link);
+			list_del_init(&vtoken->link);
+			vfs_token_put(vtoken);
+		}
+
+		kmem_cache_free(vfs_pag_cache,vfspag);
+	}
+
+} /* end vfs_pag_put() */
+
+/*****************************************************************************/
+/*
+ * dispose of a VFS token
+ */
+void vfs_token_put(struct vfs_token *vtoken)
+{
+	if (atomic_dec_and_test(&vtoken->usage)) {
+		kfree(vtoken->blob);
+		kmem_cache_free(vfs_pag_cache,vtoken);
+	}
+
+} /* end vfs_token_put() */
+
+/*****************************************************************************/
+/*
+ * add an authentication token to a pag list
+ */
+int vfs_pag_add_token(const char *fsname,
+		      unsigned short klen,
+		      const void *key,
+		      size_t dlen,
+		      const void *data,
+		      struct vfs_token **_vtoken)
+{
+	struct vfs_token *vtoken;
+	struct vfs_pag *vfspag = current->vfspag;
+
+	*_vtoken = NULL;
+
+	if (!vfspag)
+		return -EACCES;
+
+	vtoken = kmem_cache_alloc(vfs_token_cache,SLAB_KERNEL);
+	if (!vtoken)
+		return -ENOMEM;
+
+	vtoken->k_off	= strlen(fsname) + 1;
+	vtoken->d_off	= vtoken->k_off + klen;
+	vtoken->size	= vtoken->d_off + dlen;
+
+	vtoken->blob = kmalloc(vtoken->size,SLAB_KERNEL);
+	if (!vtoken->blob) {
+		kfree(vtoken);
+		return -ENOMEM;
+	}
+
+	atomic_set(&vtoken->usage,1);
+
+	memcpy(vtoken->blob,fsname,vtoken->k_off);
+	memcpy(vtoken->blob+vtoken->k_off,key,klen);
+	memcpy(vtoken->blob+vtoken->d_off,key,dlen);
+
+	write_lock(&vfspag->lock);
+	list_add_tail(&vtoken->link,&vfspag->tokens);
+	write_unlock(&vfspag->lock);
+
+	*_vtoken = vtoken;
+	return 0;
+} /* end vfs_pag_add_token() */
+
+EXPORT_SYMBOL(vfs_pag_add_token);
+
+/*****************************************************************************/
+/*
+ * search for a token covering a particular filesystem key in the specified pag list
+ */
+struct vfs_token *vfs_pag_find_token(const char *fsname,
+				     unsigned short klen,
+				     const void *key)
+{
+	struct vfs_token *vtoken;
+	struct vfs_pag *vfspag = current->vfspag;
+
+	if (!vfspag) return NULL;
+
+	read_lock(&vfspag->lock);
+
+	list_for_each_entry(vtoken,&vfspag->tokens,link) {
+		if (vtoken->d_off-vtoken->k_off == klen &&
+		    strcmp(vtoken->blob,fsname)==0 &&
+		    memcmp(vtoken->blob+vtoken->k_off,key,klen)==0)
+			goto found;		    
+	}
+
+	read_unlock(&vfspag->lock);
+	return NULL;
+
+ found:
+	read_unlock(&vfspag->lock);
+	return vtoken;
+} /* end vfs_pag_find_token() */
+
+EXPORT_SYMBOL(vfs_pag_find_token);
+
+/*****************************************************************************/
+/*
+ * withdraw a token from a pag list
+ */
+void vfs_pag_withdraw_token(struct vfs_token *vtoken)
+{
+	struct vfs_pag *vfspag = current->vfspag;
+
+	if (!vfspag)
+		return;
+
+	write_lock(&vfspag->lock);
+	list_del_init(&vtoken->link);
+	write_unlock(&vfspag->lock);
+
+	vfs_token_put(vtoken);
+
+} /* end vfs_pag_withdraw_token() */
+
+EXPORT_SYMBOL(vfs_pag_withdraw_token);
+
+/*****************************************************************************/
+/*
+ * withdraw all tokens for the named filesystem from the current PAG
+ */
+void vfs_unpag(const char *fsname)
+{
+	struct list_head *_n, *_p;
+	struct vfs_token *vtoken;
+	struct vfs_pag *vfspag = current->vfspag;
+
+	if (!vfspag)
+		return;
+
+	write_lock(&vfspag->lock);
+
+	list_for_each_safe(_p,_n,&vfspag->tokens) {
+		vtoken = list_entry(_p,struct vfs_token,link);
+
+		if (strcmp(fsname,vtoken->blob)==0) {
+			list_del_init(&vtoken->link);
+			vfs_token_put(vtoken);
+		}
+	}
+
+	write_unlock(&vfspag->lock);
+
+} /* end vfs_unpag() */
diff -uNr linux-2.5.69/kernel/fork.c linux-2.5.69-cred/kernel/fork.c
--- linux-2.5.69/kernel/fork.c	2003-05-06 15:07:12.000000000 +0100
+++ linux-2.5.69-cred/kernel/fork.c	2003-05-13 10:39:37.000000000 +0100
@@ -884,6 +884,9 @@
 
 	if (clone_flags & CLONE_CHILD_SETTID)
 		p->set_child_tid = child_tidptr;
+
+	if (p->vfspag) vfs_pag_get(p->vfspag);
+
 	/*
 	 * Clear TID on mm_release()?
 	 */
diff -uNr linux-2.5.69/kernel/Makefile linux-2.5.69-cred/kernel/Makefile
--- linux-2.5.69/kernel/Makefile	2003-05-06 15:04:56.000000000 +0100
+++ linux-2.5.69-cred/kernel/Makefile	2003-05-13 10:45:27.000000000 +0100
@@ -3,7 +3,7 @@
 #
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
-	    exit.o itimer.o time.o softirq.o resource.o \
+	    cred.o exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o futex.o pid.o \
 	    rcupdate.o intermodule.o extable.o params.o posix-timers.o