[PATCH 00/16] ceph: addr2, btime and change_attr support
CEPH_FEATURE_MSG_ADDR2 was added to the userland code a couple of years ago, but the kclient never got support for it. While addr2 doesn't add a lot of new functionality, it is a prerequisite for msgr2 support, which we will eventually need, and the feature bit is shared with CEPH_FEATURE_FS_BTIME and CEPH_FEATURE_FS_CHANGE_ATTR. This set adds support for all of three features (necessary since the bit is shared). I've also added support for querying birthtime via statx(). I was able to do a cephfs mount and ran xfstests on it, but some of the more obscure messages haven't yet been tested. Birthtime support works as expected, but I don't have a great way to test the change attribute. We don't set SB_I_VERSION, so none of the internal kernel users will rely on it, and that value is not exposed to userspace via statx (yet). Given that, we could leave off the last 4 patches for now. Jeff Layton (16): libceph: fix sa_family just after reading address libceph: add ceph_decode_entity_addr libceph: ADDR2 support for monmap libceph: switch osdmap decoding to use ceph_decode_entity_addr libceph: fix watch_item_t decoding to use ceph_decode_entity_addr libceph: correctly decode ADDR2 addresses in incremental OSD maps ceph: have MDS map decoding use entity_addr_t decoder ceph: fix decode_locker to use ceph_decode_entity_addr ceph: add btime field to ceph_inode_info ceph: handle btime in cap messages libceph: turn on CEPH_FEATURE_MSG_ADDR2 ceph: allow querying of STATX_BTIME in ceph_getattr iversion: add a routine to update a raw value with a larger one ceph: add change_attr field to ceph_inode_info ceph: handle change_attr in cap messages ceph: increment change_attribute on local changes fs/ceph/addr.c | 2 + fs/ceph/caps.c | 37 +++++++++------ fs/ceph/file.c | 5 ++ fs/ceph/inode.c | 23 +++++++-- fs/ceph/mds_client.c | 21 +++++---- fs/ceph/mds_client.h | 2 + fs/ceph/mdsmap.c | 12 +++-- fs/ceph/snap.c | 3 ++ fs/ceph/super.h | 4 +- include/linux/ceph/ceph_features.h | 1 + include/linux/ceph/decode.h | 2 + include/linux/ceph/mon_client.h | 1 - include/linux/iversion.h | 24 ++++++++++ net/ceph/Makefile | 2 +- net/ceph/cls_lock_client.c | 7 ++- net/ceph/decode.c | 75 ++++++++++++++++++++++++++++++ net/ceph/messenger.c | 5 +- net/ceph/mon_client.c | 21 +++++---- net/ceph/osd_client.c | 20 +++++--- net/ceph/osdmap.c | 31 ++++++------ 20 files changed, 232 insertions(+), 66 deletions(-) create mode 100644 net/ceph/decode.c -- 2.21.0
It doesn't make sense to leave it undecoded until later. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- net/ceph/messenger.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 3ee380758ddd..a25e71fa8124 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -1732,12 +1732,14 @@ static int read_partial_banner(struct ceph_connection *con) ret = read_partial(con, end, size, &con->actual_peer_addr); if (ret <= 0) goto out; + ceph_decode_addr(&con->actual_peer_addr); size = sizeof (con->peer_addr_for_me); end += size; ret = read_partial(con, end, size, &con->peer_addr_for_me); if (ret <= 0) goto out; + ceph_decode_addr(&con->peer_addr_for_me); out: return ret; @@ -2010,9 +2012,6 @@ static int process_banner(struct ceph_connection *con) if (verify_hello(con) < 0) return -1; - ceph_decode_addr(&con->actual_peer_addr); - ceph_decode_addr(&con->peer_addr_for_me); - /* * Make sure the other end is who we wanted. note that the other * end may not yet know their ip address, so if it's 0.0.0.0, give -- 2.21.0
Add a way to decode an entity_addr_t. Once CEPH_FEATURE_MSG_ADDR2 is enabled, the server daemons will start encoding entity_addr_t differently. Add a new helper function that can handle either format. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- include/linux/ceph/decode.h | 2 + net/ceph/Makefile | 2 +- net/ceph/decode.c | 75 +++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 net/ceph/decode.c diff --git a/include/linux/ceph/decode.h b/include/linux/ceph/decode.h index a6c2a48d42e0..1c0a665bfc03 100644 --- a/include/linux/ceph/decode.h +++ b/include/linux/ceph/decode.h @@ -230,6 +230,8 @@ static inline void ceph_decode_addr(struct ceph_entity_addr *a) WARN_ON(a->in_addr.ss_family == 512); } +extern int ceph_decode_entity_addr(void **p, void *end, + struct ceph_entity_addr *addr); /* * encoders */ diff --git a/net/ceph/Makefile b/net/ceph/Makefile index db09defe27d0..59d0ba2072de 100644 --- a/net/ceph/Makefile +++ b/net/ceph/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_CEPH_LIB) += libceph.o libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \ - mon_client.o \ + mon_client.o decode.o \ cls_lock_client.o \ osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \ striper.o \ diff --git a/net/ceph/decode.c b/net/ceph/decode.c new file mode 100644 index 000000000000..27edf5d341ec --- /dev/null +++ b/net/ceph/decode.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/ceph/decode.h> + +int +ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr) +{ + u8 marker, v, compat; + u32 len; + + ceph_decode_8_safe(p, end, marker, bad); + if (marker == 1) { + ceph_decode_8_safe(p, end, v, bad); + ceph_decode_8_safe(p, end, compat, bad); + if (!v || compat != 1) + goto bad; + /* FIXME: sanity check? */ + ceph_decode_32_safe(p, end, len, bad); + /* type is __le32, so we must copy into place as-is */ + ceph_decode_copy_safe(p, end, &addr->type, + sizeof(addr->type), bad); + + /* + * TYPE_NONE == 0 + * TYPE_LEGACY == 1 + * + * Clients that don't support ADDR2 always send TYPE_NONE. + * For now, since all we support is msgr1, just set this to 0 + * when we get a TYPE_LEGACY type. + */ + if (addr->type == cpu_to_le32(1)) + addr->type = 0; + } else if (marker == 0) { + addr->type = 0; + /* Skip rest of type field */ + ceph_decode_skip_n(p, end, 3, bad); + } else { + goto bad; + } + + ceph_decode_need(p, end, sizeof(addr->nonce), bad); + ceph_decode_copy(p, &addr->nonce, sizeof(addr->nonce)); + + /* addr length */ + if (marker == 1) { + ceph_decode_32_safe(p, end, len, bad); + if (len > sizeof(addr->in_addr)) + goto bad; + } else { + len = sizeof(addr->in_addr); + } + + memset(&addr->in_addr, 0, sizeof(addr->in_addr)); + + if (len) { + ceph_decode_need(p, end, len, bad); + ceph_decode_copy(p, &addr->in_addr, len); + + /* + * Fix up sa_family. Legacy encoding sends it in BE, addr2 + * encoding uses LE. + */ + if (marker == 1) + addr->in_addr.ss_family = + le16_to_cpu((__force __le16)addr->in_addr.ss_family); + else + addr->in_addr.ss_family = + be16_to_cpu((__force __be16)addr->in_addr.ss_family); + } + return 0; +bad: + return -EINVAL; +} +EXPORT_SYMBOL(ceph_decode_entity_addr); + -- 2.21.0
On Fri, Jun 7, 2019 at 11:38 PM Jeff Layton <jlayton@kernel.org> wrote:
Add a way to decode an entity_addr_t. Once CEPH_FEATURE_MSG_ADDR2 is enabled, the server daemons will start encoding entity_addr_t differently.
Add a new helper function that can handle either format.
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- include/linux/ceph/decode.h | 2 + net/ceph/Makefile | 2 +- net/ceph/decode.c | 75 +++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 net/ceph/decode.c
diff --git a/include/linux/ceph/decode.h b/include/linux/ceph/decode.h index a6c2a48d42e0..1c0a665bfc03 100644 --- a/include/linux/ceph/decode.h +++ b/include/linux/ceph/decode.h @@ -230,6 +230,8 @@ static inline void ceph_decode_addr(struct ceph_entity_addr *a) WARN_ON(a->in_addr.ss_family == 512); }
+extern int ceph_decode_entity_addr(void **p, void *end, + struct ceph_entity_addr *addr); /* * encoders */ diff --git a/net/ceph/Makefile b/net/ceph/Makefile index db09defe27d0..59d0ba2072de 100644 --- a/net/ceph/Makefile +++ b/net/ceph/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_CEPH_LIB) += libceph.o
libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \ - mon_client.o \ + mon_client.o decode.o \ cls_lock_client.o \ osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \ striper.o \ diff --git a/net/ceph/decode.c b/net/ceph/decode.c new file mode 100644 index 000000000000..27edf5d341ec --- /dev/null +++ b/net/ceph/decode.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/ceph/decode.h> + +int +ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr) +{ + u8 marker, v, compat;
It's better to use name struct_v, struct_compat
+ u32 len; + + ceph_decode_8_safe(p, end, marker, bad); + if (marker == 1) { + ceph_decode_8_safe(p, end, v, bad); + ceph_decode_8_safe(p, end, compat, bad); + if (!v || compat != 1) + goto bad; + /* FIXME: sanity check? */ + ceph_decode_32_safe(p, end, len, bad); + /* type is __le32, so we must copy into place as-is */ + ceph_decode_copy_safe(p, end, &addr->type, + sizeof(addr->type), bad); + + /* + * TYPE_NONE == 0 + * TYPE_LEGACY == 1 + * + * Clients that don't support ADDR2 always send TYPE_NONE. + * For now, since all we support is msgr1, just set this to 0 + * when we get a TYPE_LEGACY type. + */ + if (addr->type == cpu_to_le32(1)) + addr->type = 0; + } else if (marker == 0) { + addr->type = 0; + /* Skip rest of type field */ + ceph_decode_skip_n(p, end, 3, bad); + } else {
versioned encoding has forward compatibility. The code should looks like if (struct_v == 0) { /* old format */ return; } if (struct_compat != 1) goto bad end = *p + struct_len; if (struct_v == 1) { .... } if (struct_v == 2) { ... } *p = end;
+ goto bad; + } + + ceph_decode_need(p, end, sizeof(addr->nonce), bad); + ceph_decode_copy(p, &addr->nonce, sizeof(addr->nonce)); + + /* addr length */ + if (marker == 1) { + ceph_decode_32_safe(p, end, len, bad); + if (len > sizeof(addr->in_addr)) + goto bad; + } else { + len = sizeof(addr->in_addr); + } + + memset(&addr->in_addr, 0, sizeof(addr->in_addr)); + + if (len) { + ceph_decode_need(p, end, len, bad); + ceph_decode_copy(p, &addr->in_addr, len); + + /* + * Fix up sa_family. Legacy encoding sends it in BE, addr2 + * encoding uses LE. + */ + if (marker == 1) + addr->in_addr.ss_family = + le16_to_cpu((__force __le16)addr->in_addr.ss_family); + else + addr->in_addr.ss_family = + be16_to_cpu((__force __be16)addr->in_addr.ss_family); + } + return 0; +bad: + return -EINVAL; +} +EXPORT_SYMBOL(ceph_decode_entity_addr); + -- 2.21.0 _______________________________________________ Dev mailing list -- dev@ceph.io To unsubscribe send an email to dev-leave@ceph.io
Switch the MonMap decoder to use the new decoding routine for entity_addr_t's. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- include/linux/ceph/mon_client.h | 1 - net/ceph/mon_client.c | 21 +++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/linux/ceph/mon_client.h b/include/linux/ceph/mon_client.h index 3a4688af7455..b4d134d3312a 100644 --- a/include/linux/ceph/mon_client.h +++ b/include/linux/ceph/mon_client.h @@ -104,7 +104,6 @@ struct ceph_mon_client { #endif }; -extern struct ceph_monmap *ceph_monmap_decode(void *p, void *end); extern int ceph_monmap_contains(struct ceph_monmap *m, struct ceph_entity_addr *addr); diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 895679d3529b..0520bf9825aa 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -39,7 +39,7 @@ static int __validate_auth(struct ceph_mon_client *monc); /* * Decode a monmap blob (e.g., during mount). */ -struct ceph_monmap *ceph_monmap_decode(void *p, void *end) +static struct ceph_monmap *ceph_monmap_decode(void *p, void *end) { struct ceph_monmap *m = NULL; int i, err = -EINVAL; @@ -50,7 +50,7 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end) ceph_decode_32_safe(&p, end, len, bad); ceph_decode_need(&p, end, len, bad); - dout("monmap_decode %p %p len %d\n", p, end, (int)(end-p)); + dout("monmap_decode %p %p len %d (%d)\n", p, end, len, (int)(end-p)); p += sizeof(u16); /* skip version */ ceph_decode_need(&p, end, sizeof(fsid) + 2*sizeof(u32), bad); @@ -58,7 +58,6 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end) epoch = ceph_decode_32(&p); num_mon = ceph_decode_32(&p); - ceph_decode_need(&p, end, num_mon*sizeof(m->mon_inst[0]), bad); if (num_mon > CEPH_MAX_MON) goto bad; @@ -68,17 +67,22 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end) m->fsid = fsid; m->epoch = epoch; m->num_mon = num_mon; - ceph_decode_copy(&p, m->mon_inst, num_mon*sizeof(m->mon_inst[0])); - for (i = 0; i < num_mon; i++) - ceph_decode_addr(&m->mon_inst[i].addr); - + for (i = 0; i < num_mon; ++i) { + struct ceph_entity_inst *inst = &m->mon_inst[i]; + + /* copy name portion */ + ceph_decode_copy_safe(&p, end, &inst->name, + sizeof(inst->name), bad); + err = ceph_decode_entity_addr(&p, end, &inst->addr); + if (err) + goto bad; + } dout("monmap_decode epoch %d, num_mon %d\n", m->epoch, m->num_mon); for (i = 0; i < m->num_mon; i++) dout("monmap_decode mon%d is %s\n", i, ceph_pr_addr(&m->mon_inst[i].addr)); return m; - bad: dout("monmap_decode failed with %d\n", err); kfree(m); @@ -469,6 +473,7 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc, if (IS_ERR(monmap)) { pr_err("problem decoding monmap, %d\n", (int)PTR_ERR(monmap)); + ceph_msg_dump(msg); goto out; } -- 2.21.0
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- net/ceph/osdmap.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 48a31dc9161c..95e98ae59a54 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -1489,11 +1489,9 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map) /* osd_state, osd_weight, osd_addrs->client_addr */ ceph_decode_need(p, end, 3*sizeof(u32) + - map->max_osd*((struct_v >= 5 ? sizeof(u32) : - sizeof(u8)) + - sizeof(*map->osd_weight) + - sizeof(*map->osd_addr)), e_inval); - + map->max_osd*(struct_v >= 5 ? sizeof(u32) : + sizeof(u8)) + + sizeof(*map->osd_weight), e_inval); if (ceph_decode_32(p) != map->max_osd) goto e_inval; @@ -1514,9 +1512,11 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map) if (ceph_decode_32(p) != map->max_osd) goto e_inval; - ceph_decode_copy(p, map->osd_addr, map->max_osd*sizeof(*map->osd_addr)); - for (i = 0; i < map->max_osd; i++) - ceph_decode_addr(&map->osd_addr[i]); + for (i = 0; i < map->max_osd; i++) { + err = ceph_decode_entity_addr(p, end, &map->osd_addr[i]); + if (err) + goto bad; + } /* pg_temp */ err = decode_pg_temp(p, end, map); -- 2.21.0
While we're in there, let's also fix up the decoder to do proper bounds checking. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- net/ceph/osd_client.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index e6d31e0f0289..f8a4d29ef688 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -4914,20 +4914,26 @@ static int decode_watcher(void **p, void *end, struct ceph_watch_item *item) ret = ceph_start_decoding(p, end, 2, "watch_item_t", &struct_v, &struct_len); if (ret) - return ret; + goto bad; + + ret = -EINVAL; + ceph_decode_copy_safe(p, end, &item->name, sizeof(item->name), bad); + ceph_decode_64_safe(p, end, item->cookie, bad); + ceph_decode_skip_32(p, end, bad); /* skip timeout seconds */ - ceph_decode_copy(p, &item->name, sizeof(item->name)); - item->cookie = ceph_decode_64(p); - *p += 4; /* skip timeout_seconds */ if (struct_v >= 2) { - ceph_decode_copy(p, &item->addr, sizeof(item->addr)); - ceph_decode_addr(&item->addr); + ret = ceph_decode_entity_addr(p, end, &item->addr); + if (ret) + goto bad; + } else { + ret = 0; } dout("%s %s%llu cookie %llu addr %s\n", __func__, ENTITY_NAME(item->name), item->cookie, ceph_pr_addr(&item->addr)); - return 0; +bad: + return ret; } static int decode_watchers(void **p, void *end, -- 2.21.0
Given the new format, we have to decode the addresses twice. Once to skip past the new_up_client field, and a second time to collect the addresses. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- net/ceph/osdmap.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 95e98ae59a54..90437906b7bc 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -1618,12 +1618,17 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v, void *new_state; void *new_weight_end; u32 len; + int i; new_up_client = *p; ceph_decode_32_safe(p, end, len, e_inval); - len *= sizeof(u32) + sizeof(struct ceph_entity_addr); - ceph_decode_need(p, end, len, e_inval); - *p += len; + for (i = 0; i < len; ++i) { + struct ceph_entity_addr addr; + + ceph_decode_skip_32(p, end, e_inval); + if (ceph_decode_entity_addr(p, end, &addr)) + goto e_inval; + } new_state = *p; ceph_decode_32_safe(p, end, len, e_inval); @@ -1699,9 +1704,9 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v, struct ceph_entity_addr addr; osd = ceph_decode_32(p); - ceph_decode_copy(p, &addr, sizeof(addr)); - ceph_decode_addr(&addr); BUG_ON(osd >= map->max_osd); + if (ceph_decode_entity_addr(p, end, &addr)) + goto e_inval; pr_info("osd%d up\n", osd); map->osd_state[osd] |= CEPH_OSD_EXISTS | CEPH_OSD_UP; map->osd_addr[osd] = addr; -- 2.21.0
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/mdsmap.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c index 45a815c7975e..98814c3d18c9 100644 --- a/fs/ceph/mdsmap.c +++ b/fs/ceph/mdsmap.c @@ -107,7 +107,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) struct ceph_mdsmap *m; const void *start = *p; int i, j, n; - int err = -EINVAL; + int err; u8 mdsmap_v, mdsmap_cv; u16 mdsmap_ev; @@ -183,8 +183,9 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) inc = ceph_decode_32(p); state = ceph_decode_32(p); state_seq = ceph_decode_64(p); - ceph_decode_copy(p, &addr, sizeof(addr)); - ceph_decode_addr(&addr); + err = ceph_decode_entity_addr(p, end, &addr); + if (err) + goto corrupt; ceph_decode_copy(p, &laggy_since, sizeof(laggy_since)); *p += sizeof(u32); ceph_decode_32_safe(p, end, namelen, bad); @@ -357,7 +358,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) nomem: err = -ENOMEM; goto out_err; -bad: +corrupt: pr_err("corrupt mdsmap\n"); print_hex_dump(KERN_DEBUG, "mdsmap: ", DUMP_PREFIX_OFFSET, 16, 1, @@ -365,6 +366,9 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) out_err: ceph_mdsmap_destroy(m); return ERR_PTR(err); +bad: + err = -EINVAL; + goto corrupt; } void ceph_mdsmap_destroy(struct ceph_mdsmap *m) -- 2.21.0
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- net/ceph/cls_lock_client.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c index 4cc28541281b..b1d12bf4b83e 100644 --- a/net/ceph/cls_lock_client.c +++ b/net/ceph/cls_lock_client.c @@ -264,8 +264,11 @@ static int decode_locker(void **p, void *end, struct ceph_locker *locker) return ret; *p += sizeof(struct ceph_timespec); /* skip expiration */ - ceph_decode_copy(p, &locker->info.addr, sizeof(locker->info.addr)); - ceph_decode_addr(&locker->info.addr); + + ret = ceph_decode_entity_addr(p, end, &locker->info.addr); + if (ret) + return ret; + len = ceph_decode_32(p); *p += len; /* skip description */ -- 2.21.0
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/inode.c | 2 ++ fs/ceph/mds_client.c | 21 +++++++++++++-------- fs/ceph/mds_client.h | 1 + fs/ceph/super.h | 1 + 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 6003187dd39e..211947e3c737 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -509,6 +509,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb) INIT_WORK(&ci->i_work, ceph_inode_work); ci->i_work_mask = 0; + memset(&ci->i_btime, '\0', sizeof(ci->i_btime)); ceph_fscache_inode_init(ci); @@ -822,6 +823,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page, dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode, from_kuid(&init_user_ns, inode->i_uid), from_kgid(&init_user_ns, inode->i_gid)); + ceph_decode_timespec64(&ci->i_btime, &iinfo->btime); ceph_decode_timespec64(&ci->i_snap_btime, &iinfo->snap_btime); } diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index f5c3499fdec6..7bc0a6f4bb2e 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -150,14 +150,13 @@ static int parse_reply_info_in(void **p, void *end, info->pool_ns_data = *p; *p += info->pool_ns_len; } - /* btime, change_attr */ - { - struct ceph_timespec btime; - u64 change_attr; - ceph_decode_need(p, end, sizeof(btime), bad); - ceph_decode_copy(p, &btime, sizeof(btime)); - ceph_decode_64_safe(p, end, change_attr, bad); - } + + /* btime */ + ceph_decode_need(p, end, sizeof(info->btime), bad); + ceph_decode_copy(p, &info->btime, sizeof(info->btime)); + + /* change attribute */ + ceph_decode_skip_64(p, end, bad); /* dir pin */ if (struct_v >= 2) { @@ -206,6 +205,12 @@ static int parse_reply_info_in(void **p, void *end, } } + if (features & CEPH_FEATURE_FS_BTIME) { + ceph_decode_need(p, end, sizeof(info->btime), bad); + ceph_decode_copy(p, &info->btime, sizeof(info->btime)); + ceph_decode_skip_64(p, end, bad); + } + info->dir_pin = -ENODATA; /* info->snap_btime remains zero */ } diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 330769ecb601..da2f53646217 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -69,6 +69,7 @@ struct ceph_mds_reply_info_in { u64 max_bytes; u64 max_files; s32 dir_pin; + struct ceph_timespec btime; struct ceph_timespec snap_btime; }; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 98d2bafc2ee2..3dd9d467bb80 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -384,6 +384,7 @@ struct ceph_inode_info { int i_snap_realm_counter; /* snap realm (if caps) */ struct list_head i_snap_realm_item; struct list_head i_snap_flush_item; + struct timespec64 i_btime; struct timespec64 i_snap_btime; struct work_struct i_work; -- 2.21.0
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/caps.c | 18 ++++++++++++------ fs/ceph/snap.c | 1 + fs/ceph/super.h | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 50409d9fdc90..623b82684e90 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1139,7 +1139,7 @@ struct cap_msg_args { u64 flush_tid, oldest_flush_tid, size, max_size; u64 xattr_version; struct ceph_buffer *xattr_buf; - struct timespec64 atime, mtime, ctime; + struct timespec64 atime, mtime, ctime, btime; int op, caps, wanted, dirty; u32 seq, issue_seq, mseq, time_warp_seq; u32 flags; @@ -1160,7 +1160,6 @@ static int send_cap_msg(struct cap_msg_args *arg) struct ceph_msg *msg; void *p; size_t extra_len; - struct timespec64 zerotime = {0}; struct ceph_osd_client *osdc = &arg->session->s_mdsc->fsc->client->osdc; dout("send_cap_msg %s %llx %llx caps %s wanted %s dirty %s" @@ -1251,7 +1250,7 @@ static int send_cap_msg(struct cap_msg_args *arg) * We just zero these out for now, as the MDS ignores them unless * the requisite feature flags are set (which we don't do yet). */ - ceph_encode_timespec64(p, &zerotime); + ceph_encode_timespec64(p, &arg->btime); p += sizeof(struct ceph_timespec); ceph_encode_64(&p, 0); @@ -1379,6 +1378,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, arg.mtime = inode->i_mtime; arg.atime = inode->i_atime; arg.ctime = inode->i_ctime; + arg.btime = ci->i_btime; arg.op = op; arg.caps = cap->implemented; @@ -1438,6 +1438,7 @@ static inline int __send_flush_snap(struct inode *inode, arg.atime = capsnap->atime; arg.mtime = capsnap->mtime; arg.ctime = capsnap->ctime; + arg.btime = capsnap->btime; arg.op = CEPH_CAP_OP_FLUSHSNAP; arg.caps = capsnap->issued; @@ -3044,6 +3045,7 @@ struct cap_extra_info { u64 nsubdirs; /* currently issued */ int issued; + struct timespec64 btime; }; /* @@ -3130,6 +3132,7 @@ static void handle_cap_grant(struct inode *inode, inode->i_mode = le32_to_cpu(grant->mode); inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid)); inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid)); + ci->i_btime = extra_info->btime; dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode, from_kuid(&init_user_ns, inode->i_uid), from_kgid(&init_user_ns, inode->i_gid)); @@ -3851,17 +3854,20 @@ void ceph_handle_caps(struct ceph_mds_session *session, } } - if (msg_version >= 11) { + if (msg_version >= 9) { struct ceph_timespec *btime; u64 change_attr; - u32 flags; - /* version >= 9 */ if (p + sizeof(*btime) > end) goto bad; btime = p; + ceph_decode_timespec64(&extra_info.btime, btime); p += sizeof(*btime); ceph_decode_64_safe(&p, end, change_attr, bad); + } + + if (msg_version >= 11) { + u32 flags; /* version >= 10 */ ceph_decode_32_safe(&p, end, flags, bad); /* version >= 11 */ diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 72c6c022f02b..854308e13f12 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -606,6 +606,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, capsnap->mtime = inode->i_mtime; capsnap->atime = inode->i_atime; capsnap->ctime = inode->i_ctime; + capsnap->btime = ci->i_btime; capsnap->time_warp_seq = ci->i_time_warp_seq; capsnap->truncate_size = ci->i_truncate_size; capsnap->truncate_seq = ci->i_truncate_seq; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 3dd9d467bb80..c3cb942e08b0 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -197,7 +197,7 @@ struct ceph_cap_snap { u64 xattr_version; u64 size; - struct timespec64 mtime, atime, ctime; + struct timespec64 mtime, atime, ctime, btime; u64 time_warp_seq; u64 truncate_size; u32 truncate_seq; -- 2.21.0
On Fri, Jun 7, 2019 at 11:38 PM Jeff Layton <jlayton@kernel.org> wrote:
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/caps.c | 18 ++++++++++++------ fs/ceph/snap.c | 1 + fs/ceph/super.h | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 50409d9fdc90..623b82684e90 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1139,7 +1139,7 @@ struct cap_msg_args { u64 flush_tid, oldest_flush_tid, size, max_size; u64 xattr_version; struct ceph_buffer *xattr_buf; - struct timespec64 atime, mtime, ctime; + struct timespec64 atime, mtime, ctime, btime; int op, caps, wanted, dirty; u32 seq, issue_seq, mseq, time_warp_seq; u32 flags; @@ -1160,7 +1160,6 @@ static int send_cap_msg(struct cap_msg_args *arg) struct ceph_msg *msg; void *p; size_t extra_len; - struct timespec64 zerotime = {0}; struct ceph_osd_client *osdc = &arg->session->s_mdsc->fsc->client->osdc;
dout("send_cap_msg %s %llx %llx caps %s wanted %s dirty %s" @@ -1251,7 +1250,7 @@ static int send_cap_msg(struct cap_msg_args *arg) * We just zero these out for now, as the MDS ignores them unless * the requisite feature flags are set (which we don't do yet). */ - ceph_encode_timespec64(p, &zerotime); + ceph_encode_timespec64(p, &arg->btime); p += sizeof(struct ceph_timespec); ceph_encode_64(&p, 0);
@@ -1379,6 +1378,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, arg.mtime = inode->i_mtime; arg.atime = inode->i_atime; arg.ctime = inode->i_ctime; + arg.btime = ci->i_btime;
arg.op = op; arg.caps = cap->implemented; @@ -1438,6 +1438,7 @@ static inline int __send_flush_snap(struct inode *inode, arg.atime = capsnap->atime; arg.mtime = capsnap->mtime; arg.ctime = capsnap->ctime; + arg.btime = capsnap->btime;
arg.op = CEPH_CAP_OP_FLUSHSNAP; arg.caps = capsnap->issued; @@ -3044,6 +3045,7 @@ struct cap_extra_info { u64 nsubdirs; /* currently issued */ int issued; + struct timespec64 btime; };
/* @@ -3130,6 +3132,7 @@ static void handle_cap_grant(struct inode *inode, inode->i_mode = le32_to_cpu(grant->mode); inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid)); inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid)); + ci->i_btime = extra_info->btime;
may btime change? If not, we don't need to update it.
dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode, from_kuid(&init_user_ns, inode->i_uid), from_kgid(&init_user_ns, inode->i_gid)); @@ -3851,17 +3854,20 @@ void ceph_handle_caps(struct ceph_mds_session *session, } }
- if (msg_version >= 11) { + if (msg_version >= 9) { struct ceph_timespec *btime; u64 change_attr; - u32 flags;
- /* version >= 9 */ if (p + sizeof(*btime) > end) goto bad; btime = p; + ceph_decode_timespec64(&extra_info.btime, btime); p += sizeof(*btime); ceph_decode_64_safe(&p, end, change_attr, bad); + } + + if (msg_version >= 11) { + u32 flags; /* version >= 10 */ ceph_decode_32_safe(&p, end, flags, bad); /* version >= 11 */ diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 72c6c022f02b..854308e13f12 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -606,6 +606,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, capsnap->mtime = inode->i_mtime; capsnap->atime = inode->i_atime; capsnap->ctime = inode->i_ctime; + capsnap->btime = ci->i_btime; capsnap->time_warp_seq = ci->i_time_warp_seq; capsnap->truncate_size = ci->i_truncate_size; capsnap->truncate_seq = ci->i_truncate_seq; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 3dd9d467bb80..c3cb942e08b0 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -197,7 +197,7 @@ struct ceph_cap_snap { u64 xattr_version;
u64 size; - struct timespec64 mtime, atime, ctime; + struct timespec64 mtime, atime, ctime, btime; u64 time_warp_seq; u64 truncate_size; u32 truncate_seq; -- 2.21.0 _______________________________________________ Dev mailing list -- dev@ceph.io To unsubscribe send an email to dev-leave@ceph.io
On Fri, 2019-06-14 at 16:17 +0800, Yan, Zheng wrote:
On Fri, Jun 7, 2019 at 11:38 PM Jeff Layton <jlayton@kernel.org> wrote:
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/caps.c | 18 ++++++++++++------ fs/ceph/snap.c | 1 + fs/ceph/super.h | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 50409d9fdc90..623b82684e90 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1139,7 +1139,7 @@ struct cap_msg_args { u64 flush_tid, oldest_flush_tid, size, max_size; u64 xattr_version; struct ceph_buffer *xattr_buf; - struct timespec64 atime, mtime, ctime; + struct timespec64 atime, mtime, ctime, btime; int op, caps, wanted, dirty; u32 seq, issue_seq, mseq, time_warp_seq; u32 flags; @@ -1160,7 +1160,6 @@ static int send_cap_msg(struct cap_msg_args *arg) struct ceph_msg *msg; void *p; size_t extra_len; - struct timespec64 zerotime = {0}; struct ceph_osd_client *osdc = &arg->session->s_mdsc->fsc->client->osdc;
dout("send_cap_msg %s %llx %llx caps %s wanted %s dirty %s" @@ -1251,7 +1250,7 @@ static int send_cap_msg(struct cap_msg_args *arg) * We just zero these out for now, as the MDS ignores them unless * the requisite feature flags are set (which we don't do yet). */ - ceph_encode_timespec64(p, &zerotime); + ceph_encode_timespec64(p, &arg->btime); p += sizeof(struct ceph_timespec); ceph_encode_64(&p, 0);
@@ -1379,6 +1378,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, arg.mtime = inode->i_mtime; arg.atime = inode->i_atime; arg.ctime = inode->i_ctime; + arg.btime = ci->i_btime;
arg.op = op; arg.caps = cap->implemented; @@ -1438,6 +1438,7 @@ static inline int __send_flush_snap(struct inode *inode, arg.atime = capsnap->atime; arg.mtime = capsnap->mtime; arg.ctime = capsnap->ctime; + arg.btime = capsnap->btime;
arg.op = CEPH_CAP_OP_FLUSHSNAP; arg.caps = capsnap->issued; @@ -3044,6 +3045,7 @@ struct cap_extra_info { u64 nsubdirs; /* currently issued */ int issued; + struct timespec64 btime; };
/* @@ -3130,6 +3132,7 @@ static void handle_cap_grant(struct inode *inode, inode->i_mode = le32_to_cpu(grant->mode); inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid)); inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid)); + ci->i_btime = extra_info->btime; may btime change? If not, we don't need to update it.
Yes, it can change. Consider the case where we're restoring from backup.
dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode, from_kuid(&init_user_ns, inode->i_uid), from_kgid(&init_user_ns, inode->i_gid)); @@ -3851,17 +3854,20 @@ void ceph_handle_caps(struct ceph_mds_session *session, } }
- if (msg_version >= 11) { + if (msg_version >= 9) { struct ceph_timespec *btime; u64 change_attr; - u32 flags;
- /* version >= 9 */ if (p + sizeof(*btime) > end) goto bad; btime = p; + ceph_decode_timespec64(&extra_info.btime, btime); p += sizeof(*btime); ceph_decode_64_safe(&p, end, change_attr, bad); + } + + if (msg_version >= 11) { + u32 flags; /* version >= 10 */ ceph_decode_32_safe(&p, end, flags, bad); /* version >= 11 */ diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 72c6c022f02b..854308e13f12 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -606,6 +606,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, capsnap->mtime = inode->i_mtime; capsnap->atime = inode->i_atime; capsnap->ctime = inode->i_ctime; + capsnap->btime = ci->i_btime; capsnap->time_warp_seq = ci->i_time_warp_seq; capsnap->truncate_size = ci->i_truncate_size; capsnap->truncate_seq = ci->i_truncate_seq; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 3dd9d467bb80..c3cb942e08b0 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -197,7 +197,7 @@ struct ceph_cap_snap { u64 xattr_version;
u64 size; - struct timespec64 mtime, atime, ctime; + struct timespec64 mtime, atime, ctime, btime; u64 time_warp_seq; u64 truncate_size; u32 truncate_seq; -- 2.21.0 _______________________________________________ Dev mailing list -- dev@ceph.io To unsubscribe send an email to dev-leave@ceph.io
-- Jeff Layton <jlayton@kernel.org>
Now that the client can handle either address formatting, advertise to the peer that we can support it. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- include/linux/ceph/ceph_features.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/ceph/ceph_features.h b/include/linux/ceph/ceph_features.h index 65a38c4a02a1..39e6f4c57580 100644 --- a/include/linux/ceph/ceph_features.h +++ b/include/linux/ceph/ceph_features.h @@ -211,6 +211,7 @@ DEFINE_CEPH_FEATURE_DEPRECATED(63, 1, RESERVED_BROKEN, LUMINOUS) // client-facin CEPH_FEATURE_MON_STATEFUL_SUB | \ CEPH_FEATURE_CRUSH_TUNABLES5 | \ CEPH_FEATURE_NEW_OSDOPREPLY_ENCODING | \ + CEPH_FEATURE_MSG_ADDR2 | \ CEPH_FEATURE_CEPHX_V2) #define CEPH_FEATURES_REQUIRED_DEFAULT 0 -- 2.21.0
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/inode.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 211947e3c737..d06c492a2947 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -2307,7 +2307,7 @@ static int statx_to_caps(u32 want) { int mask = 0; - if (want & (STATX_MODE|STATX_UID|STATX_GID|STATX_CTIME)) + if (want & (STATX_MODE|STATX_UID|STATX_GID|STATX_CTIME|STATX_BTIME)) mask |= CEPH_CAP_AUTH_SHARED; if (want & (STATX_NLINK|STATX_CTIME)) @@ -2332,6 +2332,7 @@ int ceph_getattr(const struct path *path, struct kstat *stat, { struct inode *inode = d_inode(path->dentry); struct ceph_inode_info *ci = ceph_inode(inode); + u32 valid_mask = STATX_BASIC_STATS; int err = 0; /* Skip the getattr altogether if we're asked not to sync */ @@ -2344,6 +2345,16 @@ int ceph_getattr(const struct path *path, struct kstat *stat, generic_fillattr(inode, stat); stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino); + + /* + * btime on newly-allocated inodes is 0, so if this is still set to + * that, then assume that it's not valid. + */ + if (ci->i_btime.tv_sec || ci->i_btime.tv_nsec) { + stat->btime = ci->i_btime; + valid_mask |= STATX_BTIME; + } + if (ceph_snap(inode) == CEPH_NOSNAP) stat->dev = inode->i_sb->s_dev; else @@ -2367,7 +2378,6 @@ int ceph_getattr(const struct path *path, struct kstat *stat, stat->nlink = 1 + 1 + ci->i_subdirs; } - /* Mask off any higher bits (e.g. btime) until we have support */ - stat->result_mask = request_mask & STATX_BASIC_STATS; + stat->result_mask = request_mask & valid_mask; return err; } -- 2.21.0
Machines can be independently updating iversion themselves, while working under comprehensive sets of caps on an inode. Add a new function that will update a raw value with a larger one. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- include/linux/iversion.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/linux/iversion.h b/include/linux/iversion.h index be50ef7cedab..2917ef990d43 100644 --- a/include/linux/iversion.h +++ b/include/linux/iversion.h @@ -112,6 +112,30 @@ inode_peek_iversion_raw(const struct inode *inode) return atomic64_read(&inode->i_version); } +/** + * inode_set_max_iversion_raw - update i_version new value is larger + * @inode: inode to set + * @val: new i_version to set + * + * Some self-managed filesystems (e.g Ceph) will only update the i_version + * value if the new value is larger than the one we already have. + */ +static inline void +inode_set_max_iversion_raw(struct inode *inode, u64 val) +{ + u64 cur, old; + + cur = inode_peek_iversion_raw(inode); + for (;;) { + if (cur > val) + break; + old = atomic64_cmpxchg(&inode->i_version, cur, val); + if (likely(old == cur)) + break; + cur = old; + } +} + /** * inode_set_iversion - set i_version to a particular value * @inode: inode to set -- 2.21.0
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/inode.c | 5 +++++ fs/ceph/mds_client.c | 4 ++-- fs/ceph/mds_client.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index d06c492a2947..fb32db134509 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -13,6 +13,7 @@ #include <linux/posix_acl.h> #include <linux/random.h> #include <linux/sort.h> +#include <linux/iversion.h> #include "super.h" #include "mds_client.h" @@ -42,6 +43,7 @@ static int ceph_set_ino_cb(struct inode *inode, void *data) { ceph_inode(inode)->i_vino = *(struct ceph_vino *)data; inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data); + inode_set_iversion_raw(inode, 0); return 0; } @@ -805,6 +807,9 @@ static int fill_inode(struct inode *inode, struct page *locked_page, le64_to_cpu(info->version) > (ci->i_version & ~1))) new_version = true; + /* Update change_attribute */ + inode_set_max_iversion_raw(inode, iinfo->change_attr); + __ceph_caps_issued(ci, &issued); issued |= __ceph_caps_dirty(ci); new_issued = ~issued & info_caps; diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 7bc0a6f4bb2e..93b3a1e3ba9c 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -156,7 +156,7 @@ static int parse_reply_info_in(void **p, void *end, ceph_decode_copy(p, &info->btime, sizeof(info->btime)); /* change attribute */ - ceph_decode_skip_64(p, end, bad); + ceph_decode_64_safe(p, end, info->change_attr, bad); /* dir pin */ if (struct_v >= 2) { @@ -208,7 +208,7 @@ static int parse_reply_info_in(void **p, void *end, if (features & CEPH_FEATURE_FS_BTIME) { ceph_decode_need(p, end, sizeof(info->btime), bad); ceph_decode_copy(p, &info->btime, sizeof(info->btime)); - ceph_decode_skip_64(p, end, bad); + ceph_decode_64_safe(p, end, info->change_attr, bad); } info->dir_pin = -ENODATA; diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index da2f53646217..f7c8603484fe 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -71,6 +71,7 @@ struct ceph_mds_reply_info_in { s32 dir_pin; struct ceph_timespec btime; struct ceph_timespec snap_btime; + u64 change_attr; }; struct ceph_mds_reply_dir_entry { -- 2.21.0
Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/caps.c | 19 ++++++++++--------- fs/ceph/snap.c | 2 ++ fs/ceph/super.h | 1 + 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 623b82684e90..2e22efd79b0c 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -8,6 +8,7 @@ #include <linux/vmalloc.h> #include <linux/wait.h> #include <linux/writeback.h> +#include <linux/iversion.h> #include "super.h" #include "mds_client.h" @@ -1138,6 +1139,7 @@ struct cap_msg_args { u64 ino, cid, follows; u64 flush_tid, oldest_flush_tid, size, max_size; u64 xattr_version; + u64 change_attr; struct ceph_buffer *xattr_buf; struct timespec64 atime, mtime, ctime, btime; int op, caps, wanted, dirty; @@ -1244,15 +1246,10 @@ static int send_cap_msg(struct cap_msg_args *arg) /* pool namespace (version 8) (mds always ignores this) */ ceph_encode_32(&p, 0); - /* - * btime and change_attr (version 9) - * - * We just zero these out for now, as the MDS ignores them unless - * the requisite feature flags are set (which we don't do yet). - */ + /* btime and change_attr (version 9) */ ceph_encode_timespec64(p, &arg->btime); p += sizeof(struct ceph_timespec); - ceph_encode_64(&p, 0); + ceph_encode_64(&p, arg->change_attr); /* Advisory flags (version 10) */ ceph_encode_32(&p, arg->flags); @@ -1379,6 +1376,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, arg.atime = inode->i_atime; arg.ctime = inode->i_ctime; arg.btime = ci->i_btime; + arg.change_attr = inode_peek_iversion_raw(inode); arg.op = op; arg.caps = cap->implemented; @@ -1439,6 +1437,7 @@ static inline int __send_flush_snap(struct inode *inode, arg.mtime = capsnap->mtime; arg.ctime = capsnap->ctime; arg.btime = capsnap->btime; + arg.change_attr = capsnap->change_attr; arg.op = CEPH_CAP_OP_FLUSHSNAP; arg.caps = capsnap->issued; @@ -3043,6 +3042,7 @@ struct cap_extra_info { bool dirstat_valid; u64 nfiles; u64 nsubdirs; + u64 change_attr; /* currently issued */ int issued; struct timespec64 btime; @@ -3127,6 +3127,8 @@ static void handle_cap_grant(struct inode *inode, __check_cap_issue(ci, cap, newcaps); + inode_set_max_iversion_raw(inode, extra_info->change_attr); + if ((newcaps & CEPH_CAP_AUTH_SHARED) && (extra_info->issued & CEPH_CAP_AUTH_EXCL) == 0) { inode->i_mode = le32_to_cpu(grant->mode); @@ -3856,14 +3858,13 @@ void ceph_handle_caps(struct ceph_mds_session *session, if (msg_version >= 9) { struct ceph_timespec *btime; - u64 change_attr; if (p + sizeof(*btime) > end) goto bad; btime = p; ceph_decode_timespec64(&extra_info.btime, btime); p += sizeof(*btime); - ceph_decode_64_safe(&p, end, change_attr, bad); + ceph_decode_64_safe(&p, end, extra_info.change_attr, bad); } if (msg_version >= 11) { diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 854308e13f12..4c6494eb02b5 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -3,6 +3,7 @@ #include <linux/sort.h> #include <linux/slab.h> +#include <linux/iversion.h> #include "super.h" #include "mds_client.h" #include <linux/ceph/decode.h> @@ -607,6 +608,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, capsnap->atime = inode->i_atime; capsnap->ctime = inode->i_ctime; capsnap->btime = ci->i_btime; + capsnap->change_attr = inode_peek_iversion_raw(inode); capsnap->time_warp_seq = ci->i_time_warp_seq; capsnap->truncate_size = ci->i_truncate_size; capsnap->truncate_seq = ci->i_truncate_seq; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index c3cb942e08b0..8ecbcd7d45e8 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -197,6 +197,7 @@ struct ceph_cap_snap { u64 xattr_version; u64 size; + u64 change_attr; struct timespec64 mtime, atime, ctime, btime; u64 time_warp_seq; u64 truncate_size; -- 2.21.0
We don't set SB_I_VERSION on ceph since we need to manage it ourselves, so we must increment it whenever we update the file times. Signed-off-by: Jeff Layton <jlayton@kernel.org> --- fs/ceph/addr.c | 2 ++ fs/ceph/file.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index a47c541f8006..e078cc55b989 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -10,6 +10,7 @@ #include <linux/pagevec.h> #include <linux/task_io_accounting_ops.h> #include <linux/signal.h> +#include <linux/iversion.h> #include "super.h" #include "mds_client.h" @@ -1576,6 +1577,7 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) /* Update time before taking page lock */ file_update_time(vma->vm_file); + inode_inc_iversion_raw(inode); do { lock_page(page); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index a7080783fe20..e993ffeae9de 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -10,6 +10,7 @@ #include <linux/namei.h> #include <linux/writeback.h> #include <linux/falloc.h> +#include <linux/iversion.h> #include "super.h" #include "mds_client.h" @@ -1434,6 +1435,8 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) if (err) goto out; + inode_inc_iversion_raw(inode); + if (ci->i_inline_version != CEPH_INLINE_NONE) { err = ceph_uninline_data(file, NULL); if (err < 0) @@ -2065,6 +2068,8 @@ static ssize_t ceph_copy_file_range(struct file *src_file, loff_t src_off, do_final_copy = true; file_update_time(dst_file); + inode_inc_iversion_raw(dst_inode); + if (endoff > size) { int caps_flags = 0; -- 2.21.0
participants (2)
-
Jeff Layton
-
Yan, Zheng