bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux 2.6 patch] ext2 support for hurd extensions via xattr interface


From: Roland McGrath
Subject: [linux 2.6 patch] ext2 support for hurd extensions via xattr interface
Date: Thu, 12 Feb 2004 23:19:42 -0800

Hi folks.  I've just whipped up the following patch, which is against the
current Linux 2.6 source tree.  This provides a means to fetch and store
the extra data stored in nodes on ext2 filesystems with "creator_os" set to
EXT2_OS_HURD, i.e. from `mke2fs -o hurd' or filesystems created natively on
the Hurd.  The interface for this is via the "extended attributes" feature,
which has user functions getxattr, setxattr, listxattr, etc. in libc (or
libattr, whatever works for you on your particular GNU/Linux setup).  (The
`attr' package for GNU/Linux has the tools attr, getfattr, and setfattr, to
access these.)  Your .config file must set CONFIG_EXT2_FS_XATTR=y.

Please realize this doesn't have anything to do with the Hurd's ext2fs
supporting the ext2 extended attributes disk format.  That is something
that I would like to consider later on.  But to be clear, right now I am
only talking about the existing Hurdish ext2 disk format.  

This makes it possible to use a GNU/Linux system to not only create but
also populate a Hurdish ext2 filesystem complete with passive translator
settings so that it can boot the Hurd normally.  It also makes it possible
to back up and restore a Hurdish ext2 filesystem from a GNU/Linux system,
using any tools that understand the extended attributes.  (Off hand the
only such thing I'm aware of is `star', which I have not tried using
myself.)  Basically, the ./native-install bootstrapping is right goofy and
one shouldn't have to do things that way.  I would much prefer to have a
bootstrap gnu.star in the extended format so it unpacks from GNU/Linux
directly into a complete GNU/Hurd filesystem with /servers and /dev intact.

There are two "extra" pieces of information in Hurd ext2 nodes.  

The author UID, seen in st_author from the Hurd, is represented by the
"gnu.author" attribute.  The value presented to getxattr/setxattr is either
empty (zero bytes), which indicates that st_author == st_uid, or is four
bytes, giving the author UID in host byte order.  Using setfattr/getfattr
you can specify the literal value in exactly four bytes worth of hex:

        setfattr -n gnu.author -v 0x12345678

Unfortunately you have to know the native byte order to formulate your hex
string right, but doubtful anyone cares about setting this anyway (and
save/restore for archiving does the right thing).

The passive translator setting is represented by the "gnu.translator"
attribute.  The value is exactly the value as seen in the Hurd via
file_get_translator et al, including the null bytes.  With [gs]etfattr, you
can use the format "strings\0with\0nulls\0".  For example, with a patched
Linux kernel I've mounted my Hurd partition on /gnu and then:

        bash$ getfattr -Rh -d -m '.*' /gnu/servers
        getfattr: Removing leading '/' from absolute path names
        # file: gnu/servers/socket/1
        gnu.translator="/hurd/pflocal\000"

        # file: gnu/servers/exec
        gnu.translator="/hurd/exec\000"

        # file: gnu/servers/crash-suspend
        gnu.translator="/hurd/crash\000--suspend\000"

        # file: gnu/servers/crash-kill
        gnu.translator="/hurd/crash\000--kill\000"

        # file: gnu/servers/password
        gnu.translator="/hurd/password\000"

        # file: gnu/servers/default-pager
        gnu.translator="/hurd/proxy-defpager\000"

        # file: gnu/servers/crash-dump-core
        gnu.translator="/hurd/crash\000--dump-core\000"

(Note btw that getfattr -d by default matches regexp 'user.*',
so you need a -m switch to make sure you see the gnu.* attributes.)

If people find this useful, then I can try my luck at getting this
incorporated into Linux.  Unfortunately, the code in question does not lend
itself to making an isolated module instead of modifying the kernel directly.

