From: viro@www.linux.org.uk

beginning of fs side work:

* new superblock method - ->valid_dev(dev) that checks if particular
  dev_t value is OK for device inodes on that fs.  We don't even try to
  call ->mknod() if that check fails.  Invariant: for any device inode we
  expect inode->i_sb->s_op->valid_dev(inode->i_rdev) to be true.

* helpers for that method - simple_valid_dev() and old_valid_dev().  The
  former is "everything goes" (ramfs et.al.), the latter is "major and
  minor are below 256" (i.e.  what filesystem should use if it doesn't want
  to deal with new dev_t values).

* super_operations instances updated

* new helpers: old_encode_dev() and old_decode_dev().  dev_t -> u16 and
  u16 -> dev_t resp; currently these are no-ops, places that use current
  formar (minor in bits 0--7, major in bits 8--15) will switch to these
  before we widen dev_t.  They are supposed to be used by filesystems that
  have old_valid_dev() as ->valid_dev(); when/if a filesystem switches to
  wider on-disk dev_t representation it should change its ->valid_dev()
  along with encoding.



 arch/ia64/sn/io/hwgfs/ramfs.c |    1 +
 fs/cifs/cifsfs.c              |    1 +
 fs/coda/inode.c               |    1 +
 fs/devfs/base.c               |    1 +
 fs/ext2/super.c               |    1 +
 fs/ext3/super.c               |    1 +
 fs/hpfs/super.c               |    1 +
 fs/hugetlbfs/inode.c          |    1 +
 fs/intermezzo/inode.c         |    1 +
 fs/intermezzo/vfs.c           |    6 +++++-
 fs/jffs/inode-v23.c           |    1 +
 fs/jffs2/super.c              |    3 ++-
 fs/jfs/super.c                |    1 +
 fs/libfs.c                    |   27 +++++++++++++++++++++++++++
 fs/minix/inode.c              |    1 +
 fs/namei.c                    |    5 ++++-
 fs/ncpfs/inode.c              |    1 +
 fs/nfs/inode.c                |    1 +
 fs/ramfs/inode.c              |    1 +
 fs/reiserfs/super.c           |    2 +-
 fs/smbfs/inode.c              |    1 +
 fs/sysv/inode.c               |    1 +
 fs/udf/super.c                |    1 +
 fs/ufs/super.c                |    1 +
 fs/xfs/linux/xfs_super.c      |    1 +
 include/linux/fs.h            |    6 +++++-
 mm/shmem.c                    |    1 +
 27 files changed, 65 insertions(+), 5 deletions(-)

diff -puN arch/ia64/sn/io/hwgfs/ramfs.c~large-dev_t-2nd-09 arch/ia64/sn/io/hwgfs/ramfs.c
--- 25/arch/ia64/sn/io/hwgfs/ramfs.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/arch/ia64/sn/io/hwgfs/ramfs.c	2003-09-05 00:50:05.000000000 -0700
@@ -164,6 +164,7 @@ static struct inode_operations hwgfs_dir
 static struct super_operations hwgfs_ops = {
 	.statfs		= simple_statfs,
 	.drop_inode	= generic_delete_inode,
+	.valid_dev	= old_valid_dev,
 };
 
 static int hwgfs_fill_super(struct super_block * sb, void * data, int silent)
diff -puN fs/cifs/cifsfs.c~large-dev_t-2nd-09 fs/cifs/cifsfs.c
--- 25/fs/cifs/cifsfs.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/cifs/cifsfs.c	2003-09-05 00:50:05.000000000 -0700
@@ -370,6 +370,7 @@ struct super_operations cifs_super_ops =
    us with the same number of releases (closes) as opens */
 	.show_options = cifs_show_options,
 /*    .umount_begin   = cifs_umount_begin, *//* consider adding in the future */
+	.valid_dev = old_valid_dev,
 };
 
 static struct super_block *
diff -puN fs/coda/inode.c~large-dev_t-2nd-09 fs/coda/inode.c
--- 25/fs/coda/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/coda/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -91,6 +91,7 @@ struct super_operations coda_super_opera
 	.clear_inode	= coda_clear_inode,
 	.put_super	= coda_put_super,
 	.statfs		= coda_statfs,
+	.valid_dev	= old_valid_dev,
 };
 
 static int get_device_index(struct coda_mount_data *data)
diff -puN fs/devfs/base.c~large-dev_t-2nd-09 fs/devfs/base.c
--- 25/fs/devfs/base.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/devfs/base.c	2003-09-05 00:50:05.000000000 -0700
@@ -1965,6 +1965,7 @@ static struct super_operations devfs_sop
     .drop_inode    = generic_delete_inode,
     .clear_inode   = devfs_clear_inode,
     .statfs        = simple_statfs,
