]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Revert "(namespace) Revert "UBUNTU: SAUCE: quota: Convert ids relative to s_user_ns""
authorLuis Henriques <luis.henriques@canonical.com>
Wed, 23 Nov 2016 10:00:39 +0000 (10:00 +0000)
committerLuis Henriques <luis.henriques@canonical.com>
Wed, 23 Nov 2016 10:14:18 +0000 (10:14 +0000)
BugLink: https://bugs.launchpad.net/bugs/1644165
This reverts commit e56ac922c93cf9155a65237fa372f127eedfb6c2.

The kernel fix for bug #1634964 breaks LXD userspace, in particular the
following commits:

ac7f3f73cb39 (namespace) vfs: Don't modify inodes with a uid or gid unknown to the vfs
ca52383ad6a6 (namespace) vfs: Don't create inodes with a uid or gid unknown to the vfs

LXD 2.0.6 will include changes to support these kernel changes, but it isn't
available yet on xenial, so for now we just revert these commits.

Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
fs/ocfs2/quota_global.c
fs/quota/dquot.c
fs/quota/quota_tree.c
fs/quota/quota_v1.c
fs/quota/quota_v2.c
include/linux/dqblk_qtree.h

index c93d6722088753901c258151de82dc707e6eb71e..6d62a9b098c565533b1d91f2fc405c3cbe29944e 100644 (file)
@@ -66,7 +66,7 @@
 
 static void qsync_work_fn(struct work_struct *work);
 
-static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
+static int ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
 {
        struct ocfs2_global_disk_dqblk *d = dp;
        struct mem_dqblk *m = &dquot->dq_dqb;
@@ -89,9 +89,10 @@ static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
        if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags))
                m->dqb_itime = le64_to_cpu(d->dqb_itime);
        OCFS2_DQUOT(dquot)->dq_use_count = le32_to_cpu(d->dqb_use_count);
+       return 0;
 }
 
-static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
+static int ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
 {
        struct ocfs2_global_disk_dqblk *d = dp;
        struct mem_dqblk *m = &dquot->dq_dqb;
@@ -107,6 +108,7 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
        d->dqb_btime = cpu_to_le64(m->dqb_btime);
        d->dqb_itime = cpu_to_le64(m->dqb_itime);
        d->dqb_pad1 = d->dqb_pad2 = 0;
+       return 0;
 }
 
 static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
index 353ff31dcee17a19af0ffdc67c25dde9f0eaa1d9..b93a0b465247f5e28400ebe78eca103b4333796d 100644 (file)
@@ -741,7 +741,7 @@ void dqput(struct dquot *dquot)
        if (!atomic_read(&dquot->dq_count)) {
                quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
                            quotatypes[dquot->dq_id.type],
-                           from_kqid(&init_user_ns, dquot->dq_id));
+                           from_kqid(dquot->dq_sb->s_user_ns, dquot->dq_id));
                BUG();
        }
 #endif
index 58efb83dec1c870c672a5330fcb4571323c73914..c1bc15368fd56b1c2001e619e67b2173e1a5bdd4 100644 (file)
@@ -25,8 +25,10 @@ MODULE_LICENSE("GPL");
 static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth)
 {
        unsigned int epb = info->dqi_usable_bs >> 2;
-       qid_t id = from_kqid(&init_user_ns, qid);
+       qid_t id = from_kqid(info->dqi_sb->s_user_ns, qid);
 
+       if (id == (qid_t)-1)
+               return -EOVERFLOW;
        depth = info->dqi_qtree_depth - depth - 1;
        while (depth--)
                id /= epb;
@@ -292,7 +294,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
                          uint *treeblk, int depth)
 {
        char *buf = getdqbuf(info->dqi_usable_bs);
-       int ret = 0, newson = 0, newact = 0;
+       int ret = 0, newson = 0, newact = 0, index;
        __le32 *ref;
        uint newblk;
 
@@ -314,7 +316,12 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
                }
        }
        ref = (__le32 *)buf;
