Skip to content

Commit

Permalink
libcephfs: add a ceph_ll_getattrx and ceph_statx
Browse files Browse the repository at this point in the history
New interfaces for fetching extended (and selective) stat information.
Additionally, applications can specify AT_NO_ATTR_SYNC in the flags to
indicate that they want to do a "lazy" statx that just hands out the
inode info from the cache, or AT_SYMLINK_NOFOLLOW to avoid following
symlinks when walking the path.

Signed-off-by: Jeff Layton <[email protected]>
  • Loading branch information
jtlayton committed Aug 29, 2016
1 parent 2115de0 commit f7c885e
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 0 deletions.
1 change: 1 addition & 0 deletions ceph.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,7 @@ ln -sf %{_libdir}/librbd.so.1 /usr/lib64/qemu/librbd.so.1
%defattr(-,root,root,-)
%dir %{_includedir}/cephfs
%{_includedir}/cephfs/libcephfs.h
%{_includedir}/cephfs/ceph_statx.h
%{_libdir}/libcephfs.so

%files -n python-cephfs
Expand Down
1 change: 1 addition & 0 deletions debian/libcephfs-dev.install
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
usr/include/cephfs/libcephfs.h
usr/include/cephfs/ceph_statx.h
usr/lib/libcephfs.so
137 changes: 137 additions & 0 deletions src/client/Client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
#include "include/assert.h"
#include "include/stat.h"

#include "include/cephfs/ceph_statx.h"

#if HAVE_GETGROUPLIST
#include <grp.h>
#include <pwd.h>
Expand Down Expand Up @@ -6648,6 +6650,56 @@ int Client::stat(const char *relpath, struct stat *stbuf,
return r;
}

unsigned Client::statx_to_mask(unsigned int flags, unsigned int want)
{
unsigned mask = 0;

/* if NO_ATTR_SYNC is set, then we don't need any -- just use what's in cache */
if (flags & AT_NO_ATTR_SYNC)
goto out;

/* Always set PIN to distinguish from AT_NO_ATTR_SYNC case */
mask |= CEPH_CAP_PIN;
if (want & (CEPH_STATX_MODE|CEPH_STATX_UID|CEPH_STATX_GID|CEPH_STATX_RDEV|CEPH_STATX_BTIME))
mask |= CEPH_CAP_AUTH_SHARED;
if (want & CEPH_STATX_NLINK)
mask |= CEPH_CAP_LINK_SHARED;
if (want & (CEPH_STATX_ATIME|CEPH_STATX_MTIME|CEPH_STATX_CTIME|CEPH_STATX_SIZE|CEPH_STATX_BLOCKS))
mask |= CEPH_CAP_FILE_SHARED;

out:
return mask;
}

int Client::statx(const char *relpath, struct ceph_statx *stx,
unsigned int want, unsigned int flags)
{
ldout(cct, 3) << "statx enter (relpath " << relpath << " want " << want << ")" << dendl;
Mutex::Locker lock(client_lock);
tout(cct) << "statx" << std::endl;
tout(cct) << relpath << std::endl;
filepath path(relpath);
InodeRef in;

unsigned mask = statx_to_mask(flags, want);

int r = path_walk(path, &in, flags & AT_SYMLINK_NOFOLLOW, mask);
if (r < 0)
return r;

if (mask && !in->caps_issued_mask(mask)) {
r = _getattr(in, mask);
if (r < 0) {
ldout(cct, 3) << "statx exit on error!" << dendl;
return r;
}
}

fill_statx(in, mask, stx);
ldout(cct, 3) << "statx exit (relpath " << relpath << " mask " << stx->stx_mask << ")" << dendl;
return r;
}