+    .valid_dev	   = simple_valid_dev,
 };
 
 
diff -puN fs/ext2/super.c~large-dev_t-2nd-09 fs/ext2/super.c
--- 25/fs/ext2/super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/ext2/super.c	2003-09-05 00:50:05.000000000 -0700
@@ -233,6 +233,7 @@ static struct super_operations ext2_sops
 	.statfs		= ext2_statfs,
 	.remount_fs	= ext2_remount,
 	.clear_inode	= ext2_clear_inode,
+	.valid_dev	= old_valid_dev,
 };
 
 /* Yes, most of these are left as NULL!!
diff -puN fs/ext3/super.c~large-dev_t-2nd-09 fs/ext3/super.c
--- 25/fs/ext3/super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/ext3/super.c	2003-09-05 00:50:05.000000000 -0700
@@ -582,6 +582,7 @@ static struct super_operations ext3_sops
 	.statfs		= ext3_statfs,
 	.remount_fs	= ext3_remount,
 	.clear_inode	= ext3_clear_inode,
+	.valid_dev	= old_valid_dev,
 };
 
 struct dentry *ext3_get_parent(struct dentry *child);
diff -puN fs/hpfs/super.c~large-dev_t-2nd-09 fs/hpfs/super.c
--- 25/fs/hpfs/super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/hpfs/super.c	2003-09-05 00:50:05.000000000 -0700
@@ -215,6 +215,7 @@ static struct super_operations hpfs_sops
 	.put_super	= hpfs_put_super,
 	.statfs		= hpfs_statfs,
 	.remount_fs	= hpfs_remount_fs,
+	.valid_dev	= old_valid_dev,
 };
 
 /*
diff -puN fs/hugetlbfs/inode.c~large-dev_t-2nd-09 fs/hugetlbfs/inode.c
--- 25/fs/hugetlbfs/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/hugetlbfs/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -617,6 +617,7 @@ static struct super_operations hugetlbfs
 	.statfs		= hugetlbfs_statfs,
 	.drop_inode	= hugetlbfs_drop_inode,
 	.put_super	= hugetlbfs_put_super,
+	.valid_dev	= simple_valid_dev,
 };
 
 static int
diff -puN fs/intermezzo/inode.c~large-dev_t-2nd-09 fs/intermezzo/inode.c
--- 25/fs/intermezzo/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/intermezzo/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -174,6 +174,7 @@ exit:
 struct super_operations presto_super_ops = {
         .read_inode    = presto_read_inode,
         .put_super     = presto_put_super,
+	.valid_dev     = old_valid_dev,
 };
 
 
diff -puN fs/intermezzo/vfs.c~large-dev_t-2nd-09 fs/intermezzo/vfs.c
--- 25/fs/intermezzo/vfs.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/intermezzo/vfs.c	2003-09-05 00:50:05.000000000 -0700
@@ -1584,7 +1584,11 @@ int presto_do_mknod(struct presto_file_s
                 goto exit_lock2;
         }
 
-        error = iops->mknod(dir->d_inode, dentry, mode, dev);
+	if (!dir->d_inode->i_sb->s_op->valid_dev ||
+	    !dir->d_inode->i_sb->s_op->valid_dev(dev))
+		error = -EINVAL;
+	else
+		error = iops->mknod(dir->d_inode, dentry, mode, dev);
         if (error) {
                 EXIT;
                 goto exit_commit;
diff -puN fs/jffs2/super.c~large-dev_t-2nd-09 fs/jffs2/super.c
--- 25/fs/jffs2/super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/jffs2/super.c	2003-09-05 00:50:05.000000000 -0700
@@ -66,7 +66,8 @@ static struct super_operations jffs2_sup
 	.write_super =	jffs2_write_super,
 	.statfs =	jffs2_statfs,
 	.remount_fs =	jffs2_remount_fs,
-	.clear_inode =	jffs2_clear_inode
+	.clear_inode =	jffs2_clear_inode,
+	.valid_dev =	old_valid_dev,
 };
 
 static int jffs2_sb_compare(struct super_block *sb, void *data)
diff -puN fs/jffs/inode-v23.c~large-dev_t-2nd-09 fs/jffs/inode-v23.c
--- 25/fs/jffs/inode-v23.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/jffs/inode-v23.c	2003-09-05 00:50:05.000000000 -0700
@@ -1783,6 +1783,7 @@ static struct super_operations jffs_ops 
 	.put_super	= jffs_put_super,
 	.write_super	= jffs_write_super,
 	.statfs		= jffs_statfs,
+	.valid_dev	= old_valid_dev,
 };
 
 static struct super_block *jffs_get_sb(struct file_system_type *fs_type,
diff -puN fs/jfs/super.c~large-dev_t-2nd-09 fs/jfs/super.c
--- 25/fs/jfs/super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/jfs/super.c	2003-09-05 00:50:05.000000000 -0700
@@ -431,6 +431,7 @@ static struct super_operations jfs_super
 	.unlockfs       = jfs_unlockfs,
 	.statfs		= jfs_statfs,
 	.remount_fs	= jfs_remount,
+	.valid_dev	= old_valid_dev,
 };
 
 static struct export_operations jfs_export_operations = {
diff -puN fs/libfs.c~large-dev_t-2nd-09 fs/libfs.c
--- 25/fs/libfs.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/libfs.c	2003-09-05 00:50:05.000000000 -0700
@@ -3,6 +3,7 @@
  *	Library for filesystems writers.
  */
 
