
;
; Virtual Server Project
; Persistent Filesystem Context Info
;
; (C) 2003 Herbert Pötzl <herbert@13thfloor.at>
;
; Changelog:
;
;   0.03  - first public release
;   0.04  - adaptation to mq0.09
;         - generic set/get ioctl 
;         - UID32/GID16 support
;         - UID24/GID24 support
;         - ext3, jfs, and reiserfs added
;   0.05  - ctx_permission added
;         - bugfix in FIOC_* generic
;   0.06  - added MS_TAGXID flag/option
;   0.07  - adapted to vs1.1 devel branch
;         - changed internal nomenclature
;
; this patch 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.
;
; this patch is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;

diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/Documentation/Configure.help linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/Documentation/Configure.help
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/Documentation/Configure.help	Thu Nov 27 16:00:23 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/Documentation/Configure.help	Sat Nov 29 17:14:59 2003
@@ -13547,6 +13547,19 @@ CONFIG_VIOCD
   If you are running Linux on an IBM iSeries system and you want to
   read a CD drive owned by OS/400, say Y here.
 
+# Choice
+Persistent Context ID for files
+CONFIG_INOXID_NONE
+  Persistent Context IDs for your filesystem (ext2/ext3/jfs/reiser)
+  make it possible to do permission checks and per context quota,
+  which otherwise wouldn't be possible.
+
+  Disabled is the default (no context ids are stored on disc)
+  UID32/GID16 reduces GID to 16 bits, but leaves UID at 32
+  UID24/GID24 uses 8bit from UID and GID each for context id
+  UID32/GID32 uses otherwise reserved inode fields on disk
+              (only supported on ext2/ext3 for now)
+
 Quota support
 CONFIG_QUOTA
   If you say Y here, you will be able to set per user limits for disk
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/Config.in linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/Config.in
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/Config.in	Wed Nov 26 10:18:59 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/Config.in	Sat Nov 29 17:14:59 2003
@@ -4,6 +4,12 @@
 mainmenu_option next_comment
 comment 'File systems'
 