-       newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+       index = get_index(info, dquot->dq_id, depth);
+       if (index < 0) {
+               ret = index;
+               goto out_buf;
+       }
+       newblk = le32_to_cpu(ref[index]);
        if (!newblk)
                newson = 1;
        if (depth == info->dqi_qtree_depth - 1) {
@@ -322,8 +329,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
                if (newblk) {
                        quota_error(dquot->dq_sb, "Inserting already present "
                                    "quota entry (block %u)",
-                                   le32_to_cpu(ref[get_index(info,
-                                               dquot->dq_id, depth)]));
+                                   le32_to_cpu(ref[index]));
                        ret = -EIO;
                        goto out_buf;
                }
@@ -333,8 +339,7 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
                ret = do_insert_tree(info, dquot, &newblk, depth+1);
        }
        if (newson && ret >= 0) {
-               ref[get_index(info, dquot->dq_id, depth)] =
-                                                       cpu_to_le32(newblk);
+               ref[index] = cpu_to_le32(newblk);
                ret = write_blk(info, *treeblk, buf);
        } else if (newact && ret < 0) {
                put_free_dqblk(info, buf, *treeblk);
@@ -384,8 +389,10 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
                }
        }
        spin_lock(&dq_data_lock);
-       info->dqi_ops->mem2disk_dqblk(ddquot, dquot);
+       ret = info->dqi_ops->mem2disk_dqblk(ddquot, dquot);
        spin_unlock(&dq_data_lock);
+       if (ret)
+               goto out_free;
        ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size,
                                    dquot->dq_off);
        if (ret != info->dqi_entry_size) {
@@ -396,8 +403,9 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
                ret = 0;
        }
        dqstats_inc(DQST_WRITES);
-       kfree(ddquot);
 
+out_free:
+       kfree(ddquot);
        return ret;
 }
 EXPORT_SYMBOL(qtree_write_dquot);
@@ -468,7 +476,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
                       uint *blk, int depth)
 {
        char *buf = getdqbuf(info->dqi_usable_bs);
-       int ret = 0;
+       int ret = 0, index;
        uint newblk;
        __le32 *ref = (__le32 *)buf;
 
@@ -480,7 +488,12 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
                            *blk);
                goto out_buf;
        }
-       newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+       index = get_index(info, dquot->dq_id, depth);
+       if (index < 0) {
+               ret = index;
+               goto out_buf;
+       }
+       newblk = le32_to_cpu(ref[index]);
        if (depth == info->dqi_qtree_depth - 1) {
                ret = free_dqentry(info, dquot, newblk);
                newblk = 0;
@@ -489,7 +502,7 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
        }
        if (ret >= 0 && !newblk) {
                int i;
-               ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0);
+               ref[index] = cpu_to_le32(0);
                /* Block got empty? */
                for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++)
                        ;
@@ -548,7 +561,7 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
        if (i == qtree_dqstr_in_blk(info)) {
                quota_error(dquot->dq_sb,
                            "Quota for id %u referenced but not present",
-                           from_kqid(&init_user_ns, dquot->dq_id));
+                           from_kqid(dquot->dq_sb->s_user_ns, dquot->dq_id));
                ret = -EIO;
                goto out_buf;
        } else {
@@ -565,7 +578,7 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
                                struct dquot *dquot, uint blk, int depth)
 {
        char *buf = getdqbuf(info->dqi_usable_bs);
-       loff_t ret = 0;
+       loff_t ret = 0, index;
        __le32 *ref = (__le32 *)buf;
 
        if (!buf)
@@ -577,7 +590,12 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
                goto out_buf;
        }
        ret = 0;
-       blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]);
+       index = get_index(info, dquot->dq_id, depth);
+       if (index < 0) {
+               ret = index;
+               goto out_buf;
+       }
+       blk = le32_to_cpu(ref[index]);
        if (!blk)       /* No reference? */
                goto out_buf;
        if (depth < info->dqi_qtree_depth - 1)
@@ -602,7 +620,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
        struct super_block *sb = dquot->dq_sb;
        loff_t offset;
        char *ddquot;
-       int ret = 0;
+       int ret = 0, err;
 
 #ifdef __QUOTA_QT_PARANOIA
        /* Invalidated quota? */
