From: Jeff Layton Date: Mon, 29 Aug 2016 11:16:41 +0000 (-0400) Subject: client: add the ability to set the btime X-Git-Tag: v11.0.1~326^2~9 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=bce221c1b99a564d2f4827d2f28cbe939184d308;p=ceph.git client: add the ability to set the btime This adds a new set of libcephfs calls: ceph_ll_setattrx and ceph_setattrx. This allows clients to set the btime in addition to other values that are typically settable via ceph_setattr calls. Currently, the setattrx mask uses the same CEPH_SETATTR values that the ceph_setattr interface uses. I'm not sure this is what we will want though. Would it be better to rephrase that via STATX_* constants? Signed-off-by: Jeff Layton --- diff --git a/src/client/Client.cc b/src/client/Client.cc index ddf38f9beff..16b4ffaf33f 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -5064,7 +5064,7 @@ out: return r; } -int Client::may_setattr(Inode *in, struct stat *st, int mask, int uid, int gid) +int Client::may_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid) { if (uid < 0) uid = get_uid(); @@ -5084,12 +5084,12 @@ int Client::may_setattr(Inode *in, struct stat *st, int mask, int uid, int gid) r = -EPERM; if (mask & CEPH_SETATTR_UID) { - if (uid != 0 && ((uid_t)uid != in->uid || st->st_uid != in->uid)) + if (uid != 0 && ((uid_t)uid != in->uid || stx->stx_uid != in->uid)) goto out; } if (mask & CEPH_SETATTR_GID) { if (uid != 0 && ((uid_t)uid != in->uid || - (!groups.is_in(st->st_gid) && st->st_gid != in->gid))) + (!groups.is_in(stx->stx_gid) && stx->stx_gid != in->gid))) goto out; } @@ -5097,14 +5097,14 @@ int Client::may_setattr(Inode *in, struct stat *st, int mask, int uid, int gid) if (uid != 0 && (uid_t)uid != in->uid) goto out; - gid_t i_gid = (mask & CEPH_SETATTR_GID) ? st->st_gid : in->gid; + gid_t i_gid = (mask & CEPH_SETATTR_GID) ? stx->stx_gid : in->gid; if (uid != 0 && !groups.is_in(i_gid)) - st->st_mode &= ~S_ISGID; + stx->stx_mode &= ~S_ISGID; } - if (mask & (CEPH_SETATTR_CTIME | CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME)) { + if (mask & (CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME | CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME)) { if (uid != 0 && (uid_t)uid != in->uid) { - int check_mask = CEPH_SETATTR_CTIME; + int check_mask = CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME; if (!(mask & CEPH_SETATTR_MTIME_NOW)) check_mask |= CEPH_SETATTR_MTIME; if (!(mask & CEPH_SETATTR_ATIME_NOW)) @@ -6421,7 +6421,7 @@ int Client::_getattr(Inode *in, int mask, int uid, int gid, bool force) return res; } -int Client::_do_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid, +int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid, InodeRef *inp) { int issued = in->caps_issued(); @@ -6433,8 +6433,8 @@ int Client::_do_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid return -EROFS; } if ((mask & CEPH_SETATTR_SIZE) && - (unsigned long)attr->st_size > in->size && - is_quota_bytes_exceeded(in, (unsigned long)attr->st_size - in->size)) { + (unsigned long)stx->stx_size > in->size && + is_quota_bytes_exceeded(in, (unsigned long)stx->stx_size - in->size)) { return -EDQUOT; } @@ -6486,36 +6486,45 @@ int Client::_do_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid in->ctime = ceph_clock_now(cct); in->cap_dirtier_uid = uid; in->cap_dirtier_gid = gid; - in->mode = (in->mode & ~07777) | (attr->st_mode & 07777); + in->mode = (in->mode & ~07777) | (stx->stx_mode & 07777); mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_MODE; - ldout(cct,10) << "changing mode to " << attr->st_mode << dendl; + ldout(cct,10) << "changing mode to " << stx->stx_mode << dendl; } if (mask & CEPH_SETATTR_UID) { in->ctime = ceph_clock_now(cct); in->cap_dirtier_uid = uid; in->cap_dirtier_gid = gid; - in->uid = attr->st_uid; + in->uid = stx->stx_uid; mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_UID; - ldout(cct,10) << "changing uid to " << attr->st_uid << dendl; + ldout(cct,10) << "changing uid to " << stx->stx_uid << dendl; } if (mask & CEPH_SETATTR_GID) { in->ctime = ceph_clock_now(cct); in->cap_dirtier_uid = uid; in->cap_dirtier_gid = gid; - in->gid = attr->st_gid; + in->gid = stx->stx_gid; mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); mask &= ~CEPH_SETATTR_GID; - ldout(cct,10) << "changing gid to " << attr->st_gid << dendl; + ldout(cct,10) << "changing gid to " << stx->stx_gid << dendl; + } + if (mask & CEPH_SETATTR_BTIME) { + in->ctime = ceph_clock_now(cct); + in->cap_dirtier_uid = uid; + in->cap_dirtier_gid = gid; + in->btime = utime_t(stx->stx_btime, stx->stx_btime_ns); + mark_caps_dirty(in, CEPH_CAP_AUTH_EXCL); + mask &= ~CEPH_SETATTR_BTIME; + ldout(cct,10) << "changing btime to " << in->btime << dendl; } } if (in->caps_issued_mask(CEPH_CAP_FILE_EXCL)) { if (mask & (CEPH_SETATTR_MTIME|CEPH_SETATTR_ATIME)) { if (mask & CEPH_SETATTR_MTIME) - in->mtime = utime_t(stat_get_mtime_sec(attr), stat_get_mtime_nsec(attr)); + in->mtime = utime_t(stx->stx_mtime, stx->stx_mtime_ns); if (mask & CEPH_SETATTR_ATIME) - in->atime = utime_t(stat_get_atime_sec(attr), stat_get_atime_nsec(attr)); + in->atime = utime_t(stx->stx_atime, stx->stx_atime_ns); in->ctime = ceph_clock_now(cct); in->cap_dirtier_uid = uid; in->cap_dirtier_gid = gid; @@ -6539,35 +6548,38 @@ force_request: req->set_inode(in); if (mask & CEPH_SETATTR_MODE) { - req->head.args.setattr.mode = attr->st_mode; + req->head.args.setattr.mode = stx->stx_mode; req->inode_drop |= CEPH_CAP_AUTH_SHARED; - ldout(cct,10) << "changing mode to " << attr->st_mode << dendl; + ldout(cct,10) << "changing mode to " << stx->stx_mode << dendl; } if (mask & CEPH_SETATTR_UID) { - req->head.args.setattr.uid = attr->st_uid; + req->head.args.setattr.uid = stx->stx_uid; req->inode_drop |= CEPH_CAP_AUTH_SHARED; - ldout(cct,10) << "changing uid to " << attr->st_uid << dendl; + ldout(cct,10) << "changing uid to " << stx->stx_uid << dendl; } if (mask & CEPH_SETATTR_GID) { - req->head.args.setattr.gid = attr->st_gid; + req->head.args.setattr.gid = stx->stx_gid; req->inode_drop |= CEPH_CAP_AUTH_SHARED; - ldout(cct,10) << "changing gid to " << attr->st_gid << dendl; + ldout(cct,10) << "changing gid to " << stx->stx_gid << dendl; } if (mask & CEPH_SETATTR_MTIME) { - utime_t mtime = utime_t(stat_get_mtime_sec(attr), stat_get_mtime_nsec(attr)); - req->head.args.setattr.mtime = mtime; + req->head.args.setattr.mtime = utime_t(stx->stx_mtime, stx->stx_mtime_ns); req->inode_drop |= CEPH_CAP_AUTH_SHARED | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR; } if (mask & CEPH_SETATTR_ATIME) { - utime_t atime = utime_t(stat_get_atime_sec(attr), stat_get_atime_nsec(attr)); - req->head.args.setattr.atime = atime; + req->head.args.setattr.atime = utime_t(stx->stx_atime, stx->stx_atime_ns); + req->inode_drop |= CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_RD | + CEPH_CAP_FILE_WR; + } + if (mask & CEPH_SETATTR_BTIME) { + req->head.args.setattr.btime = utime_t(stx->stx_btime, stx->stx_btime_ns); req->inode_drop |= CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR; } if (mask & CEPH_SETATTR_SIZE) { - if ((unsigned long)attr->st_size < mdsmap->get_max_filesize()) - req->head.args.setattr.size = attr->st_size; + if ((unsigned long)stx->stx_size < mdsmap->get_max_filesize()) + req->head.args.setattr.size = stx->stx_size; else { //too big! put_request(req); return -EFBIG; @@ -6584,29 +6596,51 @@ force_request: return res; } -int Client::_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid, +/* Note that we only care about attrs that setattr cares about */ +void Client::stat_to_statx(struct stat *st, struct ceph_statx *stx) +{ + stx->stx_size = st->st_size; + stx->stx_mode = st->st_mode; + stx->stx_uid = st->st_uid; + stx->stx_gid = st->st_gid; + stx->stx_mtime = stat_get_mtime_sec(st); + stx->stx_mtime_ns = stat_get_mtime_nsec(st); + stx->stx_atime = stat_get_atime_sec(st); + stx->stx_atime_ns = stat_get_atime_nsec(st); +} + +int Client::__setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid, InodeRef *inp) { - int ret = _do_setattr(in, attr, mask, uid, gid, inp); + int ret = _do_setattr(in, stx, mask, uid, gid, inp); if (ret < 0) return ret; if (mask & CEPH_SETATTR_MODE) - ret = _posix_acl_chmod(in, attr->st_mode, uid, gid); + ret = _posix_acl_chmod(in, stx->stx_mode, uid, gid); return ret; } -int Client::_setattr(InodeRef &in, struct stat *attr, int mask) +int Client::_setattrx(InodeRef &in, struct ceph_statx *stx, int mask) { mask &= (CEPH_SETATTR_MODE | CEPH_SETATTR_UID | CEPH_SETATTR_GID | CEPH_SETATTR_MTIME | CEPH_SETATTR_ATIME | CEPH_SETATTR_SIZE | - CEPH_SETATTR_CTIME); + CEPH_SETATTR_CTIME | CEPH_SETATTR_BTIME); if (cct->_conf->client_permissions) { - int r = may_setattr(in.get(), attr, mask); + int r = may_setattr(in.get(), stx, mask); if (r < 0) return r; } - return _setattr(in.get(), attr, mask); + return __setattrx(in.get(), stx, mask); +} + +int Client::_setattr(InodeRef &in, struct stat *attr, int mask) +{ + struct ceph_statx stx; + + stat_to_statx(attr, &stx); + mask &= ~CEPH_SETATTR_BTIME; + return _setattrx(in, &stx, mask); } int Client::setattr(const char *relpath, struct stat *attr, int mask) @@ -6624,6 +6658,21 @@ int Client::setattr(const char *relpath, struct stat *attr, int mask) return _setattr(in, attr, mask); } +int Client::setattrx(const char *relpath, struct ceph_statx *stx, int mask, int flags) +{ + Mutex::Locker lock(client_lock); + tout(cct) << "setattrx" << std::endl; + tout(cct) << relpath << std::endl; + tout(cct) << mask << std::endl; + + filepath path(relpath); + InodeRef in; + int r = path_walk(path, &in, flags & AT_SYMLINK_NOFOLLOW); + if (r < 0) + return r; + return _setattrx(in, stx, mask); +} + int Client::fsetattr(int fd, struct stat *attr, int mask) { Mutex::Locker lock(client_lock); @@ -8844,9 +8893,9 @@ int Client::_flush(Fh *f) int Client::truncate(const char *relpath, loff_t length) { - struct stat attr; - attr.st_size = length; - return setattr(relpath, &attr, CEPH_SETATTR_SIZE); + struct ceph_statx stx; + stx.stx_size = length; + return setattrx(relpath, &stx, CEPH_SETATTR_SIZE); } int Client::ftruncate(int fd, loff_t length) @@ -9859,41 +9908,66 @@ int Client::ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want, return res; } -int Client::ll_setattr(Inode *in, struct stat *attr, int mask, int uid, - int gid) +int Client::_ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, + int gid, InodeRef *inp) { Mutex::Locker lock(client_lock); vinodeno_t vino = _get_vino(in); - ldout(cct, 3) << "ll_setattr " << vino << " mask " << hex << mask << dec + ldout(cct, 3) << "ll_setattrx " << vino << " mask " << hex << mask << dec << dendl; - tout(cct) << "ll_setattr" << std::endl; + tout(cct) << "ll_setattrx" << std::endl; tout(cct) << vino.ino.val << std::endl; - tout(cct) << attr->st_mode << std::endl; - tout(cct) << attr->st_uid << std::endl; - tout(cct) << attr->st_gid << std::endl; - tout(cct) << attr->st_size << std::endl; - tout(cct) << attr->st_mtime << std::endl; - tout(cct) << attr->st_atime << std::endl; + tout(cct) << stx->stx_mode << std::endl; + tout(cct) << stx->stx_uid << std::endl; + tout(cct) << stx->stx_gid << std::endl; + tout(cct) << stx->stx_size << std::endl; + tout(cct) << stx->stx_mtime << std::endl; + tout(cct) << stx->stx_atime << std::endl; + tout(cct) << stx->stx_btime << std::endl; tout(cct) << mask << std::endl; if (!cct->_conf->fuse_default_permissions) { - int res = may_setattr(in, attr, mask, uid, gid); + int res = may_setattr(in, stx, mask, uid, gid); if (res < 0) return res; } mask &= ~(CEPH_SETATTR_MTIME_NOW | CEPH_SETATTR_ATIME_NOW); + return __setattrx(in, stx, mask, uid, gid, inp); +} + +int Client::ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid, + int gid) +{ + InodeRef target(in); + int res = _ll_setattrx(in, stx, mask, uid, gid, &target); + if (res == 0) { + assert(in == target.get()); + fill_statx(in, in->caps_issued(), stx); + } + + ldout(cct, 3) << "ll_setattrx " << _get_vino(in) << " = " << res << dendl; + return res; +} + +int Client::ll_setattr(Inode *in, struct stat *attr, int mask, int uid, + int gid) +{ + struct ceph_statx stx; + + stat_to_statx(attr, &stx); + InodeRef target(in); - int res = _setattr(in, attr, mask, uid, gid, &target); + int res = _ll_setattrx(in, &stx, mask, uid, gid, &target); if (res == 0) { assert(in == target.get()); fill_stat(in, attr); } - ldout(cct, 3) << "ll_setattr " << vino << " = " << res << dendl; + ldout(cct, 3) << "ll_setattr " << _get_vino(in) << " = " << res << dendl; return res; } @@ -10217,9 +10291,9 @@ int Client::_setxattr(Inode *in, const char *name, const void *value, size = 0; } if (new_mode != in->mode) { - struct stat attr; - attr.st_mode = new_mode; - ret = _do_setattr(in, &attr, CEPH_SETATTR_MODE, uid, gid, NULL); + struct ceph_statx stx; + stx.stx_mode = new_mode; + ret = _do_setattr(in, &stx, CEPH_SETATTR_MODE, uid, gid, NULL); if (ret < 0) return ret; } diff --git a/src/client/Client.h b/src/client/Client.h index 4413d4b4591..e5c655c4fbd 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -773,9 +773,13 @@ private: int _rmdir(Inode *dir, const char *name, int uid=-1, int gid=-1); int _symlink(Inode *dir, const char *name, const char *target, int uid=-1, int gid=-1, InodeRef *inp = 0); int _mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, int uid=-1, int gid=-1, InodeRef *inp = 0); - int _do_setattr(Inode *in, struct stat *attr, int mask, int uid, int gid, InodeRef *inp); - int _setattr(Inode *in, struct stat *attr, int mask, int uid=-1, int gid=-1, InodeRef *inp = 0); + int _do_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid, int gid, InodeRef *inp); + void stat_to_statx(struct stat *st, struct ceph_statx *stx); + int __setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid=-1, int gid=-1, InodeRef *inp = 0); + int _setattrx(InodeRef &in, struct ceph_statx *stx, int mask); int _setattr(InodeRef &in, struct stat *attr, int mask); + int _ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid = -1, + int gid = -1, InodeRef *inp = 0); int _getattr(Inode *in, int mask, int uid=-1, int gid=-1, bool force=false); int _getattr(InodeRef &in, int mask, int uid=-1, int gid=-1, bool force=false) { return _getattr(in.get(), mask, uid, gid, force); @@ -845,7 +849,7 @@ private: int inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want); int xattr_permission(Inode *in, const char *name, unsigned want, int uid=-1, int gid=-1); - int may_setattr(Inode *in, struct stat *st, int mask, int uid=-1, int gid=-1); + int may_setattr(Inode *in, struct ceph_statx *stx, int mask, int uid=-1, int gid=-1); int may_open(Inode *in, int flags, int uid=-1, int gid=-1); int may_lookup(Inode *dir, int uid=-1, int gid=-1); int may_create(Inode *dir, int uid=-1, int gid=-1); @@ -999,6 +1003,7 @@ public: int lstatlite(const char *path, struct statlite *buf); int setattr(const char *relpath, struct stat *attr, int mask); + int setattrx(const char *relpath, struct ceph_statx *stx, int mask, int flags=0); int fsetattr(int fd, struct stat *attr, int mask); int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode); @@ -1096,6 +1101,8 @@ public: int ll_getattr(Inode *in, struct stat *st, int uid = -1, int gid = -1); int ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want, unsigned int flags, int uid = -1, int gid = -1); + int ll_setattrx(Inode *in, struct ceph_statx *stx, int mask, int uid = -1, + int gid = -1); int ll_setattr(Inode *in, struct stat *st, int mask, int uid = -1, int gid = -1); int ll_getxattr(Inode *in, const char *name, void *value, size_t size, diff --git a/src/client/MetaRequest.h b/src/client/MetaRequest.h index 8eb02048da0..341533ebc1e 100644 --- a/src/client/MetaRequest.h +++ b/src/client/MetaRequest.h @@ -27,7 +27,7 @@ private: public: uint64_t tid; utime_t op_stamp; - ceph_mds_request_head_legacy head; + ceph_mds_request_head head; filepath path, path2; bufferlist data; int inode_drop; //the inode caps this operation will drop diff --git a/src/include/cephfs/libcephfs.h b/src/include/cephfs/libcephfs.h index c550bcd7b02..688702130b6 100644 --- a/src/include/cephfs/libcephfs.h +++ b/src/include/cephfs/libcephfs.h @@ -106,13 +106,14 @@ struct CephContext; /* setattr mask bits */ #ifndef CEPH_SETATTR_MODE -# define CEPH_SETATTR_MODE 1 -# define CEPH_SETATTR_UID 2 -# define CEPH_SETATTR_GID 4 -# define CEPH_SETATTR_MTIME 8 -# define CEPH_SETATTR_ATIME 16 -# define CEPH_SETATTR_SIZE 32 -# define CEPH_SETATTR_CTIME 64 +# define CEPH_SETATTR_MODE 1 +# define CEPH_SETATTR_UID 2 +# define CEPH_SETATTR_GID 4 +# define CEPH_SETATTR_MTIME 8 +# define CEPH_SETATTR_ATIME 16 +# define CEPH_SETATTR_SIZE 32 +# define CEPH_SETATTR_CTIME 64 +# define CEPH_SETATTR_BTIME 512 #endif /* define error codes for the mount function*/ @@ -649,11 +650,23 @@ int ceph_lstat(struct ceph_mount_info *cmount, const char *path, struct stat *st * @param cmount the ceph mount handle to use for performing the setattr. * @param relpath the path to the file/directory to set the attributes of. * @param attr the stat struct that must include attribute values to set on the file. - * @param mask a mask of all the stat values that have been set on the stat struct. + * @param mask a mask of all the CEPH_SETATTR_* values that have been set in the stat struct. * @returns 0 on success or negative error code on failure. */ int ceph_setattr(struct ceph_mount_info *cmount, const char *relpath, struct stat *attr, int mask); +/** + * Set a file's attributes (extended version). + * + * @param cmount the ceph mount handle to use for performing the setattr. + * @param relpath the path to the file/directory to set the attributes of. + * @param stx the statx struct that must include attribute values to set on the file. + * @param mask a mask of all the CEPH_SETATTR_* values that have been set in the statx struct. + * @param flags mask of AT_* flags (only AT_ATTR_NOFOLLOW is respected for now) + * @returns 0 on success or negative error code on failure. + */ +int ceph_setattrx(struct ceph_mount_info *cmount, const char *relpath, struct ceph_statx *stx, int mask, int flags); + /** * Change the mode bits (permissions) of a file/directory. * @@ -1413,6 +1426,8 @@ int ceph_ll_getattrx(struct ceph_mount_info *cmount, struct Inode *in, int uid, int gid); int ceph_ll_setattr(struct ceph_mount_info *cmount, struct Inode *in, struct stat *st, int mask, int uid, int gid); +int ceph_ll_setattrx(struct ceph_mount_info *cmount, struct Inode *in, + struct ceph_statx *stx, int mask, int uid, int gid); int ceph_ll_open(struct ceph_mount_info *cmount, struct Inode *in, int flags, struct Fh **fh, int uid, int gid); off_t ceph_ll_lseek(struct ceph_mount_info *cmount, struct Fh* filehandle, diff --git a/src/libcephfs.cc b/src/libcephfs.cc index c01255e5906..05ddf8e82b4 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -634,6 +634,14 @@ extern "C" int ceph_setattr(struct ceph_mount_info *cmount, const char *relpath, return cmount->get_client()->setattr(relpath, attr, mask); } +extern "C" int ceph_setattrx(struct ceph_mount_info *cmount, const char *relpath, + struct ceph_statx *stx, int mask, int flags) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->setattrx(relpath, stx, mask, flags); +} + // *xattr() calls supporting samba/vfs extern "C" int ceph_getxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size) { @@ -1429,6 +1437,13 @@ extern "C" int ceph_ll_setattr(class ceph_mount_info *cmount, return (cmount->get_client()->ll_setattr(in, st, mask, uid, gid)); } +extern "C" int ceph_ll_setattrx(class ceph_mount_info *cmount, + Inode *in, struct ceph_statx *stx, + int mask, int uid, int gid) +{ + return (cmount->get_client()->ll_setattrx(in, stx, mask, uid, gid)); +} + extern "C" int ceph_ll_open(class ceph_mount_info *cmount, Inode *in, int flags, Fh **fh, int uid, int gid) { diff --git a/src/test/libcephfs/test.cc b/src/test/libcephfs/test.cc index ac34f3f0d19..a4062a95e9b 100644 --- a/src/test/libcephfs/test.cc +++ b/src/test/libcephfs/test.cc @@ -1504,6 +1504,37 @@ TEST(LibCephFS, Btime) { ceph_shutdown(cmount); } +TEST(LibCephFS, SetBtime) { + struct ceph_mount_info *cmount; + ASSERT_EQ(ceph_create(&cmount, NULL), 0); + ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0); + ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); + ASSERT_EQ(ceph_mount(cmount, "/"), 0); + + char filename[32]; + sprintf(filename, "/setbtime%x", getpid()); + + ceph_unlink(cmount, filename); + int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666); + ASSERT_LT(0, fd); + ceph_close(cmount, fd); + + struct ceph_statx stx; + + stx.stx_btime = 1; + stx.stx_btime_ns = 2; + + ASSERT_EQ(ceph_setattrx(cmount, filename, &stx, CEPH_SETATTR_BTIME, 0), 0); + + ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_BTIME, 0), 0); + ASSERT_TRUE(stx.stx_mask & CEPH_STATX_BTIME); + + ASSERT_EQ(stx.stx_btime, 1); + ASSERT_EQ(stx.stx_btime_ns, 2); + + ceph_shutdown(cmount); +} + TEST(LibCephFS, LazyStatx) { struct ceph_mount_info *cmount1, *cmount2; ASSERT_EQ(ceph_create(&cmount1, NULL), 0);