If we settle on this allocation of gnu.* xattr names, then another thing I
can do is make the *xattr functions in libc on the Hurd present synthetic
gnu.author and gnu.translator attributes.  The benefit of this is that
archivers like star will just work out of the box to save and restore the
author field natively on Hurd filesystems the same way they work on Linux
writing Hurd filesystems.  This is probably not so useful for
gnu.translator, since the *xattr libc interfaces don't have the semantics
of O_NOTRANS lookups.  However, if e.g. a "notrans" translator were used
for making backups or other archives, then star running on that would
automagically save and restore passive translator settings as you'd want.


Enjoy,
Roland


Index: fs/ext2/Makefile
===================================================================
RCS file: /home/roland/redhat/bkcvs/linux-2.5/fs/ext2/Makefile,v
retrieving revision 1.10
diff -b -p -u -r1.10 Makefile
--- fs/ext2/Makefile    25 Jul 2003 23:00:05 -0000      1.10
+++ fs/ext2/Makefile    13 Feb 2004 02:06:18 -0000
@@ -10,3 +10,4 @@ ext2-y := balloc.o bitmap.o dir.o file.o
 ext2-$(CONFIG_EXT2_FS_XATTR)    += xattr.o xattr_user.o xattr_trusted.o
 ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
 ext2-$(CONFIG_EXT2_FS_SECURITY)         += xattr_security.o
+ext2-$(CONFIG_EXT2_FS_XATTR)    += xattr_hurd.o
Index: fs/ext2/ext2.h
===================================================================
RCS file: /home/roland/redhat/bkcvs/linux-2.5/fs/ext2/ext2.h,v
retrieving revision 1.13
diff -b -p -u -r1.13 ext2.h
--- fs/ext2/ext2.h      7 Jul 2003 02:41:12 -0000       1.13
+++ fs/ext2/ext2.h      13 Feb 2004 02:11:07 -0000
@@ -55,6 +55,10 @@ struct ext2_inode_info {
        struct posix_acl        *i_acl;
        struct posix_acl        *i_default_acl;
 #endif
+#ifdef CONFIG_EXT2_FS_XATTR
+       __u32   i_hurd_translator;
+       __u32   i_hurd_author;
+#endif
        rwlock_t i_meta_lock;
        struct inode    vfs_inode;
 };
Index: fs/ext2/inode.c
===================================================================
RCS file: /home/roland/redhat/bkcvs/linux-2.5/fs/ext2/inode.c,v
retrieving revision 1.71
diff -b -p -u -r1.71 inode.c
--- fs/ext2/inode.c     19 Jan 2004 18:06:27 -0000      1.71
+++ fs/ext2/inode.c     13 Feb 2004 02:47:03 -0000
@@ -1085,6 +1085,15 @@ void ext2_read_inode (struct inode * ino
        else
                ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
        ei->i_dtime = 0;
+       if (EXT2_SB(inode->i_sb)->s_es->s_creator_os == EXT2_OS_HURD) {
+               ei->i_hurd_translator = 
le32_to_cpu(raw_inode->osd1.hurd1.h_i_translator);
+               ei->i_hurd_author = 
le32_to_cpu(raw_inode->osd2.hurd2.h_i_author);
+
+       }
+       else {
+               ei->i_hurd_translator = 0;
+               ei->i_hurd_author = inode->i_uid;
+       }
        inode->i_generation = le32_to_cpu(raw_inode->i_generation);
        ei->i_state = 0;
        ei->i_next_alloc_block = 0;
@@ -1218,6 +1227,11 @@ static int ext2_update_inode(struct inod
                }
        }
        