int Client::lstat(const char *relpath, struct stat *stbuf,
frag_info_t *dirstat, int mask)
{
Expand Down Expand Up @@ -6718,6 +6770,74 @@ int Client::fill_stat(Inode *in, struct stat *st, frag_info_t *dirstat, nest_inf
return in->caps_issued();
}

void Client::fill_statx(Inode *in, unsigned int mask, struct ceph_statx *stx)
{
ldout(cct, 10) << "fill_statx on " << in->ino << " snap/dev" << in->snapid
<< " mode 0" << oct << in->mode << dec
<< " mtime " << in->mtime << " ctime " << in->ctime << dendl;
memset(stx, 0, sizeof(struct ceph_statx));

/*
* If mask is 0, then the caller set AT_NO_ATTR_SYNC. Reset the mask
* so that all bits are set.
*/
if (!mask)
mask = ~0;

/* These are always considered to be available */
stx->stx_dev_major = in->snapid >> 32;
stx->stx_dev_minor = (uint32_t)in->snapid;
stx->stx_blksize = MAX(in->layout.stripe_unit, 4096);

if (use_faked_inos())
stx->stx_ino = in->faked_ino;
else
stx->stx_ino = in->ino;
stx->stx_rdev_minor = MINOR(in->rdev);
stx->stx_rdev_major = MAJOR(in->rdev);
stx->stx_mask |= (CEPH_STATX_INO|CEPH_STATX_RDEV);

if (mask & CEPH_CAP_AUTH_SHARED) {
stx->stx_uid = in->uid;
stx->stx_gid = in->gid;
stx->stx_mode = in->mode;
stx->stx_btime = in->btime.sec();
stx->stx_btime_ns = in->btime.nsec();
stx->stx_mask |= (CEPH_STATX_MODE|CEPH_STATX_UID|CEPH_STATX_GID|CEPH_STATX_BTIME);
}

if (mask & CEPH_CAP_LINK_SHARED) {
stx->stx_nlink = in->nlink;
stx->stx_mask |= CEPH_STATX_NLINK;
}

if (mask & CEPH_CAP_FILE_SHARED) {
if (in->ctime > in->mtime) {
stx->stx_ctime = in->ctime.sec();
stx->stx_ctime_ns = in->ctime.nsec();
} else {
stx->stx_ctime = in->mtime.sec();
stx->stx_ctime_ns = in->mtime.nsec();
}
stx->stx_atime = in->atime.sec();
stx->stx_atime_ns = in->atime.nsec();
stx->stx_mtime = in->mtime.sec();
stx->stx_mtime_ns = in->mtime.nsec();

if (in->is_dir()) {
if (cct->_conf->client_dirsize_rbytes)
stx->stx_size = in->rstat.rbytes;
else
stx->stx_size = in->dirstat.size();
stx->stx_blocks = 1;
} else {
stx->stx_size = in->size;
stx->stx_blocks = (in->size + 511) >> 9;
}
stx->stx_mask |= (CEPH_STATX_ATIME|CEPH_STATX_MTIME|CEPH_STATX_CTIME|CEPH_STATX_SIZE|CEPH_STATX_BLOCKS);
}
}

void Client::touch_dn(Dentry *dn)
{
lru.lru_touch(dn);
Expand Down Expand Up @@ -9705,6 +9825,23 @@ int Client::ll_getattr(Inode *in, struct stat *attr, int uid, int gid)
return res;
}

int Client::ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want,
unsigned int flags, int uid, int gid)
{
Mutex::Locker lock(client_lock);

int res = 0;
unsigned mask = statx_to_mask(flags, want);

if (mask && !in->caps_issued_mask(mask))
res = _ll_getattr(in, uid, gid);

if (res == 0)
fill_statx(in, mask, stx);
ldout(cct, 3) << "ll_getattrx " << _get_vino(in) << " = " << res << dendl;
return res;
}

