afs: Add metadata xattrs
Add xattrs to allow the user to get/set metadata in lieu of having pioctl() available. The following xattrs are now available: - "afs.cell" The name of the cell in which the vnode's volume resides. - "afs.fid" The volume ID, vnode ID and vnode uniquifier of the file as three hex numbers separated by colons. - "afs.volume" The name of the volume in which the vnode resides. For example: # getfattr -d -m ".*" /mnt/scratch getfattr: Removing leading '/' from absolute path names # file: mnt/scratch afs.cell="mycell.myorg.org" afs.fid="10000b:1:1" afs.volume="scratch" Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
fd2498211a
commit
d3e3b7eac8
@ -27,6 +27,7 @@ kafs-objs := \
|
|||||||
vlocation.o \
|
vlocation.o \
|
||||||
vnode.o \
|
vnode.o \
|
||||||
volume.o \
|
volume.o \
|
||||||
write.o
|
write.o \
|
||||||
|
xattr.o
|
||||||
|
|
||||||
obj-$(CONFIG_AFS_FS) := kafs.o
|
obj-$(CONFIG_AFS_FS) := kafs.o
|
||||||
|
@ -61,6 +61,7 @@ const struct inode_operations afs_dir_inode_operations = {
|
|||||||
.permission = afs_permission,
|
.permission = afs_permission,
|
||||||
.getattr = afs_getattr,
|
.getattr = afs_getattr,
|
||||||
.setattr = afs_setattr,
|
.setattr = afs_setattr,
|
||||||
|
.listxattr = afs_listxattr,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct dentry_operations afs_fs_dentry_operations = {
|
const struct dentry_operations afs_fs_dentry_operations = {
|
||||||
|
@ -46,6 +46,7 @@ const struct inode_operations afs_file_inode_operations = {
|
|||||||
.getattr = afs_getattr,
|
.getattr = afs_getattr,
|
||||||
.setattr = afs_setattr,
|
.setattr = afs_setattr,
|
||||||
.permission = afs_permission,
|
.permission = afs_permission,
|
||||||
|
.listxattr = afs_listxattr,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct address_space_operations afs_fs_aops = {
|
const struct address_space_operations afs_fs_aops = {
|
||||||
|
@ -28,6 +28,11 @@ struct afs_iget_data {
|
|||||||
struct afs_volume *volume; /* volume on which resides */
|
struct afs_volume *volume; /* volume on which resides */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct inode_operations afs_symlink_inode_operations = {
|
||||||
|
.get_link = page_get_link,
|
||||||
|
.listxattr = afs_listxattr,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* map the AFS file status to the inode member variables
|
* map the AFS file status to the inode member variables
|
||||||
*/
|
*/
|
||||||
@ -67,7 +72,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
|
|||||||
inode->i_fop = &afs_mntpt_file_operations;
|
inode->i_fop = &afs_mntpt_file_operations;
|
||||||
} else {
|
} else {
|
||||||
inode->i_mode = S_IFLNK | vnode->status.mode;
|
inode->i_mode = S_IFLNK | vnode->status.mode;
|
||||||
inode->i_op = &page_symlink_inode_operations;
|
inode->i_op = &afs_symlink_inode_operations;
|
||||||
}
|
}
|
||||||
inode_nohighmem(inode);
|
inode_nohighmem(inode);
|
||||||
break;
|
break;
|
||||||
|
@ -731,6 +731,11 @@ extern int afs_writeback_all(struct afs_vnode *);
|
|||||||
extern int afs_flush(struct file *, fl_owner_t);
|
extern int afs_flush(struct file *, fl_owner_t);
|
||||||
extern int afs_fsync(struct file *, loff_t, loff_t, int);
|
extern int afs_fsync(struct file *, loff_t, loff_t, int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* xattr.c
|
||||||
|
*/
|
||||||
|
extern const struct xattr_handler *afs_xattr_handlers[];
|
||||||
|
extern ssize_t afs_listxattr(struct dentry *, char *, size_t);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*
|
/*
|
||||||
|
@ -35,6 +35,7 @@ const struct inode_operations afs_mntpt_inode_operations = {
|
|||||||
.lookup = afs_mntpt_lookup,
|
.lookup = afs_mntpt_lookup,
|
||||||
.readlink = page_readlink,
|
.readlink = page_readlink,
|
||||||
.getattr = afs_getattr,
|
.getattr = afs_getattr,
|
||||||
|
.listxattr = afs_listxattr,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct inode_operations afs_autocell_inode_operations = {
|
const struct inode_operations afs_autocell_inode_operations = {
|
||||||
|
@ -319,6 +319,7 @@ static int afs_fill_super(struct super_block *sb,
|
|||||||
sb->s_blocksize_bits = PAGE_SHIFT;
|
sb->s_blocksize_bits = PAGE_SHIFT;
|
||||||
sb->s_magic = AFS_FS_MAGIC;
|
sb->s_magic = AFS_FS_MAGIC;
|
||||||
sb->s_op = &afs_super_ops;
|
sb->s_op = &afs_super_ops;
|
||||||
|
sb->s_xattr = afs_xattr_handlers;
|
||||||
ret = super_setup_bdi(sb);
|
ret = super_setup_bdi(sb);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
121
fs/afs/xattr.c
Normal file
121
fs/afs/xattr.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/* Extended attribute handling for AFS. We use xattrs to get and set metadata
|
||||||
|
* instead of providing pioctl().
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
|
||||||
|
* Written by David Howells (dhowells@redhat.com)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public Licence
|
||||||
|
* as published by the Free Software Foundation; either version
|
||||||
|
* 2 of the Licence, or (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/xattr.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
static const char afs_xattr_list[] =
|
||||||
|
"afs.cell\0"
|
||||||
|
"afs.fid\0"
|
||||||
|
"afs.volume";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve a list of the supported xattrs.
|
||||||
|
*/
|
||||||
|
ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
return sizeof(afs_xattr_list);
|
||||||
|
if (size < sizeof(afs_xattr_list))
|
||||||
|
return -ERANGE;
|
||||||
|
memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
|
||||||
|
return sizeof(afs_xattr_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the name of the cell on which a file resides.
|
||||||
|
*/
|
||||||
|
static int afs_xattr_get_cell(const struct xattr_handler *handler,
|
||||||
|
struct dentry *dentry,
|
||||||
|
struct inode *inode, const char *name,
|
||||||
|
void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||||
|
struct afs_cell *cell = vnode->volume->cell;
|
||||||
|
size_t namelen;
|
||||||
|
|
||||||
|
namelen = strlen(cell->name);
|
||||||
|
if (size == 0)
|
||||||
|
return namelen;
|
||||||
|
if (namelen > size)
|
||||||
|
return -ERANGE;
|
||||||
|
memcpy(buffer, cell->name, size);
|
||||||
|
return namelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xattr_handler afs_xattr_afs_cell_handler = {
|
||||||
|
.name = "afs.cell",
|
||||||
|
.get = afs_xattr_get_cell,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
|
||||||
|
* hex numbers separated by colons.
|
||||||
|
*/
|
||||||
|
static int afs_xattr_get_fid(const struct xattr_handler *handler,
|
||||||
|
struct dentry *dentry,
|
||||||
|
struct inode *inode, const char *name,
|
||||||
|
void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||||
|
char text[8 + 1 + 8 + 1 + 8 + 1];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = sprintf(text, "%x:%x:%x",
|
||||||
|
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
|
||||||
|
if (size == 0)
|
||||||
|
return len;
|
||||||
|
if (len > size)
|
||||||
|
return -ERANGE;
|
||||||
|
memcpy(buffer, text, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xattr_handler afs_xattr_afs_fid_handler = {
|
||||||
|
.name = "afs.fid",
|
||||||
|
.get = afs_xattr_get_fid,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the name of the volume on which a file resides.
|
||||||
|
*/
|
||||||
|
static int afs_xattr_get_volume(const struct xattr_handler *handler,
|
||||||
|
struct dentry *dentry,
|
||||||
|
struct inode *inode, const char *name,
|
||||||
|
void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||||
|
const char *volname = vnode->volume->vlocation->vldb.name;
|
||||||
|
size_t namelen;
|
||||||
|
|
||||||
|
namelen = strlen(volname);
|
||||||
|
if (size == 0)
|
||||||
|
return namelen;
|
||||||
|
if (namelen > size)
|
||||||
|
return -ERANGE;
|
||||||
|
memcpy(buffer, volname, size);
|
||||||
|
return namelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xattr_handler afs_xattr_afs_volume_handler = {
|
||||||
|
.name = "afs.volume",
|
||||||
|
.get = afs_xattr_get_volume,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct xattr_handler *afs_xattr_handlers[] = {
|
||||||
|
&afs_xattr_afs_cell_handler,
|
||||||
|
&afs_xattr_afs_fid_handler,
|
||||||
|
&afs_xattr_afs_volume_handler,
|
||||||
|
NULL
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user