+       if (EXT2_SB(inode->i_sb)->s_es->s_creator_os == EXT2_OS_HURD) {
+               raw_inode->osd1.hurd1.h_i_translator = 
cpu_to_le32(ei->i_hurd_translator);
+               raw_inode->osd2.hurd2.h_i_author = 
cpu_to_le32(ei->i_hurd_author);
+       }
+
        raw_inode->i_generation = cpu_to_le32(inode->i_generation);
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
                if (old_valid_dev(inode->i_rdev)) {
@@ -1275,4 +1289,3 @@ int ext2_setattr(struct dentry *dentry, 
                error = ext2_acl_chmod(inode);
        return error;
 }
-
Index: fs/ext2/xattr.c
===================================================================
RCS file: /home/roland/redhat/bkcvs/linux-2.5/fs/ext2/xattr.c,v
retrieving revision 1.20
diff -b -p -u -r1.20 xattr.c
--- fs/ext2/xattr.c     6 Feb 2004 16:50:15 -0000       1.20
+++ fs/ext2/xattr.c     13 Feb 2004 04:36:54 -0000
@@ -434,6 +434,37 @@ bad_block: ext2_error(inode->i_sb, "ext2
        error = size;
 
 cleanup:
+       if (error >= 0 && (EXT2_SB(inode->i_sb)->s_es->s_creator_os
+                          == cpu_to_le32(EXT2_OS_HURD))) {
+               struct ext2_inode_info *ei = EXT2_I(inode);
+               buf = buffer + size;
+               if (ei->i_hurd_author != inode->i_uid) {
+                       size += sizeof "gnu.author";
+                       if (buffer) {
+                               if (size > buffer_size)
+                                       error = -ERANGE;
+                               else {
+                                       memcpy(buf, "gnu.author",
+                                              sizeof "gnu.author");
+                                       buf += sizeof "gnu.author";
+                               }
+                       }
+               }
+               if (ei->i_hurd_translator != 0) {
+                       size += sizeof "gnu.translator";
+                       if (buffer) {
+                               if (size > buffer_size)
+                                       error = -ERANGE;
+                               else {
+                                       memcpy(buf, "gnu.translator",
+                                              sizeof "gnu.translator");
+                                       buf += sizeof "gnu.translator";
+                               }
+                       }
+               }
+               if (error >= 0)
+                       error = size;
+       }
        brelse(bh);
        up_read(&EXT2_I(inode)->xattr_sem);
 
@@ -893,6 +924,13 @@ ext2_xattr_delete_inode(struct inode *in
 cleanup:
        brelse(bh);
        up_write(&EXT2_I(inode)->xattr_sem);
+
+       if (EXT2_SB(inode->i_sb)->s_es->s_creator_os
+           == cpu_to_le32(EXT2_OS_HURD) &&
+           EXT2_I(inode)->i_hurd_translator != 0) {
+               ext2_free_blocks(inode, EXT2_I(inode)->i_hurd_translator, 1);
+               EXT2_I(inode)->i_hurd_translator = 0;
+       }
 }
 
 /*
@@ -1125,10 +1163,14 @@ init_ext2_xattr(void)
                                  &ext2_xattr_user_handler);
        if (err)
                return err;
+       err = ext2_xattr_register(EXT2_XATTR_INDEX_HURD,
+                                 &ext2_xattr_hurd_handler);
+       if (err)
+               goto out;
        err = ext2_xattr_register(EXT2_XATTR_INDEX_TRUSTED,
                                  &ext2_xattr_trusted_handler);
        if (err)
-               goto out;
+               goto out0;
 #ifdef CONFIG_EXT2_FS_SECURITY
        err = ext2_xattr_register(EXT2_XATTR_INDEX_SECURITY,
                                  &ext2_xattr_security_handler);
@@ -1160,6 +1202,9 @@ out1:
 #endif
        ext2_xattr_unregister(EXT2_XATTR_INDEX_TRUSTED,
                              &ext2_xattr_trusted_handler);
+out0:
+       ext2_xattr_unregister(EXT2_XATTR_INDEX_HURD,
+                             &ext2_xattr_hurd_handler);
 out:
        ext2_xattr_unregister(EXT2_XATTR_INDEX_USER,
                              &ext2_xattr_user_handler);
Index: fs/ext2/xattr.h
===================================================================
RCS file: /home/roland/redhat/bkcvs/linux-2.5/fs/ext2/xattr.h,v
retrieving revision 1.8
diff -b -p -u -r1.8 xattr.h
--- fs/ext2/xattr.h     13 May 2003 06:12:52 -0000      1.8
+++ fs/ext2/xattr.h     13 Feb 2004 03:22:36 -0000
@@ -24,6 +24,7 @@
 #define EXT2_XATTR_INDEX_TRUSTED               4
 #define        EXT2_XATTR_INDEX_LUSTRE                 5
 #define EXT2_XATTR_INDEX_SECURITY              6
+#define EXT2_XATTR_INDEX_HURD                  7
 
 struct ext2_xattr_header {
        __u32   h_magic;        /* magic number for identification */
@@ -135,6 +136,6 @@ exit_ext2_xattr(void)
 # endif  /* CONFIG_EXT2_FS_XATTR */
 
 extern struct ext2_xattr_handler ext2_xattr_user_handler;
+extern struct ext2_xattr_handler ext2_xattr_hurd_handler;
 extern struct ext2_xattr_handler ext2_xattr_trusted_handler;
 extern struct ext2_xattr_handler ext2_xattr_security_handler;

--- /dev/null   2003-06-05 09:19:08.000000000 -0700
+++ fs/ext2/xattr_hurd.c        2004-02-12 20:48:46.000000000 -0800
@@ -0,0 +1,204 @@
+/*
+ * linux/fs/ext2/xattr_hurd.c
+ * Handler for Hurd-specific attributes.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/buffer_head.h>
+#include "ext2.h"
+#include "xattr.h"
+
+#define XATTR_HURD_PREFIX "gnu."
+
+static size_t
+ext2_xattr_hurd_list(char *list, struct inode *inode,
+                    const char *name, int name_len)
+{
+       const int prefix_len = sizeof(XATTR_HURD_PREFIX)-1;
+
+       if (!test_opt(inode->i_sb, XATTR_USER))
+               return 0;
+
+       if (list) {
+               memcpy(list, XATTR_HURD_PREFIX, prefix_len);
+               memcpy(list+prefix_len, name, name_len);
+               list[prefix_len + name_len] = '\0';
+       }
+       return prefix_len + name_len + 1;
+}
+
+static inline int
+IS_HURD_COMPAT(struct super_block *sb)
+{
+       return (EXT2_SB(sb)->s_es->s_creator_os == cpu_to_le32(EXT2_OS_HURD));
+}
+
+
+static int
+ext2_xattr_hurd_get(struct inode *inode, const char *name,
+                   void *buffer, size_t size)
+{
+       int error;
+
+       if (IS_HURD_COMPAT(inode->i_sb)) {
+               struct ext2_inode_info *ei = EXT2_I(inode);
+               /*
+                * Compatibility mode.
+                */
+               if (!strcmp(name, "translator")) {
+                       struct buffer_head *bh;
+                       u16 len;
+                       if (ei->i_hurd_translator == 0)
+                               /* No translator set, empty.  */
+                               return 0;
+                       error = -EIO;
+                       bh = sb_bread(inode->i_sb, ei->i_hurd_translator);
+                       if (!bh)
+                               return error;
+                       len = le16_to_cpup(bh->b_data);
+                       if (len > bh->b_size - 2)
+                               error = -EFBIG; /* ? */
+                       else if (buffer == NULL) /* Just return the total.  */
+                               error = len;
+                       else if (len > size)
+                               error = -ERANGE;
+                       else {
+                               memcpy(buffer, bh->b_data + 2, len);
+                               error = len;
+                       }
+                       brelse(bh);
+                       return error;
+               }
+               if (!strcmp(name, "author")) {
+                       if (ei->i_hurd_author == inode->i_uid)
+                               return 0;
+                       if (buffer) {
+                               if (size < sizeof ei->i_hurd_author)
+                                       return -ERANGE;
+                               memcpy(buffer, &ei->i_hurd_author,
+                                      sizeof ei->i_hurd_author);
+                       }
+                       return sizeof ei->i_hurd_author;
+               }
+       }
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       return -EOPNOTSUPP;
+}
+
+static int
+ext2_xattr_hurd_set(struct inode *inode, const char *name,
+                   const void *value, size_t size, int flags)
+{
+       int error;
+
+       if (value == NULL)
+               size = 0;
+
+       if (IS_HURD_COMPAT(inode->i_sb)) {
+               struct ext2_inode_info *ei = EXT2_I(inode);
+               /*
+                * Compatibility mode.  We actually have to re-read the
+                * raw inode because ext2_read_inode does not cache this field.
+                */
+               if (!strcmp(name, "translator")) {
+                       u32 bno;
+                       u16 len;
+                       struct buffer_head *bh;
+
+                       error = permission(inode, MAY_WRITE, NULL);
+                       if (error)
+                               return error;
+                       if (ei->i_hurd_translator == 0) {
+                               /* No existing translator.  */
+                               if (flags & XATTR_REPLACE)
+                                       return -ENODATA;
+                               if (size == 0) { /* Nothing really to do.  */
+                                       inode->i_ctime = CURRENT_TIME;
+                                       mark_inode_dirty(inode);
+                                       return 0;
+                               }
+                       }
+                       else if (flags & XATTR_CREATE)
+                               return -EEXIST;
+
+                       if (size == 0) { /* Removing translator.  */
+                               bno = ei->i_hurd_translator;
+                               ei->i_hurd_translator = 0;
+                               ext2_free_blocks(inode, bno, 1);
+                               unmap_underlying_metadata(inode->i_sb->s_bdev,
+                                                         bno);
+                               inode->i_ctime = CURRENT_TIME;
+                               mark_inode_dirty(inode);
+                               return 0;
+                       }
+
+                       if (size > inode->i_sb->s_blocksize - 2)
+                               return -ERANGE;
+
+                       bno = ei->i_hurd_translator;
+                       if (bno == 0) {
+                               /*
+                                * Need to allocate a new block.
+                                */
+                               struct super_block *sb = inode->i_sb;
+                               u32 goal = le32_to_cpu(EXT2_SB(sb)->s_es->
+                                                      s_first_data_block) +
+                                       EXT2_I(inode)->i_block_group *
+                                       EXT2_BLOCKS_PER_GROUP(sb);
+                               bno = ext2_new_block(inode, goal, 0, 0,
+                                                    &error);
+                               if (error)
+                                       return error;
+                       }
+
+                       bh = sb_getblk(inode->i_sb, bno);
+                       lock_buffer(bh);
+                       len = cpu_to_le16(size);
+                       memcpy(bh->b_data, &len, sizeof len);
+                       memcpy(bh->b_data + 2, value, size);
+                       set_buffer_uptodate(bh);
+                       unlock_buffer(bh);
+                       mark_buffer_dirty(bh);
+                       brelse(bh);
+
+                       ei->i_hurd_translator = bno;
+                       inode->i_ctime = CURRENT_TIME;
+                       mark_inode_dirty(inode);
+                       return 0;
+               }
+               if (!strcmp(name, "author")) {
+                       error = permission(inode, MAY_WRITE, NULL);
+                       if (error)
+                               return error;
+                       switch (size) {
+                       default:
+                               return -EINVAL;
+                       case 0:
+                               ei->i_hurd_author = inode->i_uid;
+                               break;
+                       case sizeof ei->i_hurd_author:
+                               memcpy(&ei->i_hurd_author,
+                                      value, sizeof ei->i_hurd_author);
+                               break;
+                       }
+                       inode->i_ctime = CURRENT_TIME;
+                       mark_inode_dirty(inode);
+                       return 0;
+               }
+       }
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       return -EOPNOTSUPP;
+}
+
+struct ext2_xattr_handler ext2_xattr_hurd_handler = {
+       .prefix = XATTR_HURD_PREFIX,
+       .list   = ext2_xattr_hurd_list,
+       .get    = ext2_xattr_hurd_get,
+       .set    = ext2_xattr_hurd_set,
+};




reply via email to

[Prev in Thread] Current Thread [Next in Thread]