[Acl-Devel] user extended attributes for tmpfs

Jerry Epplin jepplin at globalvelocity.com
Fri Apr 6 21:05:03 CEST 2007


I'd be grateful for your feedback on whether this patch is the right approach
to implementing user xattrs for tmpfs.  Also, if there is a better forum
for this topic, please let me know.

Thanks,
Jerry Epplin

diff -urNp linux-2.6.20.4/fs/Kconfig linux-2.6.20.4-tmpfs-user-xattr/fs/Kconfig
--- linux-2.6.20.4/fs/Kconfig	2007-03-23 19:52:51.000000000 +0000
+++ linux-2.6.20.4-tmpfs-user-xattr/fs/Kconfig	2007-04-06 14:24:47.000000000 +0000
@@ -987,6 +987,16 @@ config TMPFS
 
 	  See <file:Documentation/filesystems/tmpfs.txt> for details.
 
+config TMPFS_USER_XATTR
+	bool "Tmpfs user extended attributes"
+	depends on TMPFS
+	help
+	  Extended attributes are name:value pairs associated with inodes by
+	  the kernel or by users (see the attr(5) manual page, or visit
+	  <http://acl.bestbits.at/> for details).
+
+	  If unsure, say N.
+
 config TMPFS_POSIX_ACL
 	bool "Tmpfs POSIX Access Control Lists"
 	depends on TMPFS
diff -urNp linux-2.6.20.4/mm/shmem.c linux-2.6.20.4-tmpfs-user-xattr/mm/shmem.c
--- linux-2.6.20.4/mm/shmem.c	2007-03-23 19:52:51.000000000 +0000
+++ linux-2.6.20.4-tmpfs-user-xattr/mm/shmem.c	2007-04-06 14:24:47.000000000 +0000
@@ -688,6 +688,15 @@ static int shmem_notify_change(struct de
 	return error;
 }
 
+#ifdef CONFIG_TMPFS_USER_XATTR
+struct shmem_xattr_user_entry {
+	struct shmem_xattr_user_entry *next;
+	char *name;
+	char *val;
+	size_t val_size;
+};
+#endif
+
 static void shmem_delete_inode(struct inode *inode)
 {
 	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
@@ -710,6 +719,18 @@ static void shmem_delete_inode(struct in
 		sbinfo->free_inodes++;
 		spin_unlock(&sbinfo->stat_lock);
 	}
+#ifdef CONFIG_TMPFS_USER_XATTR
+	/* remove any user xattrs */
+	{
+		struct shmem_xattr_user_entry *entry, *next_entry;
+		for (entry = inode->i_private; entry; entry = next_entry) {
+			next_entry = entry->next;
+			kfree(entry->name);
+			kfree(entry->val);
+			kfree(entry);
+		}
+	}
+#endif
 	clear_inode(inode);
 }
 
@@ -1954,11 +1975,105 @@ static struct xattr_handler shmem_xattr_
 	.get    = shmem_xattr_security_get,
 	.set    = shmem_xattr_security_set,
 };
+#endif
+
+#ifdef CONFIG_TMPFS_USER_XATTR
+
+static size_t shmem_xattr_user_list(struct inode *inode, char *list,
+					size_t list_len, const char *name,
+					size_t name_len)
+{
+	size_t retlen = 0, cur_name_len;
+	struct shmem_xattr_user_entry *entry;
+	for (entry = inode->i_private; entry; entry = entry->next) {
+		if (list_len >= XATTR_USER_PREFIX_LEN) {
+			memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
+			list += XATTR_USER_PREFIX_LEN;
+			list_len -= XATTR_USER_PREFIX_LEN;
+		}
+		retlen += XATTR_USER_PREFIX_LEN;
+		cur_name_len = strlen(entry->name);
+		if (list_len >= cur_name_len) {
+			memcpy(list, entry->name, cur_name_len);
+			list += cur_name_len;
+			list_len -= cur_name_len;
+		}
+		retlen += cur_name_len;
+		if (list_len >= 1) {
+			*list++ = '\0';
+			--list_len;
+		}
+		++retlen;
+	}
+	return retlen;
+}
+
+static int shmem_xattr_user_get(struct inode *inode, const char *name,
+				    void *buffer, size_t size)
+{
+	struct shmem_xattr_user_entry *entry;
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	for (entry = inode->i_private; entry; entry = entry->next) {
+		if (!strcmp(entry->name, name)) {
+			if (entry->val_size < size)
+				size = entry->val_size;
+			memcpy(buffer, entry->val, size);
+			return entry->val_size;
+		}
+	}
+	return -ENODATA;
+}
+
+static int shmem_xattr_user_set(struct inode *inode, const char *name,
+				    const void *value, size_t size, int flags)
+{
+	struct shmem_xattr_user_entry *entry;
+	int namelen = strlen(name) + 1;
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	for (entry = inode->i_private; entry; entry = entry->next)
+		if (!strcmp(entry->name, name)) {
+			if (flags & XATTR_CREATE)
+				return -EEXIST;
+			else {
+				kfree(entry->val);
+				break;
+			}
+		}
+	if (!entry) {
+		if (flags & XATTR_REPLACE)
+			return -ENODATA;
+		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+		entry->next = inode->i_private;
+		inode->i_private = entry;
+		entry->name = kmalloc(namelen, GFP_KERNEL);
+		memcpy(entry->name, name, namelen);
+	}
+	entry->val = kmalloc(size, GFP_KERNEL);
+	memcpy(entry->val, value, size);
+	entry->val_size = size;
+	return 0;
+}
+
+static struct xattr_handler shmem_xattr_user_handler = {
+	.prefix = XATTR_USER_PREFIX,
+	.list   = shmem_xattr_user_list,
+	.get    = shmem_xattr_user_get,
+	.set    = shmem_xattr_user_set,
+};
+#endif
 