+#include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
@@ -428,3 +429,29 @@ void simple_release_fs(struct vfsmount *
 	spin_unlock(&pin_fs_lock);
 	mntput(mnt);
 }
+
+/* acceptable for old filesystems */
+int old_valid_dev(dev_t dev)
+{
+	return MAJOR(dev) < 256 && MINOR(dev) < 256;
+}
+EXPORT_SYMBOL(old_valid_dev);
+
+u16 old_encode_dev(dev_t dev)
+{
+	return (MAJOR(dev) << 8) | MINOR(dev);
+}
+EXPORT_SYMBOL(old_encode_dev);
+
+dev_t old_decode_dev(u16 val)
+{
+	return MKDEV((val >> 8) & 255, val & 255);
+}
+EXPORT_SYMBOL(old_decode_dev);
+
+/* anything goes */
+int simple_valid_dev(dev_t dev)
+{
+	return 1;
+}
+EXPORT_SYMBOL(simple_valid_dev);
diff -puN fs/minix/inode.c~large-dev_t-2nd-09 fs/minix/inode.c
--- 25/fs/minix/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/minix/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -101,6 +101,7 @@ static struct super_operations minix_sop
 	.put_super	= minix_put_super,
 	.statfs		= minix_statfs,
 	.remount_fs	= minix_remount,
+	.valid_dev	= old_valid_dev,
 };
 
 static int minix_remount (struct super_block * sb, int * flags, char * data)