int Client::ll_setattr(Inode *in, struct stat *attr, int mask, int uid,
int gid)
{
Expand Down
10 changes: 10 additions & 0 deletions src/client/Client.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,12 @@ class Client : public Dispatcher, public md_config_obs_t {
int fill_stat(InodeRef& in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0) {
return fill_stat(in.get(), st, dirstat, rstat);
}

void fill_statx(Inode *in, unsigned int mask, struct ceph_statx *stx);
void fill_statx(InodeRef& in, unsigned int mask, struct ceph_statx *stx) {
return fill_statx(in.get(), mask, stx);
}

void touch_dn(Dentry *dn);

// trim cache.
Expand Down Expand Up @@ -987,7 +993,9 @@ class Client : public Dispatcher, public md_config_obs_t {
int symlink(const char *existing, const char *newname);

// inode stuff
unsigned statx_to_mask(unsigned int flags, unsigned int want);
int stat(const char *path, struct stat *stbuf, frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL);
int statx(const char *path, struct ceph_statx *stx, unsigned int want, unsigned int flags);
int lstat(const char *path, struct stat *stbuf, frag_info_t *dirstat=0, int mask=CEPH_STAT_CAP_INODE_ALL);
int lstatlite(const char *path, struct statlite *buf);

Expand Down Expand Up @@ -1087,6 +1095,8 @@ class Client : public Dispatcher, public md_config_obs_t {
bool ll_forget(Inode *in, int count);
bool ll_put(Inode *in);
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_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,
Expand Down
85 changes: 85 additions & 0 deletions src/include/cephfs/ceph_statx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
* scalable distributed file system
*
* Copyright (C) Jeff Layton <[email protected]>
*
* Heavily borrowed from David Howells' draft statx patchset.
*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software
* Foundation. See file COPYING.
*
*/

#ifndef CEPH_CEPH_STATX_H
#define CEPH_CEPH_STATX_H
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
* Since the xstat patches are still a work in progress, we borrow its data
* structures and #defines to implement ceph_getattrx. Once the xstat stuff
* has been merged we should drop this and switch over to using that instead.
*/
struct ceph_statx {
uint32_t stx_mask;
uint32_t stx_information;
uint32_t stx_blksize;
uint32_t stx_nlink;
uint32_t stx_gen;
uint32_t stx_uid;
uint32_t stx_gid;
uint16_t stx_mode;
uint16_t __spare0[1];
uint64_t stx_ino;
uint64_t stx_size;
uint64_t stx_blocks;
uint64_t stx_version;
int64_t stx_atime;
int64_t stx_btime;
int64_t stx_ctime;
int64_t stx_mtime;
int32_t stx_atime_ns;
int32_t stx_btime_ns;
int32_t stx_ctime_ns;
int32_t stx_mtime_ns;
uint32_t stx_rdev_major;
uint32_t stx_rdev_minor;
uint32_t stx_dev_major;
uint32_t stx_dev_minor;
uint64_t __spare1[16];
};

#define CEPH_STATX_MODE 0x00000001U /* Want/got stx_mode */
#define CEPH_STATX_NLINK 0x00000002U /* Want/got stx_nlink */
#define CEPH_STATX_UID 0x00000004U /* Want/got stx_uid */
#define CEPH_STATX_GID 0x00000008U /* Want/got stx_gid */
#define CEPH_STATX_RDEV 0x00000010U /* Want/got stx_rdev */
#define CEPH_STATX_ATIME 0x00000020U /* Want/got stx_atime */
#define CEPH_STATX_MTIME 0x00000040U /* Want/got stx_mtime */
#define CEPH_STATX_CTIME 0x00000080U /* Want/got stx_ctime */
#define CEPH_STATX_INO 0x00000100U /* Want/got stx_ino */
#define CEPH_STATX_SIZE 0x00000200U /* Want/got stx_size */
#define CEPH_STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */
#define CEPH_STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */
#define CEPH_STATX_BTIME 0x00000800U /* Want/got stx_btime */
#define CEPH_STATX_GEN 0x00002000U /* Want/got stx_gen */
#define CEPH_STATX_ALL_STATS 0x00003fffU /* All supported stats */

/* statx request flags. Callers can set these in the "flags" field */
#ifndef AT_NO_ATTR_SYNC
#define AT_NO_ATTR_SYNC 0x4000 /* Don't sync attributes with the server */
#endif

#ifdef __cplusplus
}
#endif

#endif /* CEPH_STATX_H */

18 changes: 18 additions & 0 deletions src/include/cephfs/libcephfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include <stdbool.h>
#include <fcntl.h>

#include "ceph_statx.h"

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -618,6 +620,19 @@ int ceph_rename(struct ceph_mount_info *cmount, const char *from, const char *to
*/
int ceph_stat(struct ceph_mount_info *cmount, const char *path, struct stat *stbuf);

/**
* Get a file's extended statistics and attributes.
*
* @param cmount the ceph mount handle to use for performing the stat.
* @param path the file or directory to get the statistics of.
* @param stx the ceph_statx struct that will be filled in with the file's statistics.
* @param want bitfield of CEPH_STATX_* flags showing designed attributes
* @param flags bitfield that can be used to set AT_* modifier flags (only AT_NO_ATTR_SYNC and AT_SYMLINK_NOFOLLOW)
* @returns 0 on success or negative error code on failure.
*/
int ceph_statx(struct ceph_mount_info *cmount, const char *path, struct ceph_statx *stx,
unsigned int want, unsigned int flags);

/**
* Get a file's statistics and attributes, without following symlinks.
*
Expand Down Expand Up @@ -1393,6 +1408,9 @@ int ceph_ll_walk(struct ceph_mount_info *cmount, const char *name,
struct stat *attr);
int ceph_ll_getattr(struct ceph_mount_info *cmount, struct Inode *in,
struct stat *attr, int uid, int gid);
int ceph_ll_getattrx(struct ceph_mount_info *cmount, struct Inode *in,
struct ceph_statx *stx, unsigned int want, unsigned int flags,
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_open(struct ceph_mount_info *cmount, struct Inode *in, int flags,
Expand Down
16 changes: 16 additions & 0 deletions src/libcephfs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,14 @@ extern "C" int ceph_stat(struct ceph_mount_info *cmount, const char *path,
return cmount->get_client()->stat(path, stbuf);
}

extern "C" int ceph_statx(struct ceph_mount_info *cmount, const char *path,
struct ceph_statx *stx, unsigned int want, unsigned int flags)
{
if (!cmount->is_mounted())
return -ENOTCONN;
return cmount->get_client()->statx(path, stx, want, flags);
}

extern "C" int ceph_lstat(struct ceph_mount_info *cmount, const char *path,
struct stat *stbuf)
{
Expand Down Expand Up @@ -1406,6 +1414,14 @@ extern "C" int ceph_ll_getattr(class ceph_mount_info *cmount,
return (cmount->get_client()->ll_getattr(in, attr, uid, gid));
}

extern "C" int ceph_ll_getattrx(class ceph_mount_info *cmount,
Inode *in, struct ceph_statx *stx,
unsigned int want, unsigned int flags,
int uid, int gid)
{
return (cmount->get_client()->ll_getattrx(in, stx, want, flags, uid, gid));
}

extern "C" int ceph_ll_setattr(class ceph_mount_info *cmount,
Inode *in, struct stat *st,
int mask, int uid, int gid)
Expand Down
Loading

0 comments on commit f7c885e

Please sign in to comment.