+choice 'Persistent Context ID for files'	\
+        "Disabled	CONFIG_INOXID_NONE	\
+         UID32/GID16	CONFIG_INOXID_GID16	\
+         UID24/GID24	CONFIG_INOXID_GID24	\
+         UID32/GID32	CONFIG_INOXID_GID32" Disabled
+
 bool 'Quota support' CONFIG_QUOTA
 dep_tristate '  VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA
 
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/attr.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/attr.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/attr.c	Mon Feb 25 20:38:07 2002
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/attr.c	Sat Nov 29 17:14:59 2003
@@ -143,6 +143,8 @@ int notify_change(struct dentry * dentry
 	unlock_kernel();
 	if (!error) {
 		unsigned long dn_mask = setattr_mask(ia_valid);
+
+		vx_dq_cond_modify(inode, current->vx_id);
 		if (dn_mask)
 			dnotify_parent(dentry, dn_mask);
 	}
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext2/inode.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext2/inode.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext2/inode.c	Thu Nov 27 16:00:23 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext2/inode.c	Sat Nov 29 17:14:59 2003
@@ -911,6 +911,8 @@ void ext2_read_inode (struct inode * ino
 	unsigned long block;
 	unsigned long offset;
 	struct ext2_group_desc * gdp;
+	uid_t uid;
+	gid_t gid;
 
 	if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
 	     inode->i_ino != EXT2_ACL_DATA_INO &&
@@ -953,12 +955,17 @@ void ext2_read_inode (struct inode * ino
 	raw_inode = (struct ext2_inode *) (bh->b_data + offset);
 
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
-	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
-	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+	uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+	gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
 	if(!(test_opt (inode->i_sb, NO_UID32))) {
-		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
-		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+		uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+		gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
+	inode->i_uid = INOXID_UID(uid, gid);
+	inode->i_gid = INOXID_GID(uid, gid);
+	if (inode->i_sb->s_flags & MS_TAGXID)
+		inode->i_xid = INOXID_XID(uid, gid, le16_to_cpu(raw_inode->i_raw_xid));
+
 	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime = le32_to_cpu(raw_inode->i_atime);
@@ -1040,6 +1047,8 @@ static int ext2_update_inode(struct inod
 	unsigned long offset;
 	int err = 0;
 	struct ext2_group_desc * gdp;
+	uid_t uid;
+	gid_t gid;
 
 	if ((inode->i_ino != EXT2_ROOT_INO &&
 	     inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
@@ -1079,27 +1088,33 @@ static int ext2_update_inode(struct inod
 	offset &= EXT2_BLOCK_SIZE(inode->i_sb) - 1;
 	raw_inode = (struct ext2_inode *) (bh->b_data + offset);
 
+	uid = XIDINO_UID(inode->i_uid, inode->i_xid);
+	gid = XIDINO_GID(inode->i_gid, inode->i_xid);
+
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
 	if(!(test_opt(inode->i_sb, NO_UID32))) {
-		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
-		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
+		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
 		if(!inode->u.ext2_i.i_dtime) {
-			raw_inode->i_uid_high = cpu_to_le16(high_16_bits(inode->i_uid));
-			raw_inode->i_gid_high = cpu_to_le16(high_16_bits(inode->i_gid));
+			raw_inode->i_uid_high = cpu_to_le16(high_16_bits(uid));
+			raw_inode->i_gid_high = cpu_to_le16(high_16_bits(gid));
 		} else {
 			raw_inode->i_uid_high = 0;
 			raw_inode->i_gid_high = 0;
 		}
 	} else {
-		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(inode->i_uid));
-		raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(inode->i_gid));
+		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(uid));
+		raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(gid));
 		raw_inode->i_uid_high = 0;
 		raw_inode->i_gid_high = 0;
 	}
+#ifdef CONFIG_INOXID_GID32	
+	raw_inode->i_raw_xid = cpu_to_le16(inode->i_xid);
+#endif
 	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
 	raw_inode->i_size = cpu_to_le32(inode->i_size);
 	raw_inode->i_atime = cpu_to_le32(inode->i_atime);
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext2/super.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext2/super.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext2/super.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext2/super.c	Sat Nov 29 17:14:59 2003
@@ -180,6 +180,10 @@ static int parse_options (char * options
 		else if (!strcmp (this_char, "nouid32")) {
 			set_opt (*mount_options, NO_UID32);
 		}
+		else if (!strcmp (this_char, "tagctx"))
+			set_opt (*mount_options, TAG_XID);
+		else if (!strcmp (this_char, "tagxid"))
+			set_opt (*mount_options, TAG_XID);
 		else if (!strcmp (this_char, "check")) {
 			if (!value || !*value || !strcmp (value, "none"))
 				clear_opt (*mount_options, CHECK);
@@ -428,6 +432,8 @@ struct super_block * ext2_read_super (st
 	    &sb->u.ext2_sb.s_mount_opt)) {
 		return NULL;
 	}
+	if (sb->u.ext2_sb.s_mount_opt & EXT2_MOUNT_TAG_XID)
+		sb->s_flags |= MS_TAGXID;
 
 	if (set_blocksize(dev, blocksize) < 0) {
 		printk ("EXT2-fs: unable to set blocksize %d\n", blocksize);
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext3/inode.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext3/inode.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext3/inode.c	Thu Nov 27 16:00:23 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext3/inode.c	Sat Nov 29 17:14:59 2003
@@ -2098,6 +2098,8 @@ void ext3_read_inode(struct inode * inod
 	struct ext3_inode *raw_inode;
 	struct buffer_head *bh;
 	int block;
+	uid_t uid;
+	gid_t gid;
 	
 	if(ext3_get_inode_loc(inode, &iloc))
 		goto bad_inode;
@@ -2105,12 +2107,17 @@ void ext3_read_inode(struct inode * inod
 	raw_inode = iloc.raw_inode;
 	init_rwsem(&inode->u.ext3_i.truncate_sem);
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
-	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
-	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+	uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+	gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
 	if(!(test_opt (inode->i_sb, NO_UID32))) {
-		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
-		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+		uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+		gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
+	inode->i_uid = INOXID_UID(uid, gid);
+	inode->i_gid = INOXID_GID(uid, gid);
+	if (inode->i_sb->s_flags & MS_TAGXID)
+		inode->i_xid = INOXID_XID(uid, gid, le16_to_cpu(raw_inode->i_raw_xid));
+	
 	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime = le32_to_cpu(raw_inode->i_atime);
@@ -2209,6 +2216,8 @@ static int ext3_do_update_inode(handle_t
 	struct ext3_inode *raw_inode = iloc->raw_inode;
 	struct buffer_head *bh = iloc->bh;
 	int err = 0, rc, block;
+	uid_t uid;
+	gid_t gid;
 
 	if (handle) {
 		BUFFER_TRACE(bh, "get_write_access");
@@ -2216,31 +2225,38 @@ static int ext3_do_update_inode(handle_t
 		if (err)
 			goto out_brelse;
 	}
+
+	uid = XIDINO_UID(inode->i_uid, inode->i_xid);
+	gid = XIDINO_GID(inode->i_gid, inode->i_xid);
+	
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
 	if(!(test_opt(inode->i_sb, NO_UID32))) {
-		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
-		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
+		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
 		if(!inode->u.ext3_i.i_dtime) {
 			raw_inode->i_uid_high =
-				cpu_to_le16(high_16_bits(inode->i_uid));
+				cpu_to_le16(high_16_bits(uid));
 			raw_inode->i_gid_high =
-				cpu_to_le16(high_16_bits(inode->i_gid));
+				cpu_to_le16(high_16_bits(gid));
 		} else {
 			raw_inode->i_uid_high = 0;
 			raw_inode->i_gid_high = 0;
 		}
 	} else {
 		raw_inode->i_uid_low =
-			cpu_to_le16(fs_high2lowuid(inode->i_uid));
+			cpu_to_le16(fs_high2lowuid(uid));
 		raw_inode->i_gid_low =
-			cpu_to_le16(fs_high2lowgid(inode->i_gid));
+			cpu_to_le16(fs_high2lowgid(gid));
 		raw_inode->i_uid_high = 0;
 		raw_inode->i_gid_high = 0;
 	}
+#ifdef CONFIG_INOXID_GID32
+        raw_inode->i_raw_xid = cpu_to_le16(inode->i_xid);
+#endif
 	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
 	raw_inode->i_size = cpu_to_le32(inode->u.ext3_i.i_disksize);
 	raw_inode->i_atime = cpu_to_le32(inode->i_atime);
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext3/ioctl.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext3/ioctl.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext3/ioctl.c	Thu Nov 27 16:00:23 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext3/ioctl.c	Sat Nov 29 17:14:59 2003
@@ -149,6 +149,38 @@ flags_err:
 			return ret;
 		}
 #endif
+#ifndef CONFIG_INOXID_NONE
+	case EXT3_IOC_SETXID: {
+		handle_t *handle;
+		struct ext3_iloc iloc;
+		int ctx;
+		int err;
+
+		/* fixme: if stealth, return -ENOTTY */
+		if (!capable(CAP_CONTEXT))
+			return -EPERM;
+		if (IS_RDONLY(inode))
+			return -EROFS;
+		if (!(inode->i_sb->s_flags & MS_TAGXID))
+			return -ENOSYS;
+		if (get_user(ctx, (int *) arg))
+			return -EFAULT;	
+
+		handle = ext3_journal_start(inode, 1);
+		if (IS_ERR(handle))
+			return PTR_ERR(handle);
+		err = ext3_reserve_inode_write(handle, inode, &iloc);
+		if (err)
+			return err;
+
+		inode->i_xid = (ctx & 0xFFFF);
+		inode->i_ctime = CURRENT_TIME;
+
+		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
+		ext3_journal_stop(handle, inode);
+		return err;
+	}
+#endif
 	default:
 		return -ENOTTY;
 	}
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext3/super.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext3/super.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ext3/super.c	Sat Nov 29 17:13:22 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ext3/super.c	Sat Nov 29 17:14:59 2003
@@ -522,6 +522,8 @@ static int parse_options (char * options
 		else if (!strcmp (this_char, "nouid32")) {
 			set_opt (*mount_options, NO_UID32);
 		}
+		else if (!strcmp (this_char, "tagctx"))
+			set_opt (*mount_options, TAG_XID);
 		else if (!strcmp (this_char, "abort"))
 			set_opt (*mount_options, ABORT);
 		else if (!strcmp (this_char, "check")) {
@@ -935,6 +937,8 @@ struct super_block * ext3_read_super (st
 		sb->s_dev = 0;
 		goto out_fail;
 	}
+	if (sbi->s_mount_opt & EXT3_MOUNT_TAG_XID)
+		sb->s_flags |= MS_TAGXID;
 
 	sb->s_blocksize = blocksize;
 	set_blocksize (dev, blocksize);
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/inode.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/inode.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/inode.c	Sat Nov 29 17:13:22 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/inode.c	Sat Nov 29 17:14:59 2003
@@ -95,6 +95,8 @@ static struct inode *alloc_inode(struct 
 		struct address_space * const mapping = &inode->i_data;
 
 		inode->i_sb = sb;
+		if (sb->s_flags & MS_TAGXID)
+			inode->i_xid = current->vx_id;
 		inode->i_dqh = dqhget(sb->s_dqh);
 		inode->i_dev = sb->s_dev;
 		inode->i_blkbits = sb->s_blocksize_bits;
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ioctl.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ioctl.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/ioctl.c	Mon Aug 25 13:44:43 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/ioctl.c	Sat Nov 29 17:14:59 2003
@@ -111,6 +111,40 @@ asmlinkage long sys_ioctl(unsigned int f
 			else
 				error = -ENOTTY;
 			break;
+#ifndef CONFIG_INOXID_NONE
+		case FIOC_GETXID: {
+			struct inode *inode = filp->f_dentry->d_inode;
+
+			/* fixme: if stealth, return -ENOTTY */
+			error = -EPERM;
+			if (capable(CAP_CONTEXT))
+				error = put_user(inode->i_xid, (int *) arg);
+			break;
+		}
+		case FIOC_SETXID: {
+			struct inode *inode = filp->f_dentry->d_inode;
+			int ctx;
+
+			/* fixme: if stealth, return -ENOTTY */
+			error = -EPERM;
+			if (!capable(CAP_CONTEXT))
+				break;
+			error = -EROFS;
+			if (IS_RDONLY(inode))
+				break;
+			error = -ENOSYS;
+			if (!(inode->i_sb->s_flags & MS_TAGXID))
+				break;
+			error = -EFAULT;
+			if (get_user(ctx, (int *) arg))
+				break;
+			error = 0;
+			inode->i_xid = (ctx & 0xFFFF);
+			inode->i_ctime = CURRENT_TIME;
+			mark_inode_dirty(inode);
+			break;	
+		}
+#endif
 		default:
 			error = -ENOTTY;
 			if (S_ISREG(filp->f_dentry->d_inode->i_mode))
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/jfs/jfs_imap.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/jfs/jfs_imap.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/jfs/jfs_imap.c	Wed Nov 26 10:18:59 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/jfs/jfs_imap.c	Sat Nov 29 17:14:59 2003
@@ -3101,14 +3101,21 @@ static void duplicateIXtree(struct super
 static int copy_from_dinode(struct dinode * dip, struct inode *ip)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	uid_t uid;
+	gid_t gid;
 
 	jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
 	jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
 
 	ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
 	ip->i_nlink = le32_to_cpu(dip->di_nlink);
-	ip->i_uid = le32_to_cpu(dip->di_uid);
-	ip->i_gid = le32_to_cpu(dip->di_gid);
+
+	uid = le32_to_cpu(dip->di_uid);
+	gid = le32_to_cpu(dip->di_gid);
+	ip->i_uid = INOXID_UID(uid, gid);
+	ip->i_gid = INOXID_GID(uid, gid);
+	ip->i_xid = INOXID_XID(uid, gid, 0);
+	
 	ip->i_size = le64_to_cpu(dip->di_size);
 	ip->i_atime = le32_to_cpu(dip->di_atime.tv_sec);
 	ip->i_mtime = le32_to_cpu(dip->di_mtime.tv_sec);
@@ -3154,6 +3161,8 @@ static int copy_from_dinode(struct dinod
 static void copy_to_dinode(struct dinode * dip, struct inode *ip)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	uid_t uid;
+	gid_t gid;
 
 	dip->di_fileset = cpu_to_le32(jfs_ip->fileset);
 	dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp);
@@ -3162,8 +3171,11 @@ static void copy_to_dinode(struct dinode
 	dip->di_size = cpu_to_le64(ip->i_size);
 	dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks));
 	dip->di_nlink = cpu_to_le32(ip->i_nlink);
-	dip->di_uid = cpu_to_le32(ip->i_uid);
-	dip->di_gid = cpu_to_le32(ip->i_gid);
+
+	uid = XIDINO_UID(ip->i_uid, ip->i_xid);
+	gid = XIDINO_GID(ip->i_gid, ip->i_xid);
+	dip->di_uid = cpu_to_le32(uid);
+	dip->di_gid = cpu_to_le32(gid);
 	/*
 	 * mode2 is only needed for storing the higher order bits.
 	 * Trust i_mode for the lower order ones
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/namei.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/namei.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/namei.c	Thu Nov 27 16:00:23 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/namei.c	Sat Nov 29 17:14:59 2003
@@ -206,10 +206,22 @@ int vfs_permission(struct inode * inode,
 	return -EACCES;
 }
 
+static inline int ctx_permission(struct inode *inode, int ctx)
+{
+	if ((ctx == 0) || (ctx == 1))
+		return 0;
+	if ((inode->i_xid == 0) || (inode->i_xid == ctx))
+		return 0;
+	return -EACCES;
+}
+
 int permission(struct inode * inode,int mask)
 {
+	int retval = 0;
+
+	if ((retval = ctx_permission(inode, current->vx_id)))
+		return retval;
 	if (inode->i_op && inode->i_op->permission) {
-		int retval;
 		lock_kernel();
 		retval = inode->i_op->permission(inode, mask);
 		unlock_kernel();
@@ -1057,6 +1069,7 @@ do_last:
 
 	/* Negative dentry, just create the file */
 	if (!dentry->d_inode) {
+		vx_dq_cond_modify(dir->d_inode, current->vx_id);
 		error = vfs_create(dir->d_inode, dentry,
 				   mode & ~current->fs->umask);
 		up(&dir->d_inode->i_sem);
@@ -1114,6 +1127,9 @@ ok:
 	if (error)
 		goto exit;
 
+	if ((flag & FMODE_WRITE) || (flag & O_TRUNC))
+		vx_dq_cond_modify(inode, current->vx_id);
+
 	/*
 	 * FIFO's, sockets and device files are special: they don't
 	 * actually live on the filesystem itself, and as such you
@@ -1129,7 +1145,7 @@ ok:
 		flag &= ~O_TRUNC;
 	} else {
 		error = -EROFS;
-		if (IS_RDONLY(inode) && (flag & 2))
+		if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
 			goto exit;
 	}
 	/*
@@ -1492,6 +1508,8 @@ int vfs_unlink(struct inode *dir, struct
 			else {
 				lock_kernel();
 				error = dir->i_op->unlink(dir, dentry);
+				if (!error)
+					vx_dq_unlink(dentry->d_inode);
 				unlock_kernel();
 				if (!error)
 					d_delete(dentry);
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/open.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/open.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/open.c	Thu Nov 27 16:00:23 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/open.c	Sat Nov 29 17:14:59 2003
@@ -547,6 +547,10 @@ static int chown_common(struct dentry * 
 		user = inode->i_uid;
 	if (group == (gid_t) -1)
 		group = inode->i_gid;
+
+	if ((user > MAX_UID) || (group > MAX_GID))
+		goto out;
+	
 	newattrs.ia_mode = inode->i_mode;
 	newattrs.ia_uid = user;
 	newattrs.ia_gid = group;
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/reiserfs/inode.c linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/reiserfs/inode.c
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/fs/reiserfs/inode.c	Thu Nov 27 16:00:23 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/fs/reiserfs/inode.c	Sat Nov 29 17:14:59 2003
@@ -978,12 +978,19 @@ static void init_inode (struct inode * i
 	// new stat data found, but object may have old items
 	// (directories and symlinks)
 	struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih);
+	uid_t uid;
+	gid_t gid;
 
 	inode->i_mode   = sd_v2_mode(sd);
 	inode->i_nlink  = sd_v2_nlink(sd);
-	inode->i_uid    = sd_v2_uid(sd);
+
+	uid = sd_v2_uid(sd);
+	gid = sd_v2_gid(sd);
+	inode->i_uid    = INOXID_UID(uid, gid);
+	inode->i_gid    = INOXID_GID(uid, gid);
+	inode->i_xid	= INOXID_XID(uid, gid, 0);
+
 	inode->i_size   = sd_v2_size(sd);
-	inode->i_gid    = sd_v2_gid(sd);
 	inode->i_mtime  = sd_v2_mtime(sd);
 	inode->i_atime  = sd_v2_atime(sd);
 	inode->i_ctime  = sd_v2_ctime(sd);
@@ -1030,12 +1037,18 @@ static void inode2sd (void * sd, struct 
 {
     struct stat_data * sd_v2 = (struct stat_data *)sd;
     __u16 flags;
+    uid_t uid;
+    gid_t gid;
 
     set_sd_v2_mode(sd_v2, inode->i_mode );
     set_sd_v2_nlink(sd_v2, inode->i_nlink );
-    set_sd_v2_uid(sd_v2, inode->i_uid );
+
+    uid = XIDINO_UID(inode->i_uid, inode->i_xid);
+    gid = XIDINO_GID(inode->i_gid, inode->i_xid);
+    set_sd_v2_uid(sd_v2, uid );
+    set_sd_v2_gid(sd_v2, gid );
+
     set_sd_v2_size(sd_v2, inode->i_size );
-    set_sd_v2_gid(sd_v2, inode->i_gid );
     set_sd_v2_mtime(sd_v2, inode->i_mtime );
     set_sd_v2_atime(sd_v2, inode->i_atime );
     set_sd_v2_ctime(sd_v2, inode->i_ctime );
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/capability.h linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/capability.h
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/capability.h	Thu Nov 27 16:00:48 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/capability.h	Sat Nov 29 17:19:45 2003
@@ -285,6 +285,11 @@ typedef __u32 kernel_cap_t;
 
 #define CAP_QUOTACTL         29
 
+/* Allow context manipulations */
+/* Allow changing context info on files */
+
+#define CAP_CONTEXT          30
+
 #ifdef __KERNEL__
 /* 
  * Bounding set
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/ext2_fs.h linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/ext2_fs.h
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/ext2_fs.h	Thu Nov 27 16:01:59 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/ext2_fs.h	Sat Nov 29 17:20:58 2003
@@ -247,7 +247,7 @@ struct ext2_inode {
 		struct {
 			__u8	l_i_frag;	/* Fragment number */
 			__u8	l_i_fsize;	/* Fragment size */
-			__u16	i_pad1;
+			__u16	l_i_xid;	/* LRU Context */
 			__u16	l_i_uid_high;	/* these 2 fields    */
 			__u16	l_i_gid_high;	/* were reserved2[0] */
 			__u32	l_i_reserved2;
@@ -279,6 +279,7 @@ struct ext2_inode {
 #define i_gid_low	i_gid
 #define i_uid_high	osd2.linux2.l_i_uid_high
 #define i_gid_high	osd2.linux2.l_i_gid_high
+#define i_raw_xid	osd2.linux2.l_i_xid
 #define i_reserved2	osd2.linux2.l_i_reserved2
 #endif
 
@@ -315,6 +316,7 @@ struct ext2_inode {
 #define EXT2_MOUNT_ERRORS_PANIC		0x0040	/* Panic on errors */
 #define EXT2_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */
 #define EXT2_MOUNT_NO_UID32		0x0200  /* Disable 32-bit UIDs */
+#define EXT2_MOUNT_TAG_XID		0x4000  /* Enable Context Tags */
 
 #define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt
 #define set_opt(o, opt)			o |= EXT2_MOUNT_##opt
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/ext3_fs.h linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/ext3_fs.h
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/ext3_fs.h	Thu Nov 27 16:02:06 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/ext3_fs.h	Sat Nov 29 17:21:05 2003
@@ -227,6 +227,7 @@ struct ext3_group_desc
 #ifdef CONFIG_JBD_DEBUG
 #define EXT3_IOC_WAIT_FOR_READONLY	_IOR('f', 99, long)
 #endif
+#define	EXT3_IOC_SETXID		FIOC_SETXIDJ
 
 /*
  * Structure of an inode on the disk
@@ -263,7 +264,7 @@ struct ext3_inode {
 		struct {
 			__u8	l_i_frag;	/* Fragment number */
 			__u8	l_i_fsize;	/* Fragment size */
-			__u16	i_pad1;
+			__u16	l_i_xid;	/* LRU Context */
 			__u16	l_i_uid_high;	/* these 2 fields    */
 			__u16	l_i_gid_high;	/* were reserved2[0] */
 			__u32	l_i_reserved2;
@@ -295,6 +296,7 @@ struct ext3_inode {
 #define i_gid_low	i_gid
 #define i_uid_high	osd2.linux2.l_i_uid_high
 #define i_gid_high	osd2.linux2.l_i_gid_high
+#define i_raw_xid	osd2.linux2.l_i_xid
 #define i_reserved2	osd2.linux2.l_i_reserved2
 
 #elif defined(__GNU__)
@@ -340,6 +342,7 @@ struct ext3_inode {
   #define EXT3_MOUNT_WRITEBACK_DATA	0x0C00	/* No data ordering */
 #define EXT3_MOUNT_UPDATE_JOURNAL	0x1000	/* Update the journal format */
 #define EXT3_MOUNT_NO_UID32		0x2000  /* Disable 32-bit UIDs */
+#define EXT3_MOUNT_TAG_XID		0x4000  /* Enable Context Tags */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/fs.h linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/fs.h
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/fs.h	Sat Nov 29 17:13:22 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/fs.h	Sat Nov 29 17:14:59 2003
@@ -21,6 +21,7 @@
 #include <linux/cache.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/vxid.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
@@ -111,6 +112,7 @@ extern int leases_enable, dir_notify_ena
 #define MS_MOVE		8192
 #define MS_REC		16384
 #define MS_VERBOSE	32768
+#define MS_TAGXID	(1<<24)	/* tag inodes with context information */
 #define MS_ACTIVE	(1<<30)
 #define MS_NOUSER	(1<<31)
 
@@ -482,6 +484,7 @@ struct inode {
 	struct block_device	*i_bdev;
 	struct char_device	*i_cdev;
 
+	unsigned int		i_xid;          /* LRU Context */
 	unsigned long		i_dnotify_mask; /* Directory notify events */
 	struct dnotify_struct	*i_dnotify; /* for directory notifications */
 
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/quotaops.h linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/quotaops.h
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/quotaops.h	Sat Nov 29 17:13:22 2003
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/quotaops.h	Sat Nov 29 17:14:59 2003
@@ -36,6 +36,37 @@ extern void dquot_free_inode(const struc
 
 extern int  dquot_transfer(struct inode *inode, struct iattr *iattr);
 
+
+static __inline__ void vx_dq_modify(struct inode *inode, unsigned int ctx)
+{
+	if (!(inode->i_sb->s_flags & MS_TAGXID))
+		return;
+	dprintk("··· vx_dq_modify: %p #%d -> #%d\n", inode, inode->i_xid, ctx);
+	inode->i_xid = ctx;
+	mark_inode_dirty(inode);
+}
+
+static __inline__ void vx_dq_cond_modify(struct inode *inode, unsigned int ctx)
+{
+	if (inode->i_xid != ctx)
+		vx_dq_modify(inode, ctx);
+}
+
+static __inline__ void vx_dq_unlink(struct inode *inode)
+{
+	if (inode->i_nlink == 0)
+		return;
+	/* inode from other context? */
+	if (inode->i_xid != current->vx_id)
+		return;
+	/* inode still referenced ... */
+	if (inode->i_xid == 0)
+		return;
+	/* transfer back to ctx zero hash */
+	vx_dq_modify(inode, 0);
+}
+
+
 /*
  * Operations supported for diskquotas.
  */
@@ -45,11 +76,14 @@ extern struct quotactl_ops vfs_quotactl_
 #define sb_dquot_ops (&dquot_operations)
 #define sb_quotactl_ops (&vfs_quotactl_ops)
 
+#define CHECK_DQHASH(inode)			do { } while(0)
+
 static __inline__ void DQUOT_INIT(struct inode *inode)
 {
 	if (!inode->i_sb)
 		out_of_line_bug();
 	lock_kernel();
+	CHECK_DQHASH(inode);
 	if (!dqhash_valid(inode->i_dqh))
 		goto out;
 	if (dqh_any_quota_enabled(inode->i_dqh) && !IS_NOQUOTA(inode))
@@ -72,6 +106,7 @@ static __inline__ void DQUOT_DROP(struct
 static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
+	CHECK_DQHASH(inode);
 	if (dqh_any_quota_enabled(inode->i_dqh)) {
 		/* Used space is updated in alloc_space() */
 		if (inode->i_dqh->dqh_qop->alloc_space(inode, nr, 1) == NO_QUOTA) {
@@ -96,6 +131,7 @@ static __inline__ int DQUOT_PREALLOC_SPA
 static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
+	CHECK_DQHASH(inode);
 	if (dqh_any_quota_enabled(inode->i_dqh)) {
 		/* Used space is updated in alloc_space() */
 		if (inode->i_dqh->dqh_qop->alloc_space(inode, nr, 0) == NO_QUOTA) {
@@ -120,6 +156,7 @@ static __inline__ int DQUOT_ALLOC_SPACE(
 static __inline__ int DQUOT_ALLOC_INODE(struct inode *inode)
 {
 	lock_kernel();
+	CHECK_DQHASH(inode);
 	if (dqh_any_quota_enabled(inode->i_dqh)) {
 		DQUOT_INIT(inode);
 		if (inode->i_dqh->dqh_qop->alloc_inode(inode, 1) == NO_QUOTA) {
@@ -199,6 +236,12 @@ static __inline__ int DQUOT_OFF(struct d
 #define DQUOT_SYNC_DQH(hash)			do { } while(0)
 #define DQUOT_OFF(hash)				do { } while(0)
 #define DQUOT_TRANSFER(inode, iattr)		(0)
+
+#define vx_dq_modify(inode, ctx)		do { } while(0)
+#define vx_dq_cond_modify(inode, ctx)		do { } while(0)
+#define vx_dq_unlink(inode)			do { } while(0)
+
+#define CHECK_DQHASH(inode)			do { } while(0)
 
 extern __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
diff -NurpP --minimal linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/vxid.h linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/vxid.h
--- linux-2.4.23-rc5-vs1.1.6-qh0.12/include/linux/vxid.h	Thu Jan  1 01:00:00 1970
+++ linux-2.4.23-rc5-vs1.1.6-qh0.12-cx0.07/include/linux/vxid.h	Sat Nov 29 17:19:45 2003
@@ -0,0 +1,64 @@
+#ifndef _LINUX_VXID_H_
+#define _LINUX_VXID_H_
+
+#ifdef CONFIG_INOXID_NONE
+
+#define	INOXID_UID(uid, gid)		(uid)
+#define	INOXID_GID(uid, gid)		(gid)
+#define	INOXID_XID(uid, gid, ctx)	(0)
+
+#define	XIDINO_UID(uid, ctx)		(uid)
+#define	XIDINO_GID(gid, ctx)		(gid)
+
+#define	MAX_UID		0xFFFFFFFF
+#define	MAX_GID		0xFFFFFFFF
+
+#endif
+
+#ifdef CONFIG_INOXID_GID16
+
+#define	INOXID_UID(uid, gid)		(uid)
+#define	INOXID_GID(uid, gid)		((gid) & 0xFFFF)
+#define	INOXID_XID(uid, gid, ctx)	(((gid) >> 16) & 0xFFFF)
+
+#define	XIDINO_UID(uid, ctx)		(uid)
+#define	XIDINO_GID(gid, ctx)		(((gid) & 0xFFFF) | ((ctx) << 16))
+
+#define	MAX_UID		0xFFFFFFFF
+#define	MAX_GID		0x0000FFFF
+
+#endif
+
+#ifdef CONFIG_INOXID_GID24
+
+#define	INOXID_UID(uid, gid)		((uid) & 0xFFFFFF)
+#define	INOXID_GID(uid, gid)		((gid) & 0xFFFFFF)
+#define	INOXID_XID(uid, gid, ctx)	((((uid) >> 16) & 0xFF00) | (((gid) >> 24) & 0xFF))
+
+#define	XIDINO_UID(uid, ctx)		(((uid) & 0xFFFFFF) | (((ctx) & 0xFF00) << 16))
+#define	XIDINO_GID(gid, ctx)		(((gid) & 0xFFFFFF) | (((ctx) & 0x00FF) << 24))
+
+#define	MAX_UID		0x00FFFFFF
+#define	MAX_GID		0x00FFFFFF
+
+#endif
+
+#ifdef CONFIG_INOXID_GID32
+
+#define	INOXID_UID(uid, gid)		(uid)
+#define	INOXID_GID(uid, gid)		(gid)
+#define	INOXID_XID(uid, gid, ctx)	(ctx)
+
+#define	XIDINO_UID(uid, ctx)		(uid)
+#define	XIDINO_GID(gid, ctx)		(gid)
+
+#define	MAX_UID		0xFFFFFFFF
+#define	MAX_GID		0xFFFFFFFF
+
+#endif
+
+#define	FIOC_GETXID	_IOR('x', 1, long)
+#define	FIOC_SETXID	_IOW('x', 2, long)
+#define	FIOC_SETXIDJ	_IOW('x', 3, long)
+
+#endif