diff -puN fs/namei.c~large-dev_t-2nd-09 fs/namei.c
--- 25/fs/namei.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/namei.c	2003-09-05 00:50:05.000000000 -0700
@@ -1437,7 +1437,10 @@ int vfs_mknod(struct inode *dir, struct 
 		return error;
 
 	DQUOT_INIT(dir);
-	error = dir->i_op->mknod(dir, dentry, mode, dev);
+	if (!dir->i_sb->s_op->valid_dev || !dir->i_sb->s_op->valid_dev(dev))
+		error = -EINVAL;
+	else
+		error = dir->i_op->mknod(dir, dentry, mode, dev);
 	if (!error) {
 		inode_dir_notify(dir, DN_CREATE);
 		security_inode_post_mknod(dir, dentry, mode, dev);
diff -puN fs/ncpfs/inode.c~large-dev_t-2nd-09 fs/ncpfs/inode.c
--- 25/fs/ncpfs/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/ncpfs/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -93,6 +93,7 @@ static struct super_operations ncp_sops 
 	.delete_inode	= ncp_delete_inode,
 	.put_super	= ncp_put_super,
 	.statfs		= ncp_statfs,
+	.valid_dev	= old_valid_dev,
 };
 
 extern struct dentry_operations ncp_root_dentry_operations;
diff -puN fs/nfs/inode.c~large-dev_t-2nd-09 fs/nfs/inode.c
--- 25/fs/nfs/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/nfs/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -66,6 +66,7 @@ static struct super_operations nfs_sops 
 	.clear_inode	= nfs_clear_inode,
 	.umount_begin	= nfs_umount_begin,
 	.show_options	= nfs_show_options,
+	.valid_dev	= old_valid_dev,
 };
 
 /*
diff -puN fs/ramfs/inode.c~large-dev_t-2nd-09 fs/ramfs/inode.c
--- 25/fs/ramfs/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/ramfs/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -167,6 +167,7 @@ static struct inode_operations ramfs_dir
 static struct super_operations ramfs_ops = {
 	.statfs		= simple_statfs,
 	.drop_inode	= generic_delete_inode,
+	.valid_dev	= simple_valid_dev,
 };
 
 static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
diff -puN fs/reiserfs/super.c~large-dev_t-2nd-09 fs/reiserfs/super.c
--- 25/fs/reiserfs/super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/reiserfs/super.c	2003-09-05 00:50:05.000000000 -0700
@@ -483,7 +483,7 @@ struct super_operations reiserfs_sops = 
   .unlockfs = reiserfs_unlockfs,
   .statfs = reiserfs_statfs,
   .remount_fs = reiserfs_remount,
-
+  .valid_dev = old_valid_dev,
 };
 
 static struct export_operations reiserfs_export_ops = {
diff -puN fs/smbfs/inode.c~large-dev_t-2nd-09 fs/smbfs/inode.c
--- 25/fs/smbfs/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/smbfs/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -101,6 +101,7 @@ static struct super_operations smb_sops 
 	.put_super	= smb_put_super,
 	.statfs		= smb_statfs,
 	.show_options	= smb_show_options,
+	.valid_dev	= old_valid_dev,
 };
 
 
diff -puN fs/sysv/inode.c~large-dev_t-2nd-09 fs/sysv/inode.c
--- 25/fs/sysv/inode.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/sysv/inode.c	2003-09-05 00:50:05.000000000 -0700
@@ -322,6 +322,7 @@ struct super_operations sysv_sops = {
 	.put_super	= sysv_put_super,
 	.write_super	= sysv_write_super,
 	.statfs		= sysv_statfs,
+	.valid_dev	= old_valid_dev,
 };
 
 int __init sysv_init_icache(void)
diff -puN fs/udf/super.c~large-dev_t-2nd-09 fs/udf/super.c
--- 25/fs/udf/super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/udf/super.c	2003-09-05 00:50:05.000000000 -0700
@@ -167,6 +167,7 @@ static struct super_operations udf_sb_op
 	.write_super		= udf_write_super,
 	.statfs			= udf_statfs,
 	.remount_fs		= udf_remount_fs,
+	.valid_dev		= old_valid_dev,
 };
 
 struct udf_options
diff -puN fs/ufs/super.c~large-dev_t-2nd-09 fs/ufs/super.c
--- 25/fs/ufs/super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/ufs/super.c	2003-09-05 00:50:05.000000000 -0700
@@ -1052,6 +1052,7 @@ static struct super_operations ufs_super
 	.write_super	= ufs_write_super,
 	.statfs		= ufs_statfs,
 	.remount_fs	= ufs_remount,
+	.valid_dev	= old_valid_dev,
 };
 
 static struct super_block *ufs_get_sb(struct file_system_type *fs_type,
diff -puN fs/xfs/linux/xfs_super.c~large-dev_t-2nd-09 fs/xfs/linux/xfs_super.c
--- 25/fs/xfs/linux/xfs_super.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/fs/xfs/linux/xfs_super.c	2003-09-05 00:50:05.000000000 -0700
@@ -822,6 +822,7 @@ STATIC struct super_operations linvfs_so
 	.statfs			= linvfs_statfs,
 	.remount_fs		= linvfs_remount,
 	.show_options		= linvfs_show_options,
+	.valid_dev		= old_valid_dev,
 };
 
 STATIC struct quotactl_ops linvfs_qops = {
diff -puN include/linux/fs.h~large-dev_t-2nd-09 include/linux/fs.h
--- 25/include/linux/fs.h~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/include/linux/fs.h	2003-09-05 00:50:05.000000000 -0700
@@ -867,8 +867,8 @@ struct super_operations {
 	int (*remount_fs) (struct super_block *, int *, char *);
 	void (*clear_inode) (struct inode *);
 	void (*umount_begin) (struct super_block *);
-
 	int (*show_options)(struct seq_file *, struct vfsmount *);
+	int (*valid_dev)(dev_t);
 };
 
 /* Inode state bits.  Protected by inode_lock. */
@@ -1389,6 +1389,10 @@ struct tree_descr { char *name; struct f
 extern int simple_fill_super(struct super_block *, int, struct tree_descr *);
 extern int simple_pin_fs(char *name, struct vfsmount **mount, int *count);
 extern void simple_release_fs(struct vfsmount **mount, int *count);
+extern int simple_valid_dev(dev_t);
+extern int old_valid_dev(dev_t);
+extern u16 old_encode_dev(dev_t);
+extern dev_t old_decode_dev(u16);
 
 extern int inode_change_ok(struct inode *, struct iattr *);
 extern int inode_setattr(struct inode *, struct iattr *);
diff -puN mm/shmem.c~large-dev_t-2nd-09 mm/shmem.c
--- 25/mm/shmem.c~large-dev_t-2nd-09	2003-09-05 00:50:05.000000000 -0700
+++ 25-akpm/mm/shmem.c	2003-09-05 00:50:05.000000000 -0700
@@ -1811,6 +1811,7 @@ static struct super_operations shmem_ops
 	.delete_inode	= shmem_delete_inode,
 	.drop_inode	= generic_delete_inode,
 	.put_super	= shmem_put_super,
+	.valid_dev	= simple_valid_dev,
 };
 
 static struct vm_operations_struct shmem_vm_ops = {

_