#include <linux/ceph/ceph_debug.h>
#include "super.h"
#include "mds_client.h"
#include <linux/ceph/decode.h>
#include <linux/xattr.h>
#include <linux/slab.h>
#define XATTR_CEPH_PREFIX "ceph."
#define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
static bool ceph_is_valid_xattr(const char *name)
{
return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) ||
!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 {
char *name;
size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
size_t size);
bool readonly;
};
/* 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);
}
#define CEPH_XATTR_NAME(_type, _name) XATTR_CEPH_PREFIX #_type "." #_name
#define XATTR_NAME_CEPH(_type, _name) \
{ \
.name = CEPH_XATTR_NAME(_type, _name), \
.getxattr_cb = ceph_vxattrcb_ ## _name, \
.readonly = true, \
}
static struct ceph_vxattr_cb ceph_dir_vxattrs[] = {
XATTR_NAME_CEPH(dir, entries),
XATTR_NAME_CEPH(dir, files),
XATTR_NAME_CEPH(dir, subdirs),
XATTR_NAME_CEPH(dir, rentries),
XATTR_NAME_CEPH(dir, rfiles),
XATTR_NAME_CEPH(dir, rsubdirs),
XATTR_NAME_CEPH(dir, rbytes),
XATTR_NAME_CEPH(dir, rctime),
{ 0 } /* Required table terminator */
};
/* 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[] = {
XATTR_NAME_CEPH(file, layout),
/* The following extended attribute name is deprecated */
{
.name = XATTR_CEPH_PREFIX "layout",
.getxattr_cb = ceph_vxattrcb_layout,
.readonly = true,
},
{ 0 } /* Required table terminator */
};
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 inode *inode,
const char *name)
{
struct ceph_vxattr_cb *vxattr = ceph_inode_vxattrs(inode);
if (vxattr) {
while (vxattr->name) {
if (!strcmp(vxattr->name, name))
return vxattr;
vxattr++;
}
}
return NULL;
}
static int __set_xattr(struct ceph_inode_info *ci,
<