@@ -618,7 +636,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
                        if (offset < 0)
                                quota_error(sb,"Can't read quota structure "
                                            "for id %u",
-                                           from_kqid(&init_user_ns,
+                                           from_kqid(sb->s_user_ns,
                                                      dquot->dq_id));
                        dquot->dq_off = 0;
                        set_bit(DQ_FAKE_B, &dquot->dq_flags);
@@ -637,18 +655,20 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
                if (ret >= 0)
                        ret = -EIO;
                quota_error(sb, "Error while reading quota structure for id %u",
-                           from_kqid(&init_user_ns, dquot->dq_id));
+                           from_kqid(sb->s_user_ns, dquot->dq_id));
                set_bit(DQ_FAKE_B, &dquot->dq_flags);
                memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
                kfree(ddquot);
                goto out;
        }
        spin_lock(&dq_data_lock);
-       info->dqi_ops->disk2mem_dqblk(dquot, ddquot);
-       if (!dquot->dq_dqb.dqb_bhardlimit &&
-           !dquot->dq_dqb.dqb_bsoftlimit &&
-           !dquot->dq_dqb.dqb_ihardlimit &&
-           !dquot->dq_dqb.dqb_isoftlimit)
+       err = info->dqi_ops->disk2mem_dqblk(dquot, ddquot);
+       if (err)
+               ret = err;
+       else if (!dquot->dq_dqb.dqb_bhardlimit &&
+                !dquot->dq_dqb.dqb_bsoftlimit &&
+                !dquot->dq_dqb.dqb_ihardlimit &&
+                !dquot->dq_dqb.dqb_isoftlimit)
                set_bit(DQ_FAKE_B, &dquot->dq_flags);
        spin_unlock(&dq_data_lock);
        kfree(ddquot);
index 8fe79beced5cc05c77ad0d536fe017beeb4a2f9e..bc8930637ed56f43646958cd4054b2e082aa60b0 100644 (file)
@@ -56,15 +56,20 @@ static int v1_read_dqblk(struct dquot *dquot)
 {
        int type = dquot->dq_id.type;
        struct v1_disk_dqblk dqblk;
+       qid_t qid;
 
        if (!sb_dqopt(dquot->dq_sb)->files[type])
                return -EINVAL;
 
+       qid = from_kqid(dquot->dq_sb->s_user_ns, dquot->dq_id);
+       if (qid == (qid_t)-1)
+               return -EOVERFLOW;
+
        /* Set structure to 0s in case read fails/is after end of file */
        memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
        dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
                        sizeof(struct v1_disk_dqblk),
-                       v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));
+                       v1_dqoff(qid));
 
        v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
        if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
@@ -82,6 +87,10 @@ static int v1_commit_dqblk(struct dquot *dquot)
        short type = dquot->dq_id.type;
        ssize_t ret;
        struct v1_disk_dqblk dqblk;
+       qid_t qid = from_kqid(dquot->dq_sb->s_user_ns, dquot->dq_id);
+
+       if (qid == (qid_t)-1)
+               return -EOVERFLOW;
 
        v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
        if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) ||
@@ -95,7 +104,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
        if (sb_dqopt(dquot->dq_sb)->files[type])
                ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
                        (char *)&dqblk, sizeof(struct v1_disk_dqblk),
