Signed-off-by: Ludwig Nussel <ludwig.nus...@suse.de>
---
 Documentation/filesystems/ext2.txt |    9 ++++
 fs/ext2/ext2.h                     |    8 +++
 fs/ext2/inode.c                    |   48 +++++++++++++-----
 fs/ext2/super.c                    |   95 +++++++++++++++++++++++++++++++++++-
 4 Dateien geändert, 147 Zeilen hinzugefügt(+), 13 Zeilen entfernt(-)
diff --git a/Documentation/filesystems/ext2.txt 
b/Documentation/filesystems/ext2.txt
index 67639f9..fcc1002 100644
--- a/Documentation/filesystems/ext2.txt
+++ b/Documentation/filesystems/ext2.txt
@@ -42,6 +42,15 @@ orlov                        (*)     Use the Orlov block 
allocator.
 resuid=n                       The user ID which may use the reserved blocks.
 resgid=n                       The group ID which may use the reserved blocks.
 
+uid=n[:m]                      Make all files appear to belong to uid n.
+                               Useful for e.g. removable media with fstab
+                               options 'user,uid=useruid'. The optional second
+                               uid m is actually written to the file system.
+
+gid=n[:m]                      Make all files appear to belong to gid n.
+                               The optional second gid m is actually written to
+                               the file system.
+
 sb=n                           Use alternate superblock at this location.
 
 user_xattr                     Enable "user." POSIX Extended Attributes
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index d9a17d0..160d5d8 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -84,6 +84,10 @@ struct ext2_sb_info {
        unsigned long s_sb_block;
        kuid_t s_resuid;
        kgid_t s_resgid;
+       kuid_t s_uid;          /* make all files appear to belong to this uid */
+       kuid_t s_diskuid;      /* write this uid to disk (if s_uid != 0) */
+       kgid_t s_gid;          /* make all files appear to belong to this gid */
+       kgid_t s_diskgid;      /* write this gid to disk (if s_gid != 0) */
        unsigned short s_mount_state;
        unsigned short s_pad;
        int s_addr_per_block_bits;
@@ -639,6 +643,10 @@ struct ext2_mount_options {
        unsigned long s_mount_opt;
        kuid_t s_resuid;
        kgid_t s_resgid;
+       kuid_t s_uid;
+       kuid_t s_diskuid;
+       kgid_t s_gid;
+       kgid_t s_diskgid;
 };
 
 /*
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 6363ac6..b2320e4 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1321,8 +1321,14 @@ struct inode *ext2_iget (struct super_block *sb, 
unsigned long ino)
                i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
                i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
        }
-       i_uid_write(inode, i_uid);
-       i_gid_write(inode, i_gid);
+       if (uid_valid(EXT2_SB(sb)->s_uid))
+               inode->i_uid = EXT2_SB(sb)->s_uid;
+       else
+               i_uid_write(inode, i_uid);
+       if (gid_valid(EXT2_SB(sb)->s_gid))
+               inode->i_gid = EXT2_SB(sb)->s_gid;
+       else
+               i_gid_write(inode, i_gid);
        set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
        inode->i_size = le32_to_cpu(raw_inode->i_size);
        inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
@@ -1426,6 +1432,10 @@ static int __ext2_write_inode(struct inode *inode, int 
do_sync)
        struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);
        int n;
        int err = 0;
+       __le16 uid_low;
+       __le16 gid_low;
+       __le16 uid_high;
+       __le16 gid_high;
 
        if (IS_ERR(raw_inode))
                return -EIO;
@@ -1437,26 +1447,40 @@ static int __ext2_write_inode(struct inode *inode, int 
do_sync)
 
        ext2_get_inode_flags(ei);
        raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+       if (uid_valid(EXT2_SB(sb)->s_uid))
+               uid = from_kuid(&init_user_ns, EXT2_SB(sb)->s_diskuid);
+       if (gid_valid(EXT2_SB(sb)->s_gid))
+               gid = from_kgid(&init_user_ns, EXT2_SB(sb)->s_diskgid);
        if (!(test_opt(sb, NO_UID32))) {
-               raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
-               raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid));
+               uid_low = cpu_to_le16(low_16_bits(uid));
+               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 (!ei->i_dtime) {
-                       raw_inode->i_uid_high = cpu_to_le16(high_16_bits(uid));
-                       raw_inode->i_gid_high = cpu_to_le16(high_16_bits(gid));
+                       uid_high = cpu_to_le16(high_16_bits(uid));
+                       gid_high = cpu_to_le16(high_16_bits(gid));
                } else {
-                       raw_inode->i_uid_high = 0;
-                       raw_inode->i_gid_high = 0;
+                       uid_high = 0;
+                       gid_high = 0;
                }
        } else {
-               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;
+               uid_low = cpu_to_le16(fs_high2lowuid(uid));
+               gid_low = cpu_to_le16(fs_high2lowgid(gid));
+               uid_high = 0;
+               gid_high = 0;
+       }
+       /* don't mangle uid/gid of existing files if override is active */
+       if (!uid_valid(EXT2_SB(sb)->s_uid) || ei->i_state & EXT2_STATE_NEW) {
+               raw_inode->i_uid_high = uid_high;
+               raw_inode->i_uid_low = uid_low;
        }
+       if (!gid_valid(EXT2_SB(sb)->s_gid) || ei->i_state & EXT2_STATE_NEW) {
+               raw_inode->i_gid_high = gid_high;
+               raw_inode->i_gid_low = gid_low;
+       }
+
        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.tv_sec);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index af74d9e..0f91dfb 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -237,6 +237,24 @@ static int ext2_show_options(struct seq_file *seq, struct 
dentry *root)
                seq_printf(seq, ",resgid=%u",
                                from_kgid_munged(&init_user_ns, sbi->s_resgid));
        }
