#include "ceph_debug.h"
#include "super.h"
#include "decode.h"
#include <linux/xattr.h>
#include <linux/slab.h>
static bool ceph_is_valid_xattr(const char *name)
{
return !strncmp(name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN) ||
!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
}
/*
* These define virtual xattrs exposing the recursive directory
* statistics and layout metadata.
*/
struct ceph_vxattr_cb {
bool readonly;
char *name;
size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
size_t size);
};
/* directories */
static size_t ceph_vxattrcb_entries(struct ceph_inode_info *ci, char *val,
size_t size)
{
return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
}
static size_t ceph_vxattrcb_files(struct ceph_inode_info *ci, char *val,
size_t size)
{
return snprintf(val, size, "%lld", ci->i_files);
}
static size_t ceph_vxattrcb_subdirs(struct ceph_inode_info *ci, char *val,
size_t size)
{
return snprintf(val, size, "%lld", ci->i_subdirs);
}
static size_t ceph_vxattrcb_rentries(struct ceph_inode_info *ci, char *val,
size_t size)
{
return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
}
static size_t ceph_vxattrcb_rfiles(struct ceph_inode_info *ci, char *val,
size_t size)
{
return snprintf(val, size, "%lld", ci->i_rfiles);
}
static size_t ceph_vxattrcb_rsubdirs(struct ceph_inode_info *ci, char *val,
size_t size)
{
return snprintf(val, size, "%lld", ci->i_rsubdirs);
}
static size_t ceph_vxattrcb_rbytes(struct ceph_inode_info *ci, char *val,
size_t size)
{
return snprintf(val, size, "%lld", ci->i_rbytes);
}
static size_t ceph_vxattrcb_rctime(struct ceph_inode_info *ci, char *val,
size_t size)
{
return snprintf(val, size, "%ld.%ld", (long)ci->i_rctime.tv_sec,
(long)ci->i_rctime.tv_nsec);
}
static struct ceph_vxattr_cb ceph_dir_vxattrs[] = {
{ true, "user.ceph.dir.entries", ceph_vxattrcb_entries},
{ true, "user.ceph.dir.files", ceph_vxattrcb_files},
{ true, "user.ceph.dir.subdirs", ceph_vxattrcb_subdirs},
{ true, "user.ceph.dir.rentries", ceph_vxattrcb_rentries},
{ true, "user.ceph.dir.rfiles", ceph_vxattrcb_rfiles},
{ true, "user.ceph.dir.rsubdirs", ceph_vxattrcb_rsubdirs},
{ true, "user.ceph.dir.rbytes", ceph_vxattrcb_rbytes},
{ true, "user.ceph.dir.rctime", ceph_vxattrcb_rctime},
{ true, NULL, NULL }
};
/* files */
static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
size_t size)
{
int ret;
ret = snprintf(val, size,
"chunk_bytes=%lld\nstripe_count=%lld\nobject_size=%lld\n",
(unsigned long long)ceph_file_layout_su(ci->i_layout),
(unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
(unsigned long long)ceph_file_layout_object_size(ci->i_layout));
if (ceph_file_layout_pg_preferred(ci->i_layout))
ret += snprintf(val + ret, size, "preferred_osd=%lld\n",
(unsigned long long)ceph_file_layout_pg_preferred(
ci->i_layout));
return ret;
}
static struct ceph_vxattr_cb ceph_file_vxattrs[] = {
{ true, "user.ceph.layout", ceph_vxattrcb_layout},
{ NULL, NULL }
};
static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode)
{
if (S_ISDIR(inode->i_mode))
return ceph_dir_vxattrs;
else if (S_ISREG(inode->i_mode))
return ceph_file_vxattrs;
return NULL;
}
static struct ceph_vxattr_cb *ceph_match_vxattr(struct ceph_vxattr_cb *vxattr,
const char *name)
{
do {
if (strcmp(vxattr->name, name) == 0)
return vxattr;
vxattr++;
} while (vxattr->name);
return NULL;
}
static int __set_xattr(struct ceph_inode_info *ci,
const char *name, int name_len,
const char *val, int val_len,
int dirty,
int should_free_name, int should_free_val,
struct ceph_inode_xattr **newxattr)
{
struct rb_node **p;
struct rb_node *parent = NULL;
struct ceph_inode_xattr *xattr = NULL;
int c;
int new = 0;
p = &ci->i_xattrs.index.rb_node;
while (*p) {
pare