Signed-off-by: Ludwig Nussel <ludwig.nus...@suse.de>
---
 Documentation/filesystems/ext3.txt |    9 ++++
 fs/ext3/ext3.h                     |    8 +++
 fs/ext3/inode.c                    |   54 ++++++++++++++------
 fs/ext3/super.c                    |   95 +++++++++++++++++++++++++++++++++++-
 4 Dateien geändert, 149 Zeilen hinzugefügt(+), 17 Zeilen entfernt(-)

diff --git a/Documentation/filesystems/ext3.txt 
b/Documentation/filesystems/ext3.txt
index 293855e..bd586d9 100644
--- a/Documentation/filesystems/ext3.txt
+++ b/Documentation/filesystems/ext3.txt
@@ -124,6 +124,15 @@ resgid=n           The group ID which may use the reserved 
blocks.
 
 resuid=n               The user 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.
 
 quota                  These options are ignored by the filesystem. They
diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h
index e85ff15..401114d 100644
--- a/fs/ext3/ext3.h
+++ b/fs/ext3/ext3.h
@@ -245,6 +245,10 @@ struct ext3_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;
        unsigned long s_commit_interval;
 #ifdef CONFIG_QUOTA
        int s_jquota_fmt;
@@ -639,6 +643,10 @@ struct ext3_sb_info {
        ext3_fsblk_t 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;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 9a4a5c4..c1176ae 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2915,8 +2915,14 @@ struct inode *ext3_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(EXT3_SB(sb)->s_uid))
+               inode->i_uid = EXT3_SB(sb)->s_uid;
+       else
+               i_uid_write(inode, i_uid);
+       if (gid_valid(EXT3_SB(sb)->s_gid))
+               inode->i_gid = EXT3_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);
@@ -3074,6 +3080,10 @@ static int ext3_do_update_inode(handle_t *handle,
        int err = 0, rc, block;
        uid_t i_uid;
        gid_t i_gid;
+       __le16 uid_low;
+       __le16 gid_low;
+       __le16 uid_high;
+       __le16 gid_high;
 
 again:
        /* we can't allow multiple procs in here at once, its a bit racey */
@@ -3088,30 +3098,42 @@ again:
        raw_inode->i_mode = cpu_to_le16(inode->i_mode);
        i_uid = i_uid_read(inode);
        i_gid = i_gid_read(inode);
+       if (uid_valid(EXT3_SB(inode->i_sb)->s_uid))
+               i_uid = from_kuid(&init_user_ns, 
EXT3_SB(inode->i_sb)->s_diskuid);
+       if (gid_valid(EXT3_SB(inode->i_sb)->s_gid))
+               i_gid = from_kgid(&init_user_ns, 
EXT3_SB(inode->i_sb)->s_diskgid);
        if(!(test_opt(inode->i_sb, NO_UID32))) {
-               raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
-               raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
+               uid_low = cpu_to_le16(low_16_bits(i_uid));
+               gid_low = cpu_to_le16(low_16_bits(i_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(i_uid));
-                       raw_inode->i_gid_high =
-                               cpu_to_le16(high_16_bits(i_gid));
+                       uid_high = cpu_to_le16(high_16_bits(i_uid));
+                       gid_high = cpu_to_le16(high_16_bits(i_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(i_uid));
-               raw_inode->i_gid_low =
-                       cpu_to_le16(fs_high2lowgid(i_gid));
-               raw_inode->i_uid_high = 0;
-               raw_inode->i_gid_high = 0;
+               uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
+               gid_low = cpu_to_le16(fs_high2lowgid(i_gid));
+               uid_high = 0;
+               gid_high = 0;
+       }
+       /* don't mangle uid/gid of existing files if override is active */
+       if (!uid_valid(EXT3_SB(inode->i_sb)->s_uid) ||
+                       ext3_test_inode_state(inode, EXT3_STATE_NEW)) {
+               raw_inode->i_uid_high = uid_high;
+               raw_inode->i_uid_low = uid_low;
        }
+       if (!gid_valid(EXT3_SB(inode->i_sb)->s_gid) ||
+                       ext3_test_inode_state(inode, EXT3_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(ei->i_disksize);
        raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ff9bcdc..730c532 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -627,6 +627,24 @@ static int ext3_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);
 
@@ -822,7 +840,8 @@ enum {
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
        Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
-       Opt_resize, Opt_usrquota, Opt_grpquota
+       Opt_resize, Opt_usrquota, Opt_grpquota,
+       Opt_uid, Opt_diskuid, Opt_gid, Opt_diskgid
 };
 
 static const match_table_t tokens = {
@@ -879,6 +898,10 @@ static const match_table_t tokens = {
        {Opt_barrier, "barrier"},
        {Opt_nobarrier, "nobarrier"},
        {Opt_resize, "resize"},
+       {Opt_uid, "uid=%u"},
+       {Opt_diskuid, "uid=%u:%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_diskgid, "gid=%u:%u"},
        {Opt_err, NULL},
 };
 
@@ -1282,6 +1305,64 @@ set_qf_format:
                        ext3_msg(sb, KERN_WARNING,
                                "warning: ignoring deprecated bh option");
                        break;
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       uid = make_kuid(current_user_ns(), option);
+                       if (!uid_valid(uid)) {
+                               ext3_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)) {
+                               ext3_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)) {
+                               ext3_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)) {
+                               ext3_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)) {
+                               ext3_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)) {
+                               ext3_msg(sb, KERN_ERR, "Invalid gid value %d", 
option);
+                               return -1;
+                       }
+                       sbi->s_diskgid = gid;
+                       break;
                default:
                        ext3_msg(sb, KERN_ERR,
                                "error: unrecognized mount option \"%s\" "
@@ -1668,6 +1749,10 @@ static int ext3_fill_super (struct super_block *sb, void 
*data, int silent)
        sbi->s_mount_opt = 0;
        sbi->s_resuid = make_kuid(&init_user_ns, EXT3_DEF_RESUID);
        sbi->s_resgid = make_kgid(&init_user_ns, EXT3_DEF_RESGID);
+       sbi->s_uid = INVALID_UID;
+       sbi->s_gid = INVALID_GID;
+       sbi->s_diskuid = INVALID_UID;
+       sbi->s_diskgid = INVALID_GID;
        sbi->s_sb_block = sb_block;
 
        blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE);
@@ -2611,6 +2696,10 @@ static int ext3_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;
        old_opts.s_commit_interval = sbi->s_commit_interval;
 #ifdef CONFIG_QUOTA
        old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
@@ -2722,6 +2811,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;
        sbi->s_commit_interval = old_opts.s_commit_interval;
 #ifdef CONFIG_QUOTA
        sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
-- 
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