diff options
| -rw-r--r-- | libglusterfs/src/dict.c | 59 | ||||
| -rw-r--r-- | libglusterfs/src/glusterfs/dict.h | 5 | ||||
| -rw-r--r-- | libglusterfs/src/glusterfs/glusterfs.h | 3 | ||||
| -rw-r--r-- | libglusterfs/src/glusterfs/iatt.h | 20 | ||||
| -rw-r--r-- | libglusterfs/src/libglusterfs.sym | 3 | ||||
| -rw-r--r-- | rpc/xdr/src/glusterfs-fops.x | 1 | ||||
| -rw-r--r-- | rpc/xdr/src/glusterfs3.h | 59 | ||||
| -rw-r--r-- | rpc/xdr/src/glusterfs4-xdr.x | 12 | ||||
| -rw-r--r-- | rpc/xdr/src/libgfxdr.sym | 3 | ||||
| -rw-r--r-- | tests/basic/ctime/ctime-mdata-legacy-files.t | 83 | ||||
| -rw-r--r-- | xlators/features/utime/src/utime-messages.h | 3 | ||||
| -rw-r--r-- | xlators/features/utime/src/utime.c | 154 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix-inode-fd-ops.c | 17 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix-messages.h | 3 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix-metadata.c | 103 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix-metadata.h | 4 | 
16 files changed, 475 insertions, 57 deletions
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c index 2a317e36981..b44dda33f00 100644 --- a/libglusterfs/src/dict.c +++ b/libglusterfs/src/dict.c @@ -118,6 +118,7 @@ int32_t  is_data_equal(data_t *one, data_t *two)  {      struct iatt *iatt1, *iatt2; +    struct mdata_iatt *mdata_iatt1, *mdata_iatt2;      if (!one || !two || !one->data || !two->data) {          gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, @@ -182,6 +183,24 @@ is_data_equal(data_t *one, data_t *two)          */          return 1;      } +    if (one->data_type == GF_DATA_TYPE_MDATA) { +        if ((one->len < sizeof(struct mdata_iatt)) || +            (two->len < sizeof(struct mdata_iatt))) { +            return 0; +        } +        mdata_iatt1 = (struct mdata_iatt *)one->data; +        mdata_iatt2 = (struct mdata_iatt *)two->data; + +        if (mdata_iatt1->ia_atime != mdata_iatt2->ia_atime || +            mdata_iatt1->ia_mtime != mdata_iatt2->ia_mtime || +            mdata_iatt1->ia_ctime != mdata_iatt2->ia_ctime || +            mdata_iatt1->ia_atime_nsec != mdata_iatt2->ia_atime_nsec || +            mdata_iatt1->ia_mtime_nsec != mdata_iatt2->ia_mtime_nsec || +            mdata_iatt1->ia_ctime_nsec != mdata_iatt2->ia_ctime_nsec) { +            return 0; +        } +        return 1; +    }      if (one->len != two->len)          return 0; @@ -1072,6 +1091,7 @@ static char *data_type_name[GF_DATA_TYPE_MAX] = {      [GF_DATA_TYPE_PTR] = "pointer",      [GF_DATA_TYPE_GFUUID] = "gf-uuid",      [GF_DATA_TYPE_IATT] = "iatt", +    [GF_DATA_TYPE_MDATA] = "mdata",  };  int64_t @@ -2660,6 +2680,45 @@ err:  }  int +dict_set_mdata(dict_t *this, char *key, struct mdata_iatt *mdata, +               bool is_static) +{ +    return dict_set_bin_common(this, key, mdata, sizeof(struct mdata_iatt), +                               is_static, GF_DATA_TYPE_MDATA); +} + +int +dict_get_mdata(dict_t *this, char *key, struct mdata_iatt *mdata) +{ +    data_t *data = NULL; +    int ret = -EINVAL; + +    if (!this || !key || !mdata) { +        goto err; +    } +    ret = dict_get_with_ref(this, key, &data); +    if (ret < 0) { +        goto err; +    } + +    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_MDATA, key, -EINVAL); +    if (data->len < sizeof(struct mdata_iatt)) { +        gf_msg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF, +               "data value for '%s' is smaller than expected", key); +        ret = -ENOBUFS; +        goto err; +    } + +    memcpy(mdata, data->data, min(data->len, sizeof(struct mdata_iatt))); + +err: +    if (data) +        data_unref(data); + +    return ret; +} + +int  dict_set_iatt(dict_t *this, char *key, struct iatt *iatt, bool is_static)  {      return dict_set_bin_common(this, key, iatt, sizeof(struct iatt), is_static, diff --git a/libglusterfs/src/glusterfs/dict.h b/libglusterfs/src/glusterfs/dict.h index 7854c9feaa1..35337251360 100644 --- a/libglusterfs/src/glusterfs/dict.h +++ b/libglusterfs/src/glusterfs/dict.h @@ -391,6 +391,11 @@ GF_MUST_CHECK int  dict_set_iatt(dict_t *this, char *key, struct iatt *iatt, bool is_static);  GF_MUST_CHECK int  dict_get_iatt(dict_t *this, char *key, struct iatt *iatt); +GF_MUST_CHECK int +dict_set_mdata(dict_t *this, char *key, struct mdata_iatt *mdata, +               bool is_static); +GF_MUST_CHECK int +dict_get_mdata(dict_t *this, char *key, struct mdata_iatt *mdata);  void  dict_dump_to_statedump(dict_t *dict, char *dict_name, char *domain); diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h index 18d8d2136f8..d4c800b7416 100644 --- a/libglusterfs/src/glusterfs/glusterfs.h +++ b/libglusterfs/src/glusterfs/glusterfs.h @@ -229,6 +229,9 @@ enum gf_internal_fop_indicator {  #define VIRTUAL_QUOTA_XATTR_CLEANUP_KEY "glusterfs.quota-xattr-cleanup"  #define QUOTA_READ_ONLY_KEY "trusted.glusterfs.quota.read-only" +/* ctime related */ +#define CTIME_MDATA_XDATA_KEY "set-ctime-mdata" +  /* afr related */  #define AFR_XATTR_PREFIX "trusted.afr" diff --git a/libglusterfs/src/glusterfs/iatt.h b/libglusterfs/src/glusterfs/iatt.h index bee7a0afa77..f03d68b02f0 100644 --- a/libglusterfs/src/glusterfs/iatt.h +++ b/libglusterfs/src/glusterfs/iatt.h @@ -92,6 +92,15 @@ struct old_iatt {      uint32_t ia_ctime_nsec;  }; +struct mdata_iatt { +    int64_t ia_atime; /* last access time */ +    int64_t ia_mtime; /* last modification time */ +    int64_t ia_ctime; /* last status change time */ +    uint32_t ia_atime_nsec; +    uint32_t ia_mtime_nsec; +    uint32_t ia_ctime_nsec; +}; +  /* 64-bit mask for valid members in struct iatt. */  #define IATT_TYPE 0x0000000000000001U  #define IATT_MODE 0x0000000000000002U @@ -313,6 +322,17 @@ st_mode_from_ia(ia_prot_t prot, ia_type_t type)      return st_mode;  } +static inline void +iatt_to_mdata(struct mdata_iatt *mdata, struct iatt *iatt) +{ +    mdata->ia_atime = iatt->ia_atime; +    mdata->ia_atime_nsec = iatt->ia_atime_nsec; +    mdata->ia_mtime = iatt->ia_mtime; +    mdata->ia_mtime_nsec = iatt->ia_mtime_nsec; +    mdata->ia_ctime = iatt->ia_ctime; +    mdata->ia_ctime_nsec = iatt->ia_ctime_nsec; +} +  static inline int  iatt_from_stat(struct iatt *iatt, struct stat *stat)  { diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym index 188cda27bc5..60b3f317cc8 100644 --- a/libglusterfs/src/libglusterfs.sym +++ b/libglusterfs/src/libglusterfs.sym @@ -375,6 +375,7 @@ dict_get_bin  dict_get_double  dict_get_gfuuid  dict_get_iatt +dict_get_mdata  dict_get_int16  dict_get_int32  dict_get_int32n @@ -412,6 +413,7 @@ dict_set_dynstrn  dict_set_dynstr_with_alloc  dict_set_gfuuid  dict_set_iatt +dict_set_mdata  dict_set_int16  dict_set_int32  dict_set_int32n @@ -504,6 +506,7 @@ fop_lease_stub  fop_link_stub  fop_lk_stub  fop_log_level +fop_lookup_cbk_stub  fop_lookup_stub  fop_mkdir_stub  fop_mknod_stub diff --git a/rpc/xdr/src/glusterfs-fops.x b/rpc/xdr/src/glusterfs-fops.x index bacf07735f4..651f8def0ba 100644 --- a/rpc/xdr/src/glusterfs-fops.x +++ b/rpc/xdr/src/glusterfs-fops.x @@ -245,5 +245,6 @@ enum gf_dict_data_type_t {          GF_DATA_TYPE_PTR,          GF_DATA_TYPE_GFUUID,          GF_DATA_TYPE_IATT, +        GF_DATA_TYPE_MDATA,          GF_DATA_TYPE_MAX  }; diff --git a/rpc/xdr/src/glusterfs3.h b/rpc/xdr/src/glusterfs3.h index 5521f4d4eca..86b3a4c0e5d 100644 --- a/rpc/xdr/src/glusterfs3.h +++ b/rpc/xdr/src/glusterfs3.h @@ -585,6 +585,34 @@ out:  }  static inline void +gfx_mdata_iatt_to_mdata_iatt(struct gfx_mdata_iatt *gf_mdata_iatt, +                             struct mdata_iatt *mdata_iatt) +{ +    if (!mdata_iatt || !gf_mdata_iatt) +        return; +    mdata_iatt->ia_atime = gf_mdata_iatt->ia_atime; +    mdata_iatt->ia_atime_nsec = gf_mdata_iatt->ia_atime_nsec; +    mdata_iatt->ia_mtime = gf_mdata_iatt->ia_mtime; +    mdata_iatt->ia_mtime_nsec = gf_mdata_iatt->ia_mtime_nsec; +    mdata_iatt->ia_ctime = gf_mdata_iatt->ia_ctime; +    mdata_iatt->ia_ctime_nsec = gf_mdata_iatt->ia_ctime_nsec; +} + +static inline void +gfx_mdata_iatt_from_mdata_iatt(struct gfx_mdata_iatt *gf_mdata_iatt, +                               struct mdata_iatt *mdata_iatt) +{ +    if (!mdata_iatt || !gf_mdata_iatt) +        return; +    gf_mdata_iatt->ia_atime = mdata_iatt->ia_atime; +    gf_mdata_iatt->ia_atime_nsec = mdata_iatt->ia_atime_nsec; +    gf_mdata_iatt->ia_mtime = mdata_iatt->ia_mtime; +    gf_mdata_iatt->ia_mtime_nsec = mdata_iatt->ia_mtime_nsec; +    gf_mdata_iatt->ia_ctime = mdata_iatt->ia_ctime; +    gf_mdata_iatt->ia_ctime_nsec = mdata_iatt->ia_ctime_nsec; +} + +static inline void  gfx_stat_to_iattx(struct gfx_iattx *gf_stat, struct iatt *iatt)  {      if (!iatt || !gf_stat) @@ -721,6 +749,12 @@ dict_to_xdr(dict_t *this, gfx_dict *dict)                  gfx_stat_from_iattx(&xpair->value.gfx_value_u.iatt,                                      (struct iatt *)dpair->value->data);                  break; +            case GF_DATA_TYPE_MDATA: +                index++; +                gfx_mdata_iatt_from_mdata_iatt( +                    &xpair->value.gfx_value_u.mdata_iatt, +                    (struct mdata_iatt *)dpair->value->data); +                break;              case GF_DATA_TYPE_GFUUID:                  index++;                  memcpy(&xpair->value.gfx_value_u.uuid, dpair->value->data, @@ -787,6 +821,7 @@ xdr_to_dict(gfx_dict *dict, dict_t **to)      dict_t *this = NULL;      unsigned char *uuid = NULL;      struct iatt *iatt = NULL; +    struct mdata_iatt *mdata_iatt = NULL;      if (!to || !dict)          goto out; @@ -854,6 +889,30 @@ xdr_to_dict(gfx_dict *dict, dict_t **to)                  gfx_stat_to_iattx(&xpair->value.gfx_value_u.iatt, iatt);                  ret = dict_set_iatt(this, key, iatt, false);                  break; +            case GF_DATA_TYPE_MDATA: +                mdata_iatt = GF_CALLOC(1, sizeof(struct mdata_iatt), +                                       gf_common_mt_char); +                if (!mdata_iatt) { +                    errno = ENOMEM; +                    gf_msg(THIS->name, GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, +                           "failed to allocate memory. key: %s", key); +                    ret = -1; +                    goto out; +                } +                gfx_mdata_iatt_to_mdata_iatt( +                    &xpair->value.gfx_value_u.mdata_iatt, mdata_iatt); +                ret = dict_set_mdata(this, key, mdata_iatt, false); +                if (ret != 0) { +                    GF_FREE(mdata_iatt); +                    gf_msg(THIS->name, GF_LOG_ERROR, ENOMEM, +                           LG_MSG_DICT_SET_FAILED, +                           "failed to set the key (%s)" +                           " into dict", +                           key); +                    ret = -1; +                    goto out; +                } +                break;              case GF_DATA_TYPE_PTR:              case GF_DATA_TYPE_STR_OLD:                  value = GF_MALLOC(xpair->value.gfx_value_u.other.other_len + 1, diff --git a/rpc/xdr/src/glusterfs4-xdr.x b/rpc/xdr/src/glusterfs4-xdr.x index 6d13aafc9eb..30597850e23 100644 --- a/rpc/xdr/src/glusterfs4-xdr.x +++ b/rpc/xdr/src/glusterfs4-xdr.x @@ -46,6 +46,16 @@ struct gfx_iattx {          unsigned int     mode;          /* type of file and rwx mode */  }; +struct gfx_mdata_iatt { +        hyper      ia_atime;      /* last access time */ +        hyper      ia_mtime;      /* last modification time */ +        hyper      ia_ctime;      /* last status change time */ + +        unsigned int     ia_atime_nsec; +        unsigned int     ia_mtime_nsec; +        unsigned int     ia_ctime_nsec; +}; +  union gfx_value switch (gf_dict_data_type_t type) {          case GF_DATA_TYPE_INT:                  hyper value_int; @@ -62,6 +72,8 @@ union gfx_value switch (gf_dict_data_type_t type) {          case GF_DATA_TYPE_PTR:          case GF_DATA_TYPE_STR_OLD:                  opaque other<>; +        case GF_DATA_TYPE_MDATA: +                gfx_mdata_iatt mdata_iatt;  };  /* AUTH */ diff --git a/rpc/xdr/src/libgfxdr.sym b/rpc/xdr/src/libgfxdr.sym index 22cdf30bfda..dd4ac8562bc 100644 --- a/rpc/xdr/src/libgfxdr.sym +++ b/rpc/xdr/src/libgfxdr.sym @@ -251,6 +251,7 @@ xdr_to_write3args  xdr_vector_round_up  xdr_gfx_read_rsp  xdr_gfx_iattx +xdr_gfx_mdata_iatt  xdr_gfx_value  xdr_gfx_dict_pair  xdr_gfx_dict @@ -344,4 +345,4 @@ xdr_compound_req_v2  xdr_gfx_compound_req  xdr_compound_rsp_v2  xdr_gfx_compound_rsp -xdr_gfx_copy_file_range_req
\ No newline at end of file +xdr_gfx_copy_file_range_req diff --git a/tests/basic/ctime/ctime-mdata-legacy-files.t b/tests/basic/ctime/ctime-mdata-legacy-files.t new file mode 100644 index 00000000000..2e782d5c99d --- /dev/null +++ b/tests/basic/ctime/ctime-mdata-legacy-files.t @@ -0,0 +1,83 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +############################################################################### +#Replica volume + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +#Disable ctime and create file, file doesn't contain "trusted.glusterfs.mdata" xattr +TEST $CLI volume set $V0 ctime off + +TEST "mkdir $M0/DIR" +TEST "echo hello_world > $M0/DIR/FILE" + +#Verify absence of xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}0/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}0/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}1/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}1/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}2/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}2/DIR/FILE" + +#Enable ctime +TEST $CLI volume set $V0 ctime on +sleep 3 +TEST stat $M0/DIR/FILE + +#Verify presence "trusted.glusterfs.mdata" xattr on backend +#The lookup above should have created xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}0/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}0/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}1/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}1/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}2/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}2/DIR/FILE" + +############################################################################### +#Disperse Volume + +TEST $CLI volume create $V1 disperse 3 redundancy 1  $H0:$B0/${V1}{0,1,2} +TEST $CLI volume set $V1 performance.stat-prefetch off +TEST $CLI volume start $V1 + +TEST glusterfs --volfile-id=$V1 --volfile-server=$H0 --entry-timeout=0 $M1; + +#Disable ctime and create file, file doesn't contain "trusted.glusterfs.mdata" xattr +TEST $CLI volume set $V1 ctime off +TEST "mkdir $M1/DIR" +TEST "echo hello_world > $M1/DIR/FILE" + +#Verify absence of xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}0/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}0/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}1/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}1/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}2/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}2/DIR/FILE" + +#Enable ctime +TEST $CLI volume set $V1 ctime on +sleep 3 +TEST stat $M1/DIR/FILE + +#Verify presence "trusted.glusterfs.mdata" xattr on backend +#The lookup above should have created xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}0/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}0/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}1/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}1/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}2/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}2/DIR/FILE" + +cleanup; +############################################################################### diff --git a/xlators/features/utime/src/utime-messages.h b/xlators/features/utime/src/utime-messages.h index bac18aba460..bd40265abaf 100644 --- a/xlators/features/utime/src/utime-messages.h +++ b/xlators/features/utime/src/utime-messages.h @@ -23,6 +23,7 @@   * glfs-message-id.h.   */ -GLFS_MSGID(UTIME, UTIME_MSG_NO_MEMORY); +GLFS_MSGID(UTIME, UTIME_MSG_NO_MEMORY, UTIME_MSG_SET_MDATA_FAILED, +           UTIME_MSG_DICT_SET_FAILED);  #endif /* __UTIME_MESSAGES_H__ */ diff --git a/xlators/features/utime/src/utime.c b/xlators/features/utime/src/utime.c index 877c751c764..2a986e71add 100644 --- a/xlators/features/utime/src/utime.c +++ b/xlators/features/utime/src/utime.c @@ -9,8 +9,10 @@  */  #include "utime.h" +#include "utime-helpers.h"  #include "utime-messages.h"  #include "utime-mem-types.h" +#include <glusterfs/call-stub.h>  int32_t  gf_utime_invalidate(xlator_t *this, inode_t *inode) @@ -133,6 +135,124 @@ mem_acct_init(xlator_t *this)  }  int32_t +gf_utime_set_mdata_setxattr_cbk(call_frame_t *frame, void *cookie, +                                xlator_t *this, int op_ret, int op_errno, +                                dict_t *xdata) +{ +    /* Don't fail lookup if mdata setxattr fails */ +    if (op_ret) { +        gf_msg(this->name, GF_LOG_ERROR, op_errno, UTIME_MSG_SET_MDATA_FAILED, +               "dict set of key for set-ctime-mdata failed"); +    } +    call_resume(frame->local); +    return 0; +} + +int32_t +gf_utime_set_mdata_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +                              int32_t op_ret, int32_t op_errno, inode_t *inode, +                              struct iatt *stbuf, dict_t *xdata, +                              struct iatt *postparent) +{ +    dict_t *dict = NULL; +    struct mdata_iatt *mdata = NULL; +    int ret = 0; +    loc_t loc = { +        0, +    }; + +    if (!op_ret && dict_get(xdata, GF_XATTR_MDATA_KEY) == NULL) { +        dict = dict_new(); +        if (!dict) { +            op_errno = ENOMEM; +            goto err; +        } +        mdata = GF_MALLOC(sizeof(struct mdata_iatt), gf_common_mt_char); +        if (mdata == NULL) { +            op_errno = ENOMEM; +            goto err; +        } +        iatt_to_mdata(mdata, stbuf); +        ret = dict_set_mdata(dict, CTIME_MDATA_XDATA_KEY, mdata, _gf_false); +        if (ret < 0) { +            gf_msg(this->name, GF_LOG_WARNING, ENOMEM, UTIME_MSG_NO_MEMORY, +                   "dict set of key for set-ctime-mdata failed"); +            goto err; +        } +        frame->local = fop_lookup_cbk_stub(frame, default_lookup_cbk, op_ret, +                                           op_errno, inode, stbuf, xdata, +                                           postparent); +        if (!frame->local) { +            gf_msg(this->name, GF_LOG_WARNING, ENOMEM, UTIME_MSG_NO_MEMORY, +                   "lookup_cbk stub allocation failed"); +            goto stub_err; +        } + +        loc.inode = inode_ref(inode); +        gf_uuid_copy(loc.gfid, stbuf->ia_gfid); +        STACK_WIND(frame, gf_utime_set_mdata_setxattr_cbk, FIRST_CHILD(this), +                   FIRST_CHILD(this)->fops->setxattr, &loc, dict, 0, NULL); + +        dict_unref(dict); +        inode_unref(loc.inode); +        return 0; +    } + +    STACK_UNWIND_STRICT(lookup, frame, op_ret, op_errno, inode, stbuf, xdata, +                        postparent); +    return 0; + +err: +    if (mdata) { +        GF_FREE(mdata); +    } +stub_err: +    if (dict) { +        dict_unref(dict); +    } +    STACK_UNWIND_STRICT(lookup, frame, -1, op_errno, NULL, NULL, NULL, NULL); +    return 0; +} + +int +gf_utime_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) +{ +    int op_errno = -1; +    int ret = -1; + +    VALIDATE_OR_GOTO(frame, err); +    VALIDATE_OR_GOTO(this, err); +    VALIDATE_OR_GOTO(loc, err); +    VALIDATE_OR_GOTO(loc->inode, err); + +    xdata = xdata ? dict_ref(xdata) : dict_new(); +    if (!xdata) { +        op_errno = ENOMEM; +        goto err; +    } + +    ret = dict_set_int8(xdata, GF_XATTR_MDATA_KEY, 1); +    if (ret < 0) { +        gf_msg(this->name, GF_LOG_WARNING, -ret, UTIME_MSG_DICT_SET_FAILED, +               "%s: Unable to set dict value for %s", loc->path, +               GF_XATTR_MDATA_KEY); +        op_errno = -ret; +        goto free_dict; +    } + +    STACK_WIND(frame, gf_utime_set_mdata_lookup_cbk, FIRST_CHILD(this), +               FIRST_CHILD(this)->fops->lookup, loc, xdata); +    dict_unref(xdata); +    return 0; + +free_dict: +    dict_unref(xdata); +err: +    STACK_UNWIND_STRICT(lookup, frame, -1, op_errno, NULL, NULL, NULL, NULL); +    return 0; +} + +int32_t  init(xlator_t *this)  {      utime_priv_t *utime = NULL; @@ -182,19 +302,27 @@ notify(xlator_t *this, int event, void *data, ...)  }  struct xlator_fops fops = { -    /* TODO: Need to go through other fops and -     *       check if they modify time attributes -     */ -    .rename = gf_utime_rename,       .mknod = gf_utime_mknod, -    .readv = gf_utime_readv,         .fremovexattr = gf_utime_fremovexattr, -    .open = gf_utime_open,           .create = gf_utime_create, -    .mkdir = gf_utime_mkdir,         .writev = gf_utime_writev, -    .rmdir = gf_utime_rmdir,         .fallocate = gf_utime_fallocate, -    .truncate = gf_utime_truncate,   .symlink = gf_utime_symlink, -    .zerofill = gf_utime_zerofill,   .link = gf_utime_link, -    .ftruncate = gf_utime_ftruncate, .unlink = gf_utime_unlink, -    .setattr = gf_utime_setattr,     .fsetattr = gf_utime_fsetattr, -    .opendir = gf_utime_opendir,     .removexattr = gf_utime_removexattr, +    .rename = gf_utime_rename, +    .mknod = gf_utime_mknod, +    .readv = gf_utime_readv, +    .fremovexattr = gf_utime_fremovexattr, +    .open = gf_utime_open, +    .create = gf_utime_create, +    .mkdir = gf_utime_mkdir, +    .writev = gf_utime_writev, +    .rmdir = gf_utime_rmdir, +    .fallocate = gf_utime_fallocate, +    .truncate = gf_utime_truncate, +    .symlink = gf_utime_symlink, +    .zerofill = gf_utime_zerofill, +    .link = gf_utime_link, +    .ftruncate = gf_utime_ftruncate, +    .unlink = gf_utime_unlink, +    .setattr = gf_utime_setattr, +    .fsetattr = gf_utime_fsetattr, +    .opendir = gf_utime_opendir, +    .removexattr = gf_utime_removexattr, +    .lookup = gf_utime_lookup,  };  struct xlator_cbks cbks = {      .invalidate = gf_utime_invalidate, diff --git a/xlators/storage/posix/src/posix-inode-fd-ops.c b/xlators/storage/posix/src/posix-inode-fd-ops.c index 8c9637876ac..dd2b8e007fd 100644 --- a/xlators/storage/posix/src/posix-inode-fd-ops.c +++ b/xlators/storage/posix/src/posix-inode-fd-ops.c @@ -2629,6 +2629,9 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict,      gf_cs_obj_state state = -1;      int i = 0;      int len; +    struct mdata_iatt mdata_iatt = { +        0, +    };      DECLARE_OLD_FS_ID_VAR;      SET_FS_ID(frame->root->uid, frame->root->gid); @@ -2642,6 +2645,20 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict,      priv = this->private;      DISK_SPACE_CHECK_AND_GOTO(frame, priv, xdata, op_ret, op_errno, out); +    ret = dict_get_mdata(dict, CTIME_MDATA_XDATA_KEY, &mdata_iatt); +    if (ret == 0) { +        /* This is initiated by lookup when ctime feature is enabled to create +         * "trusted.glusterfs.mdata" xattr if not present. These are the files +         * which were created when ctime feature is disabled. +         */ +        ret = posix_set_mdata_xattr_legacy_files(this, loc->inode, &mdata_iatt, +                                                 &op_errno); +        if (ret != 0) { +            op_ret = -1; +        } +        goto out; +    } +      MAKE_INODE_HANDLE(real_path, this, loc, NULL);      if (!real_path) {          op_ret = -1; diff --git a/xlators/storage/posix/src/posix-messages.h b/xlators/storage/posix/src/posix-messages.h index 32292756bc4..15e23ff7563 100644 --- a/xlators/storage/posix/src/posix-messages.h +++ b/xlators/storage/posix/src/posix-messages.h @@ -68,6 +68,7 @@ GLFS_MSGID(POSIX, P_MSG_XATTR_FAILED, P_MSG_NULL_GFID, P_MSG_FCNTL_FAILED,             P_MSG_FALLOCATE_FAILED, P_MSG_STOREMDATA_FAILED,             P_MSG_FETCHMDATA_FAILED, P_MSG_GETMDATA_FAILED,             P_MSG_SETMDATA_FAILED, P_MSG_FRESHFILE, P_MSG_MUTEX_FAILED, -           P_MSG_COPY_FILE_RANGE_FAILED, P_MSG_TIMER_DELETE_FAILED); +           P_MSG_COPY_FILE_RANGE_FAILED, P_MSG_TIMER_DELETE_FAILED, +           P_MSG_NOMEM);  #endif /* !_GLUSTERD_MESSAGES_H_ */ diff --git a/xlators/storage/posix/src/posix-metadata.c b/xlators/storage/posix/src/posix-metadata.c index 5a5e6cd744e..647c0bb3a65 100644 --- a/xlators/storage/posix/src/posix-metadata.c +++ b/xlators/storage/posix/src/posix-metadata.c @@ -245,6 +245,10 @@ __posix_get_mdata_xattr(xlator_t *this, const char *real_path, int _fd,      if (ret == -1 || !mdata) {          mdata = GF_CALLOC(1, sizeof(posix_mdata_t), gf_posix_mt_mdata_attr);          if (!mdata) { +            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, P_MSG_NOMEM, +                   "Could not allocate mdata. file: %s: gfid: %s", +                   real_path ? real_path : "null", +                   inode ? uuid_utoa(inode->gfid) : "null");              ret = -1;              goto out;          } @@ -262,18 +266,8 @@ __posix_get_mdata_xattr(xlator_t *this, const char *real_path, int _fd,              }          } else {              /* Failed to get mdata from disk, xattr missing. -             * This happens on two cases. -             * 1. File is created before ctime is enabled. -             * 2. On new file creation. -             * -             * Do nothing, just return success. It is as -             * good as ctime feature is not enabled for this -             * file. For files created before ctime is enabled, -             * time attributes gets updated into ctime structure -             * once the metadata modification fop happens and -             * time attributes become consistent eventually. -             * For new files, it would obviously get updated -             * before the fop completion. +             * This happens when the file is created before +             * ctime is enabled.               */              if (stbuf && op_errno != ENOENT) {                  ret = 0; @@ -345,6 +339,54 @@ posix_compare_timespec(struct timespec *first, struct timespec *second)          return first->tv_sec - second->tv_sec;  } +int +posix_set_mdata_xattr_legacy_files(xlator_t *this, inode_t *inode, +                                   struct mdata_iatt *mdata_iatt, int *op_errno) +{ +    posix_mdata_t *mdata = NULL; +    int ret = 0; + +    GF_VALIDATE_OR_GOTO("posix", this, out); +    GF_VALIDATE_OR_GOTO(this->name, inode, out); + +    LOCK(&inode->lock); +    { +        mdata = GF_CALLOC(1, sizeof(posix_mdata_t), gf_posix_mt_mdata_attr); +        if (!mdata) { +            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, P_MSG_NOMEM, +                   "Could not allocate mdata. gfid: %s", +                   uuid_utoa(inode->gfid)); +            ret = -1; +            *op_errno = ENOMEM; +            goto unlock; +        } + +        mdata->version = 1; +        mdata->flags = 0; +        mdata->ctime.tv_sec = mdata_iatt->ia_ctime; +        mdata->ctime.tv_nsec = mdata_iatt->ia_ctime_nsec; +        mdata->atime.tv_sec = mdata_iatt->ia_atime; +        mdata->atime.tv_nsec = mdata_iatt->ia_atime_nsec; +        mdata->mtime.tv_sec = mdata_iatt->ia_mtime; +        mdata->mtime.tv_nsec = mdata_iatt->ia_mtime_nsec; + +        __inode_ctx_set1(inode, this, (uint64_t *)&mdata); + +        ret = posix_store_mdata_xattr(this, NULL, -1, inode, mdata); +        if (ret) { +            gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_STOREMDATA_FAILED, +                   "gfid: %s key:%s ", uuid_utoa(inode->gfid), +                   GF_XATTR_MDATA_KEY); +            *op_errno = errno; +            goto unlock; +        } +    } +unlock: +    UNLOCK(&inode->lock); +out: +    return ret; +} +  /* posix_set_mdata_xattr updates the posix_mdata_t based on the flag   * in inode context and stores it on disk   */ @@ -372,6 +414,9 @@ posix_set_mdata_xattr(xlator_t *this, const char *real_path, int fd,               */              mdata = GF_CALLOC(1, sizeof(posix_mdata_t), gf_posix_mt_mdata_attr);              if (!mdata) { +                gf_msg(this->name, GF_LOG_ERROR, ENOMEM, P_MSG_NOMEM, +                       "Could not allocate mdata. file: %s: gfid: %s", +                       real_path ? real_path : "null", uuid_utoa(inode->gfid));                  ret = -1;                  goto unlock;              } @@ -386,35 +431,11 @@ posix_set_mdata_xattr(xlator_t *this, const char *real_path, int fd,                  __inode_ctx_set1(inode, this, (uint64_t *)&mdata);              } else {                  /* -                 * This is the first time creating the time -                 * attr. This happens when you activate this -                 * feature, and the legacy file will not have -                 * any xattr set. -                 * -                 * New files will create extended attributes. -                 */ - -                /* -                 * TODO: This is wrong approach, because before -                 * creating fresh xattr, we should consult -                 * to all replica and/or distribution set. -                 * -                 * We should contact the time management -                 * xlators, and ask them to create an xattr. -                 */ -                /* We should not be relying on backend file's -                 * time attributes to load the initial ctime -                 * time attribute structure. This is incorrect -                 * as each replica set would have witnessed the -                 * file creation at different times. -                 * -                 * For new file creation, ctime, atime and mtime -                 * should be same, hence initiate the ctime -                 * structure with the time from the frame. But -                 * for the files which were created before ctime -                 * feature is enabled, this is not accurate but -                 * still fine as the times would get eventually -                 * accurate. +                 * This is the first time creating the time attr. This happens +                 * when you activate this feature. On this code path, only new +                 * files will create mdata xattr. The legacy files (files +                 * created before ctime enabled) will not have any xattr set. +                 * The xattr on legacy file will be set via lookup.                   */                  /* Don't create xattr with utimes/utimensat, only update if diff --git a/xlators/storage/posix/src/posix-metadata.h b/xlators/storage/posix/src/posix-metadata.h index 3416148ea97..dc25e59c66a 100644 --- a/xlators/storage/posix/src/posix-metadata.h +++ b/xlators/storage/posix/src/posix-metadata.h @@ -53,5 +53,9 @@ posix_set_ctime_cfr(call_frame_t *frame, xlator_t *this,                      const char *real_path_in, int fd_in, inode_t *inode_in,                      struct iatt *stbuf_in, const char *read_path_put,                      int fd_out, inode_t *inode_out, struct iatt *stbuf_out); +int +posix_set_mdata_xattr_legacy_files(xlator_t *this, inode_t *inode, +                                   struct mdata_iatt *mdata_iatt, +                                   int *op_errno);  #endif /* _POSIX_METADATA_H */  | 
