diff options
| author | David Howells <dhowells@redhat.com> | 2017-07-06 10:50:27 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-09 17:40:12 -0400 |
| commit | d3e3b7eac886fb1383db2f22b81550fa6d87f62f (patch) | |
| tree | f3a8e5d9775aeb053290e2157a946425e9803cd2 | |
| parent | fd2498211a551fd42b2d6b9050d649d43536e75c (diff) | |
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>
| -rw-r--r-- | fs/afs/Makefile | 3 | ||||
| -rw-r--r-- | fs/afs/dir.c | 1 | ||||
| -rw-r--r-- | fs/afs/file.c | 1 | ||||
| -rw-r--r-- | fs/afs/inode.c | 7 | ||||
| -rw-r--r-- | fs/afs/internal.h | 5 | ||||
| -rw-r--r-- | fs/afs/mntpt.c | 1 | ||||
| -rw-r--r-- | fs/afs/super.c | 1 | ||||
| -rw-r--r-- | fs/afs/xattr.c | 121 |
8 files changed, 138 insertions, 2 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile index 4f64b95d57bd..095c54165dfd 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile | |||
| @@ -27,6 +27,7 @@ kafs-objs := \ | |||
| 27 | vlocation.o \ | 27 | vlocation.o \ |
| 28 | vnode.o \ | 28 | vnode.o \ |
| 29 | volume.o \ | 29 | volume.o \ |
| 30 | write.o | 30 | write.o \ |
| 31 | xattr.o | ||
| 31 | 32 | ||
| 32 | obj-$(CONFIG_AFS_FS) := kafs.o | 33 | obj-$(CONFIG_AFS_FS) := kafs.o |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 949f960337f5..613a77058263 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
| @@ -61,6 +61,7 @@ const struct inode_operations afs_dir_inode_operations = { | |||
| 61 | .permission = afs_permission, | 61 | .permission = afs_permission, |
| 62 | .getattr = afs_getattr, | 62 | .getattr = afs_getattr, |
| 63 | .setattr = afs_setattr, | 63 | .setattr = afs_setattr, |
| 64 | .listxattr = afs_listxattr, | ||
| 64 | }; | 65 | }; |
| 65 | 66 | ||
| 66 | const struct dentry_operations afs_fs_dentry_operations = { | 67 | const struct dentry_operations afs_fs_dentry_operations = { |
diff --git a/fs/afs/file.c b/fs/afs/file.c index 0d5b8508869b..510cba15fa56 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
| @@ -46,6 +46,7 @@ const struct inode_operations afs_file_inode_operations = { | |||
| 46 | .getattr = afs_getattr, | 46 | .getattr = afs_getattr, |
| 47 | .setattr = afs_setattr, | 47 | .setattr = afs_setattr, |
| 48 | .permission = afs_permission, | 48 | .permission = afs_permission, |
| 49 | .listxattr = afs_listxattr, | ||
| 49 | }; | 50 | }; |
| 50 | 51 | ||
| 51 | const struct address_space_operations afs_fs_aops = { | 52 | const struct address_space_operations afs_fs_aops = { |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index aae55dd15108..342316a9e3e0 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
| @@ -28,6 +28,11 @@ struct afs_iget_data { | |||
| 28 | struct afs_volume *volume; /* volume on which resides */ | 28 | struct afs_volume *volume; /* volume on which resides */ |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | static const struct inode_operations afs_symlink_inode_operations = { | ||
| 32 | .get_link = page_get_link, | ||
| 33 | .listxattr = afs_listxattr, | ||
| 34 | }; | ||
| 35 | |||
| 31 | /* | 36 | /* |
| 32 | * map the AFS file status to the inode member variables | 37 | * map the AFS file status to the inode member variables |
| 33 | */ | 38 | */ |
| @@ -67,7 +72,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) | |||
| 67 | inode->i_fop = &afs_mntpt_file_operations; | 72 | inode->i_fop = &afs_mntpt_file_operations; |
| 68 | } else { | 73 | } else { |
| 69 | inode->i_mode = S_IFLNK | vnode->status.mode; | 74 | inode->i_mode = S_IFLNK | vnode->status.mode; |
| 70 | inode->i_op = &page_symlink_inode_operations; | 75 | inode->i_op = &afs_symlink_inode_operations; |
| 71 | } | 76 | } |
| 72 | inode_nohighmem(inode); | 77 | inode_nohighmem(inode); |
| 73 | break; | 78 | break; |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 4e2556606623..82e16556afea 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
| @@ -731,6 +731,11 @@ extern int afs_writeback_all(struct afs_vnode *); | |||
| 731 | extern int afs_flush(struct file *, fl_owner_t); | 731 | extern int afs_flush(struct file *, fl_owner_t); |
| 732 | extern int afs_fsync(struct file *, loff_t, loff_t, int); | 732 | extern int afs_fsync(struct file *, loff_t, loff_t, int); |
| 733 | 733 | ||
| 734 | /* | ||
| 735 | * xattr.c | ||
| 736 | */ | ||
| 737 | extern const struct xattr_handler *afs_xattr_handlers[]; | ||
| 738 | extern ssize_t afs_listxattr(struct dentry *, char *, size_t); | ||
| 734 | 739 | ||
| 735 | /*****************************************************************************/ | 740 | /*****************************************************************************/ |
| 736 | /* | 741 | /* |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index bd3b65cde282..690fea9d84c3 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -35,6 +35,7 @@ const struct inode_operations afs_mntpt_inode_operations = { | |||
| 35 | .lookup = afs_mntpt_lookup, | 35 | .lookup = afs_mntpt_lookup, |
| 36 | .readlink = page_readlink, | 36 | .readlink = page_readlink, |
| 37 | .getattr = afs_getattr, | 37 | .getattr = afs_getattr, |
| 38 | .listxattr = afs_listxattr, | ||
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | const struct inode_operations afs_autocell_inode_operations = { | 41 | const struct inode_operations afs_autocell_inode_operations = { |
diff --git a/fs/afs/super.c b/fs/afs/super.c index c79633e5cfd8..67680c2d96cf 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
| @@ -319,6 +319,7 @@ static int afs_fill_super(struct super_block *sb, | |||
| 319 | sb->s_blocksize_bits = PAGE_SHIFT; | 319 | sb->s_blocksize_bits = PAGE_SHIFT; |
| 320 | sb->s_magic = AFS_FS_MAGIC; | 320 | sb->s_magic = AFS_FS_MAGIC; |
| 321 | sb->s_op = &afs_super_ops; | 321 | sb->s_op = &afs_super_ops; |
| 322 | sb->s_xattr = afs_xattr_handlers; | ||
| 322 | ret = super_setup_bdi(sb); | 323 | ret = super_setup_bdi(sb); |
| 323 | if (ret) | 324 | if (ret) |
| 324 | return ret; | 325 | return ret; |
diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c new file mode 100644 index 000000000000..2830e4f48d85 --- /dev/null +++ b/fs/afs/xattr.c | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | /* Extended attribute handling for AFS. We use xattrs to get and set metadata | ||
| 2 | * instead of providing pioctl(). | ||
| 3 | * | ||
| 4 | * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. | ||
| 5 | * Written by David Howells (dhowells@redhat.com) | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public Licence | ||
| 9 | * as published by the Free Software Foundation; either version | ||
| 10 | * 2 of the Licence, or (at your option) any later version. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/fs.h> | ||
| 15 | #include <linux/xattr.h> | ||
| 16 | #include "internal.h" | ||
| 17 | |||
| 18 | static const char afs_xattr_list[] = | ||
| 19 | "afs.cell\0" | ||
| 20 | "afs.fid\0" | ||
| 21 | "afs.volume"; | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Retrieve a list of the supported xattrs. | ||
| 25 | */ | ||
| 26 | ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
| 27 | { | ||
| 28 | if (size == 0) | ||
| 29 | return sizeof(afs_xattr_list); | ||
| 30 | if (size < sizeof(afs_xattr_list)) | ||
| 31 | return -ERANGE; | ||
| 32 | memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list)); | ||
| 33 | return sizeof(afs_xattr_list); | ||
| 34 | } | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Get the name of the cell on which a file resides. | ||
| 38 | */ | ||
| 39 | static int afs_xattr_get_cell(const struct xattr_handler *handler, | ||
| 40 | struct dentry *dentry, | ||
| 41 | struct inode *inode, const char *name, | ||
| 42 | void *buffer, size_t size) | ||
| 43 | { | ||
| 44 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
| 45 | struct afs_cell *cell = vnode->volume->cell; | ||
| 46 | size_t namelen; | ||
| 47 | |||
| 48 | namelen = strlen(cell->name); | ||
| 49 | if (size == 0) | ||
| 50 | return namelen; | ||
| 51 | if (namelen > size) | ||
| 52 | return -ERANGE; | ||
| 53 | memcpy(buffer, cell->name, size); | ||
| 54 | return namelen; | ||
| 55 | } | ||
| 56 | |||
| 57 | static const struct xattr_handler afs_xattr_afs_cell_handler = { | ||
| 58 | .name = "afs.cell", | ||
| 59 | .get = afs_xattr_get_cell, | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of | ||
| 64 | * hex numbers separated by colons. | ||
| 65 | */ | ||
| 66 | static int afs_xattr_get_fid(const struct xattr_handler *handler, | ||
| 67 | struct dentry *dentry, | ||
| 68 | struct inode *inode, const char *name, | ||
| 69 | void *buffer, size_t size) | ||
| 70 | { | ||
| 71 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
| 72 | char text[8 + 1 + 8 + 1 + 8 + 1]; | ||
| 73 | size_t len; | ||
| 74 | |||
| 75 | len = sprintf(text, "%x:%x:%x", | ||
| 76 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | ||
| 77 | if (size == 0) | ||
| 78 | return len; | ||
| 79 | if (len > size) | ||
| 80 | return -ERANGE; | ||
| 81 | memcpy(buffer, text, len); | ||
| 82 | return len; | ||
| 83 | } | ||
| 84 | |||
| 85 | static const struct xattr_handler afs_xattr_afs_fid_handler = { | ||
| 86 | .name = "afs.fid", | ||
| 87 | .get = afs_xattr_get_fid, | ||
| 88 | }; | ||
| 89 | |||
| 90 | /* | ||
| 91 | * Get the name of the volume on which a file resides. | ||
| 92 | */ | ||
| 93 | static int afs_xattr_get_volume(const struct xattr_handler *handler, | ||
| 94 | struct dentry *dentry, | ||
| 95 | struct inode *inode, const char *name, | ||
| 96 | void *buffer, size_t size) | ||
| 97 | { | ||
| 98 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
| 99 | const char *volname = vnode->volume->vlocation->vldb.name; | ||
| 100 | size_t namelen; | ||
| 101 | |||