-                       v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));
+                       v1_dqoff(qid));
        if (ret != sizeof(struct v1_disk_dqblk)) {
                quota_error(dquot->dq_sb, "dquota write failed");
                if (ret >= 0)
index 2aa012a68e90e524255fb47e983d121cf9c839b4..7f68e2c339ddae285bda0d551fce71950193b46b 100644 (file)
@@ -23,11 +23,11 @@ MODULE_LICENSE("GPL");
 
 #define __QUOTA_V2_PARANOIA
 
-static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
-static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
+static int v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
+static int v2r0_disk2memdqb(struct dquot *dquot, void *dp);
 static int v2r0_is_id(void *dp, struct dquot *dquot);
-static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
-static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
+static int v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
+static int v2r1_disk2memdqb(struct dquot *dquot, void *dp);
 static int v2r1_is_id(void *dp, struct dquot *dquot);
 
 static struct qtree_fmt_operations v2r0_qtree_ops = {
@@ -177,7 +177,7 @@ static int v2_write_file_info(struct super_block *sb, int type)
        return 0;
 }
 
-static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
+static int v2r0_disk2memdqb(struct dquot *dquot, void *dp)
 {
        struct v2r0_disk_dqblk *d = dp, empty;
        struct mem_dqblk *m = &dquot->dq_dqb;
@@ -195,14 +195,19 @@ static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
        empty.dqb_itime = cpu_to_le64(1);
        if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
                m->dqb_itime = 0;
+       return 0;
 }
 
-static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
+static int v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
 {
        struct v2r0_disk_dqblk *d = dp;
        struct mem_dqblk *m = &dquot->dq_dqb;
        struct qtree_mem_dqinfo *info =
                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+       qid_t qid = from_kqid(dquot->dq_sb->s_user_ns, dquot->dq_id);
+
+       if (qid == (qid_t)-1)
+               return -EOVERFLOW;
 
        d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
        d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
@@ -212,9 +217,10 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
        d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
        d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
        d->dqb_btime = cpu_to_le64(m->dqb_btime);
-       d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
+       d->dqb_id = cpu_to_le32(qid);
        if (qtree_entry_unused(info, dp))
                d->dqb_itime = cpu_to_le64(1);
+       return 0;
 }
 
 static int v2r0_is_id(void *dp, struct dquot *dquot)
@@ -222,15 +228,18 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
        struct v2r0_disk_dqblk *d = dp;
        struct qtree_mem_dqinfo *info =
                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+       struct kqid qid;
 
        if (qtree_entry_unused(info, dp))
                return 0;
-       return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type,
-                               le32_to_cpu(d->dqb_id)),
-                     dquot->dq_id);
+       qid = make_kqid(dquot->dq_sb->s_user_ns, dquot->dq_id.type,
+                       le32_to_cpu(d->dqb_id));
+       if (!qid_valid(qid))
+               return 0;
+       return qid_eq(qid, dquot->dq_id);
 }
 
-static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
+static int v2r1_disk2memdqb(struct dquot *dquot, void *dp)
 {
        struct v2r1_disk_dqblk *d = dp, empty;
        struct mem_dqblk *m = &dquot->dq_dqb;
@@ -248,14 +257,19 @@ static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
        empty.dqb_itime = cpu_to_le64(1);
        if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
                m->dqb_itime = 0;
+       return 0;
 }
 
-static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
+static int v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
 {
        struct v2r1_disk_dqblk *d = dp;
        struct mem_dqblk *m = &dquot->dq_dqb;
        struct qtree_mem_dqinfo *info =
                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
+       qid_t qid = from_kqid(dquot->dq_sb->s_user_ns, dquot->dq_id);
+
+       if (qid == (qid_t)-1)
+               return -EOVERFLOW;
 
        d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
        d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
@@ -265,9 +279,10 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
        d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
        d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
        d->dqb_btime = cpu_to_le64(m->dqb_btime);
-       d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
+       d->dqb_id = cpu_to_le32(qid);
        if (qtree_entry_unused(info, dp))
                d->dqb_itime = cpu_to_le64(1);
+       return 0;
 }
 
 static int v2r1_is_id(void *dp, struct dquot *dquot)
@@ -278,7 +293,7 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
 
        if (qtree_entry_unused(info, dp))
                return 0;
-       return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type,
+       return qid_eq(make_kqid(dquot->dq_sb->s_user_ns, dquot->dq_id.type,
                                le32_to_cpu(d->dqb_id)),
                      dquot->dq_id);
 }
index 82a16527b367a26c1fbcf199da8a418540ee1847..b4fb8639cf2c4528b0e36b6685bed6467f609adf 100644 (file)
@@ -18,8 +18,8 @@ struct dquot;
 
 /* Operations */
 struct qtree_fmt_operations {
-       void (*mem2disk_dqblk)(void *disk, struct dquot *dquot);        /* Convert given entry from in memory format to disk one */
-       void (*disk2mem_dqblk)(struct dquot *dquot, void *disk);        /* Convert given entry from disk format to in memory one */
+       int (*mem2disk_dqblk)(void *disk, struct dquot *dquot); /* Convert given entry from in memory format to disk one */
+       int (*disk2mem_dqblk)(struct dquot *dquot, void *disk); /* Convert given entry from disk format to in memory one */
        int (*is_id)(void *disk, struct dquot *dquot);  /* Is this structure for given id? */
 };