ceph_alloc_options() allocates the monitor address array separately,
always sized for CEPH_MAX_MON entries. Make it a flexible array member
at the end of struct ceph_options and allocate both together with
kzalloc_flex(). The array was already an 8 KiB slab object, so this
only drops the separate allocation and its error path.

num_mon is the number of addresses in use, not the capacity, so the
array cannot be annotated with __counted_by().

ceph_compare_options() memcmp()s the simple fields up to the first
member that needs a custom comparison. With mon_addr gone from there,
use num_mon as that boundary; the compared fields are unchanged.
Document that num_mon has to stay first past that point.

Assisted-by: LLM
Signed-off-by: Rosen Penev <[email protected]>
---
 include/linux/ceph/libceph.h |  7 ++++---
 net/ceph/ceph_common.c       | 11 ++---------
 2 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index f92fdd853f1f..e585d6d11303 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -57,15 +57,16 @@ struct ceph_options {
        /*
         * any type that can't be simply compared or doesn't need
         * to be compared should go beyond this point,
-        * ceph_compare_options() should be updated accordingly
+        * ceph_compare_options() should be updated accordingly.
+        * num_mon must stay the first member past this point, as
+        * ceph_compare_options() uses it as the end of the memcmp().
         */
 
-       struct ceph_entity_addr *mon_addr; /* should be the first
-                                             pointer type of args */
        int num_mon;
        char *name;
        struct ceph_crypto_key *key;
        struct rb_root crush_locs;
+       struct ceph_entity_addr mon_addr[];
 };
 
 /*
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index a797c7360e3c..95dc18257056 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -133,7 +133,7 @@ int ceph_compare_options(struct ceph_options *new_opt,
 {
        struct ceph_options *opt1 = new_opt;
        struct ceph_options *opt2 = client->options;
-       int ofs = offsetof(struct ceph_options, mon_addr);
+       int ofs = offsetof(struct ceph_options, num_mon);
        int i;
        int ret;
 
@@ -309,17 +309,11 @@ struct ceph_options *ceph_alloc_options(void)
 {
        struct ceph_options *opt;
 
-       opt = kzalloc_obj(*opt);
+       opt = kzalloc_flex(*opt, mon_addr, CEPH_MAX_MON);
        if (!opt)
                return NULL;
 
        opt->crush_locs = RB_ROOT;
-       opt->mon_addr = kzalloc_objs(*opt->mon_addr, CEPH_MAX_MON);
-       if (!opt->mon_addr) {
-               kfree(opt);
-               return NULL;
-       }
-
        opt->flags = CEPH_OPT_DEFAULT;
        opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
        opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT;
@@ -344,7 +338,6 @@ void ceph_destroy_options(struct ceph_options *opt)
                ceph_crypto_key_destroy(opt->key);
                kfree(opt->key);
        }
-       kfree(opt->mon_addr);
        kfree(opt);
 }
 EXPORT_SYMBOL(ceph_destroy_options);
-- 
2.56.0


Reply via email to