+#if defined(CONFIG_TMPFS_POSIX_ACL) || defined(CONFIG_TMPFS_USER_XATTR)
 static struct xattr_handler *shmem_xattr_handlers[] = {
+#ifdef CONFIG_TMPFS_POSIX_ACL
 	&shmem_xattr_acl_access_handler,
 	&shmem_xattr_acl_default_handler,
 	&shmem_xattr_security_handler,
+#endif
+#ifdef CONFIG_TMPFS_USER_XATTR
+	&shmem_xattr_user_handler,
+#endif
 	NULL
 };
 #endif
@@ -2240,8 +2355,10 @@ static int shmem_fill_super(struct super
 	sb->s_magic = TMPFS_MAGIC;
 	sb->s_op = &shmem_ops;
 	sb->s_time_gran = 1;
-#ifdef CONFIG_TMPFS_POSIX_ACL
+#if defined(CONFIG_TMPFS_POSIX_ACL) || defined(CONFIG_TMPFS_USER_XATTR)
 	sb->s_xattr = shmem_xattr_handlers;
+#endif
+#ifdef CONFIG_TMPFS_POSIX_ACL
 	sb->s_flags |= MS_POSIXACL;
 #endif
 
@@ -2339,13 +2456,15 @@ static struct inode_operations shmem_ino
 	.truncate	= shmem_truncate,
 	.setattr	= shmem_notify_change,
 	.truncate_range	= shmem_truncate_range,
-#ifdef CONFIG_TMPFS_POSIX_ACL
+#if defined(CONFIG_TMPFS_POSIX_ACL) || defined(CONFIG_TMPFS_USER_XATTR)
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
 	.listxattr	= generic_listxattr,
 	.removexattr	= generic_removexattr,
+#ifdef CONFIG_TMPFS_POSIX_ACL
 	.permission	= shmem_permission,
 #endif
+#endif
 
 };
 
@@ -2361,25 +2480,29 @@ static struct inode_operations shmem_dir
 	.mknod		= shmem_mknod,
 	.rename		= shmem_rename,
 #endif
-#ifdef CONFIG_TMPFS_POSIX_ACL
+#if defined(CONFIG_TMPFS_POSIX_ACL) || defined(CONFIG_TMPFS_USER_XATTR)
 	.setattr	= shmem_notify_change,
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
 	.listxattr	= generic_listxattr,
 	.removexattr	= generic_removexattr,
+#ifdef CONFIG_TMPFS_POSIX_ACL
 	.permission	= shmem_permission,
 #endif
+#endif
 };
 
 static struct inode_operations shmem_special_inode_operations = {
-#ifdef CONFIG_TMPFS_POSIX_ACL
+#if defined(CONFIG_TMPFS_POSIX_ACL) || defined(CONFIG_TMPFS_USER_XATTR)
 	.setattr	= shmem_notify_change,
 	.setxattr	= generic_setxattr,
 	.getxattr	= generic_getxattr,
 	.listxattr	= generic_listxattr,
 	.removexattr	= generic_removexattr,
+#ifdef CONFIG_TMPFS_POSIX_ACL
 	.permission	= shmem_permission,
 #endif
+#endif
 };
 
 static struct super_operations shmem_ops = {
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://acl.bestbits.at/pipermail/acl-devel/attachments/20070406/53c27cbc/attachment.htm 


More information about the acl-devel mailing list