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, +}; _______________________________________________ Bug-hurd mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/bug-hurd