+       if (uid_valid(sbi->s_uid)) {
+               if (!uid_eq(sbi->s_uid, sbi->s_diskuid))
+                       seq_printf(seq, ",uid=%u:%u",
+                               from_kuid_munged(&init_user_ns, sbi->s_uid),
+                               from_kuid_munged(&init_user_ns, 
sbi->s_diskuid));
+               else
+                       seq_printf(seq, ",uid=%u",
+                               from_kuid_munged(&init_user_ns, sbi->s_uid));
+       }
+       if (gid_valid(sbi->s_gid)) {
+               if (!gid_eq(sbi->s_gid, sbi->s_diskgid))
+                       seq_printf(seq, ",gid=%u:%u",
+                               from_kgid_munged(&init_user_ns, sbi->s_gid),
+                               from_kgid_munged(&init_user_ns, 
sbi->s_diskgid));
+               else
+                       seq_printf(seq, ",gid=%u",
+                               from_kgid_munged(&init_user_ns, sbi->s_gid));
+       }
        if (test_opt(sb, ERRORS_RO)) {
                int def_errors = le16_to_cpu(es->s_errors);
 
@@ -390,7 +408,8 @@ enum {
        Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug,
        Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
        Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
-       Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
+       Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation,
+       Opt_uid, Opt_diskuid, Opt_gid, Opt_diskgid
 };
 
 static const match_table_t tokens = {
@@ -424,6 +443,10 @@ static const match_table_t tokens = {
        {Opt_usrquota, "usrquota"},
        {Opt_reservation, "reservation"},
        {Opt_noreservation, "noreservation"},
+       {Opt_uid, "uid=%u"},
+       {Opt_diskuid, "uid=%u:%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_diskgid, "gid=%u:%u"},
        {Opt_err, NULL}
 };
 
@@ -578,6 +601,64 @@ static int parse_options(char *options, struct super_block 
*sb)
                        clear_opt(sbi->s_mount_opt, RESERVATION);
                        ext2_msg(sb, KERN_INFO, "reservations OFF");
                        break;
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       uid = make_kuid(current_user_ns(), option);
+                       if (!uid_valid(uid)) {
+                               ext2_msg(sb, KERN_ERR, "Invalid uid value %d", 
option);
+                               return -1;
+                       }
+                       sbi->s_uid = sbi->s_diskuid = uid;
+                       break;
+               case Opt_diskuid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       uid = make_kuid(current_user_ns(), option);
+                       if (!uid_valid(uid)) {
+                               ext2_msg(sb, KERN_ERR, "Invalid uid value %d", 
option);
+                               return -1;
+                       }
+                       sbi->s_uid = uid;
+
+                       if (match_int(&args[1], &option))
+                               return 0;
+                       uid = make_kuid(current_user_ns(), option);
+                       if (!uid_valid(uid)) {
+                               ext2_msg(sb, KERN_ERR, "Invalid uid value %d", 
option);
+                               return -1;
+                       }
+                       sbi->s_diskuid = uid;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       gid = make_kgid(current_user_ns(), option);
+                       if (!gid_valid(gid)) {
+                               ext2_msg(sb, KERN_ERR, "Invalid gid value %d", 
option);
+                               return -1;
+                       }
+                       sbi->s_gid = sbi->s_diskgid = gid;
+                       break;
+               case Opt_diskgid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       gid = make_kgid(current_user_ns(), option);
+                       if (!gid_valid(gid)) {
+                               ext2_msg(sb, KERN_ERR, "Invalid gid value %d", 
option);
+                               return -1;
+                       }
+                       sbi->s_gid = gid;
+
+                       if (match_int(&args[1], &option))
+                               return 0;
+                       gid = make_kgid(current_user_ns(), option);
+                       if (!gid_valid(gid)) {
+                               ext2_msg(sb, KERN_ERR, "Invalid gid value %d", 
option);
+                               return -1;
+                       }
+                       sbi->s_diskgid = gid;
+                       break;
                case Opt_ignore:
                        break;
                default:
@@ -853,6 +934,10 @@ static int ext2_fill_super(struct super_block *sb, void 
*data, int silent)
 
        sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
        sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
+       sbi->s_uid = INVALID_UID;
+       sbi->s_gid = INVALID_GID;
+       sbi->s_diskuid = INVALID_UID;
+       sbi->s_diskgid = INVALID_GID;
        
        set_opt(sbi->s_mount_opt, RESERVATION);
 
@@ -1256,6 +1341,10 @@ static int ext2_remount (struct super_block * sb, int * 
flags, char * data)
        old_opts.s_mount_opt = sbi->s_mount_opt;
        old_opts.s_resuid = sbi->s_resuid;
        old_opts.s_resgid = sbi->s_resgid;
+       old_opts.s_uid = sbi->s_uid;
+       old_opts.s_diskuid = sbi->s_diskuid;
+       old_opts.s_gid = sbi->s_gid;
+       old_opts.s_diskgid = sbi->s_diskgid;
 
        /*
         * Allow the "check" option to be passed as a remount option.
@@ -1342,6 +1431,10 @@ restore_opts:
        sbi->s_mount_opt = old_opts.s_mount_opt;
        sbi->s_resuid = old_opts.s_resuid;
        sbi->s_resgid = old_opts.s_resgid;
+       sbi->s_uid = old_opts.s_uid;
+       sbi->s_diskuid = old_opts.s_diskuid;
+       sbi->s_gid = old_opts.s_gid;
+       sbi->s_diskgid = old_opts.s_diskgid;
        sb->s_flags = old_sb_flags;
        spin_unlock(&sbi->s_lock);
        return err;
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to