[prev in list] [next in list] [prev in thread] [next in thread] 

List:       intermezzo-discuss
Subject:    extended attribute and acl replication patches
From:       Shirish Hemant Phatak <shirish () nustorage ! com>
Date:       2001-07-07 0:09:56
[Download RAW message or body]

Hi,

    I have been playing with replicating ACLs and Extended
Attributes in Intermezzo. I am attaching a patch. The patch
passes regression and also passes the appropriate ACL tests. ACLs
are not yet being journalled natively, rather I use the
underlying extended attribute structure.

    So far the patch appears fairly stable. It includes the
EA/ACL code only if the appropriate defines are in config.h. make
config has been extended appropriately.

     As always bug reports are welcome. These patches also work
with my rsync patches, which I am migrating (slowly!) to the
branch.

     EA/ACL patches for linux 2.2.19 are available from
http://moldybread.net.

-Shirish

["presto+lento+ea.diff" (text/plain)]

? presto/tests/loop_discard
Index: presto/Configure
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/Configure,v
retrieving revision 1.26
diff -u -r1.26 Configure
--- presto/Configure	2001/02/02 03:10:46	1.26
+++ presto/Configure	2001/07/07 00:56:43
@@ -372,6 +372,8 @@
     fi
     printflag "/proc filesystem support" CONFIG_PROC_FS
     printflag "sysctl support" CONFIG_SYSCTL
+    printflag "extended attribute support" CONFIG_FS_EXT_ATTR
+    printflag "POSIX acl support" CONFIG_FS_POSIX_ACL
     if [ "$BIGMEM" ] ; then
 	if [ "$CONFIG_3GB" = "y" ] ; then MEMMAX=3GB
 	elif [ "$CONFIG_2GB" = "y" ] ; then MEMMAX=2GB
@@ -428,6 +430,8 @@
 	fi
 	symcheck proc_root CONFIG_PROC_FS
 	symcheck proc_sys_root CONFIG_SYSCTL
+	symcheck ext_attr CONFIG_FS_EXT_ATTR
+	symcheck posix_acl CONFIG_FS_POSIX_ACL
 	echo "Extracting kernel symbol versions..."
 	echo "#ifndef __LINUX_MODVERSIONS_H" > $MODVER
 	echo "#define __LINUX_MODVERSIONS_H" >> $MODVER
@@ -457,7 +461,8 @@
 	    configcheck CONFIG_SMP
 	fi
 	for C in CONFIG_PCI CONFIG_INET CONFIG_MODVERSIONS CONFIG_PROC_FS \
-	    CONFIG_EXT3_FS CONFIG_EXT2_FS CONFIG_SYSCTL CONFIG_LOOP_DISCARD; do
+	    CONFIG_EXT3_FS CONFIG_EXT2_FS CONFIG_SYSCTL CONFIG_LOOP_DISCARD\
+        CONFIG_FS_EXT_ATTR CONFIG_FS_POSIX_ACL; do
 	    configcheck $C
 	done
 	if [ $ARCH = "alpha" ] ; then
@@ -503,6 +508,8 @@
 	    write_bool CONFIG_3GB
 	fi
 	ask_bool "/proc filesystem support" CONFIG_PROC_FS
+	ask_bool "extended attribute support" CONFIG_FS_EXT_ATTR
+	ask_bool "posix acl support" CONFIG_FS_POSIX_ACL
 	;;
 esac
 
Index: presto/Makefile
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/Makefile,v
retrieving revision 1.35
diff -u -r1.35 Makefile
--- presto/Makefile	2001/01/28 16:48:05	1.35
+++ presto/Makefile	2001/07/07 00:56:43
@@ -54,7 +54,7 @@
 CC :=$(shell if which $(CROSS_COMPILE)kgcc > /dev/null 2>&1; then echo \
$(CROSS_COMPILE)kgcc; else echo $(CROSS_COMPILE)gcc; fi)   
 
-SRCS= journal.c intermezzo.c vfs.c file.c dir.c methods.c cache.c  super.c \
journal_ext2.c journal_ext3.c psdev.c upcall.c sysctl.c  inode.c dcache.c +SRCS= \
journal.c intermezzo.c vfs.c file.c dir.c methods.c cache.c  super.c journal_ext2.c \
journal_ext3.c psdev.c upcall.c sysctl.c  inode.c dcache.c ext_attr.c  
 ifdef CONFIG_KREINT
 SRCS += kmlrec.c kmlreint.c
Index: presto/dir.c
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/dir.c,v
retrieving revision 1.57.2.5
diff -u -r1.57.2.5 dir.c
--- presto/dir.c	2001/04/11 19:37:11	1.57.2.5
+++ presto/dir.c	2001/07/07 00:56:43
@@ -614,6 +614,10 @@
  * reading, while not making ilookup totally insecure.  This could all
  * go away if we could set the CAP_DAC_READ_SEARCH capability for the client.
  */
+/* If posix acls are available, the underlying cache fs will export the
+ * appropriate permission function. Thus we do not worry here about ACLs
+ * or EAs. -SHP
+ */
 int presto_permission(struct inode *inode, int mask)
 {
         unsigned short mode = inode->i_mode;
@@ -762,5 +766,13 @@
         NULL,                   /* bmap */
         NULL,                   /* truncate */
         presto_permission,      /* permission */
-        NULL                    /* smap */
+        NULL,                   /* smap */
+        NULL,                   /* updatepage */
+        NULL,                   /* revalidate */
+        NULL,                   /* prepare_write */
+        NULL,                   /* sync_page */
+#ifdef CONFIG_FS_EXT_ATTR
+        NULL,                   /* get_ext_attr */
+        presto_set_ext_attr,    /* set_ext_attr */
+#endif
 };
Index: presto/ext_attr.c
===================================================================
RCS file: ext_attr.c
diff -N ext_attr.c
--- /dev/null	Thu May 24 22:33:05 2001
+++ ext_attr.c	Fri Jul  6 17:56:43 2001
@@ -0,0 +1,199 @@
+/* 
+ * Extended attribute handling for presto.
+ *
+ * Copyright (C) 2001. All rights reserved.
+ * Shirish H. Phatak
+ * Tacitus Systems, Inc.
+ *
+ */
+
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <asm/segment.h>
+#include <linux/smp_lock.h>
+
+#include <linux/intermezzo_fs.h>
+#include <linux/intermezzo_upcall.h>
+#include <linux/intermezzo_psdev.h>
+#include <linux/intermezzo_kml.h>
+
+
+#ifdef CONFIG_FS_EXT_ATTR
+#include <linux/ext_attr.h>
+
+extern inline void presto_debug_fail_blkdev(struct presto_file_set *fset,
+                                            unsigned long value);
+
+extern int presto_prep(struct dentry *, struct presto_cache **,
+                       struct presto_file_set **);
+
+
+/* VFS interface */
+/* XXX! Fixme test for user defined attributes */
+int presto_set_ext_attr(struct inode *inode, 
+                        const char *name, void *buffer,
+                        size_t buffer_len, int flags) 
+{
+        int error;
+        struct presto_cache *cache;
+        struct presto_file_set *fset;
+        struct lento_vfs_context info;
+        struct dentry *dentry;
+        int minor = presto_i2m(inode);
+        char *buf = NULL;
+
+        ENTRY;
+        if (minor < 0) {
+                EXIT;
+                return -1;
+        }
+
+        if ( ISLENTO(minor) ) {
+                EXIT;
+                return -EINVAL;
+        }
+
+        /* BAD...vfs should really pass down the dentry to use, especially
+         * since every other operation in iops does. But for now
+         * we do a reverse mapping from inode to the first dentry 
+         */
+        if (list_empty(&inode->i_dentry)) {
+                printk("No alias for inode %d\n", (int) inode->i_ino);
+                EXIT;
+                return -EINVAL;
+        }
+
+        dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
+
+        error = presto_prep(dentry, &cache, &fset);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
+        if ((buffer != NULL) && (buffer_len != 0)) {
+            /* If buffer is a user space pointer copy it to kernel space
+            * and reset the flag. We do this since the journal functions need
+            * access to the contents of the buffer, and the file system
+            * does not care. When we actually invoke the function, we remove
+            * the EXT_ATTR_FLAG_USER flag.
+            *
+            * XXX:Check if the "fs does not care" assertion is always true -SHP
+            * (works for ext3)
+            */
+            if (flags & EXT_ATTR_FLAG_USER) {
+                PRESTO_ALLOC(buf, char *, buffer_len);
+                if (!buf) {
+                        printk("InterMezzo: out of memory!!!\n");
+                        return -ENOMEM;
+                }
+                error = copy_from_user(buf, buffer, buffer_len);
+                if (error) 
+                        return error;
+            } else 
+                buf = buffer;
+        } else
+                buf = buffer;
+
+        if ( presto_get_permit(inode) < 0 ) {
+                EXIT;
+                if (buffer_len && (flags & EXT_ATTR_FLAG_USER))
+                        PRESTO_FREE(buf, buffer_len);
+                return -EROFS;
+        }
+
+        /* Simulate presto_setup_info */
+        memset(&info, 0, sizeof(info));
+        /* For now redundant..but we keep it around just in case */
+        info.flags = LENTO_FL_IGNORE_TIME;
+        if (!ISLENTO(cache->cache_psdev->uc_minor))
+            info.flags |= LENTO_FL_KML;
+
+        /* We pass in the kernel space pointer and reset the 
+         * EXT_ATTR_FLAG_USER flag.
+         * See comments above. 
+         */ 
+        /* Note that mode is already set by VFS so we send in a NULL */
+        error = presto_do_set_ext_attr(fset, dentry, name, buf,
+                                       buffer_len, flags & ~EXT_ATTR_FLAG_USER,
+                                       NULL, &info);
+        presto_put_permit(inode);
+
+        if (buffer_len && (flags & EXT_ATTR_FLAG_USER))
+                PRESTO_FREE(buf, buffer_len);
+        EXIT;
+        return error;
+}
+
+/* Lento Interface */
+/* XXX: ignore flags? We should be forcing these operations through? -SHP*/
+int lento_set_ext_attr(const char *path, const char *name, 
+                       void *buffer, size_t buffer_len, int flags, mode_t mode, 
+                       struct lento_vfs_context *info) 
+{
+        int error;
+        char * pathname;
+        struct dentry *dentry;
+        struct presto_file_set *fset;
+
+        ENTRY;
+        lock_kernel();
+
+        pathname=getname(path);
+        error = PTR_ERR(pathname);
+        if (IS_ERR(pathname)) {
+                EXIT;
+                goto exit;
+        }
+
+        /* XXX: Check the flags from lookup_dentry -SHP */
+        /* Note that ext_attrs apply to files and directories..*/
+        dentry = lookup_dentry(pathname, NULL, LOOKUP_SLASHOK);
+        error = PTR_ERR(dentry);
+        if (IS_ERR(dentry)) {
+                EXIT;
+                goto exit_path;
+        }
+
+        fset = presto_fset(dentry);
+        error = -EINVAL;
+        if ( !fset ) {
+                printk("No fileset!\n");
+                EXIT;
+                goto exit_dentry;
+        }
+
+        if (buffer==NULL) buffer_len=0;
+
+        error = presto_do_set_ext_attr(fset, dentry, name, buffer,
+                                       buffer_len, flags, &mode, info);
+exit_dentry:
+        dput(dentry);
+exit_path:
+        putname(pathname);
+exit:
+        unlock_kernel();
+        return error; 
+}
+
+#endif /*CONFIG_FS_EXT_ATTR*/
Index: presto/file.c
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/file.c,v
retrieving revision 1.17.2.15
diff -u -r1.17.2.15 file.c
--- presto/file.c	2001/06/28 23:11:19	1.17.2.15
+++ presto/file.c	2001/07/07 00:56:43
@@ -359,6 +359,9 @@
 struct inode_operations presto_file_iops = {
         default_file_ops: &presto_file_fops,
         permission: presto_permission,
+#ifdef CONFIG_FS_EXT_ATTR
+        set_ext_attr: presto_set_ext_attr
+#endif
 };
 
 
Index: presto/journal.c
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/journal.c,v
retrieving revision 1.74.2.31
diff -u -r1.74.2.31 journal.c
--- presto/journal.c	2001/06/30 20:07:36	1.74.2.31
+++ presto/journal.c	2001/07/07 00:56:44
@@ -1,5 +1,8 @@
 /*
  * Intermezzo. (C) 1998 Peter J. Braam
+ *
+ * Support for journalling extended attributes
+ * (C) 2001 Shirish H. Phatak, Tacitus Systems, Inc.
  */
 
 #include <linux/types.h>
@@ -21,8 +24,9 @@
 
 static int presto_log(struct presto_file_set *fset, struct rec_info *rec,
                       const char *buf, size_t size,
-                      const char *path1, int len1, 
-                      const char *path2, int len2);
+                      const char *string1, int len1, 
+                      const char *string2, int len2,
+                      const char *string3, int len3);
 
 /*
  *  reserve record space and/or atomically request state of the log
@@ -492,16 +496,17 @@
 }
 
 
-/* structure of the log record:
+/* structure of an extended log record:
 
-   buf-prefix  buf-body [path1 [path2]] buf-suffix
+   buf-prefix  buf-body [string1 [string2 [string3]]] buf-suffix
 
    note: moves offset forward
 */
-int presto_write_record(struct file *f, loff_t *off,
+static inline int presto_write_record(struct file *f, loff_t *off,
                         const char *buf, size_t size,
-                        const char *path1, int len1, 
-                        const char *path2, int len2)
+                        const char *string1, int len1, 
+                        const char *string2, int len2,
+                        const char *string3, int len3)
 {
         size_t prefix_size; 
         int rc;
@@ -514,8 +519,8 @@
                 return -EIO;
         }
 
-        if  ( path1 ) {
-                rc = presto_fwrite(f, path1, len1, off);
+        if  ( string1  && len1 ) {
+                rc = presto_fwrite(f, string1, len1, off);
                 if ( rc != len1 ) {
                         printk("Write error!\n");
                         EXIT;
@@ -523,8 +528,8 @@
                 }
         }
 
-        if  ( path2 ) {
-                rc = presto_fwrite(f, path2, len2, off);
+        if  ( string2 && len2 ) {
+                rc = presto_fwrite(f, string2, len2, off);
                 if ( rc != len2 ) {
                         printk("Write error!\n");
                         EXIT;
@@ -532,6 +537,15 @@
                 }
         }
 
+        if  ( string3 && len3 ) {
+                rc = presto_fwrite(f, string3, len3, off);
+                if ( rc != len3 ) {
+                        printk("Write error!\n");
+                        EXIT;
+                        return -EIO;
+                }
+        }
+
         rc = presto_fwrite(f, buf + prefix_size,
                            sizeof(struct journal_suffix), off);
         if ( rc != sizeof(struct journal_suffix) ) {
@@ -548,8 +562,9 @@
  */
 static int presto_log(struct presto_file_set *fset, struct rec_info *rec,
                       const char *buf, size_t size,
-                      const char *path1, int len1, 
-                      const char *path2, int len2)
+                      const char *string1, int len1, 
+                      const char *string2, int len2,
+                      const char *string3, int len3)
 {
         int rc;
         struct presto_reservation_data rd;
@@ -581,7 +596,7 @@
         s->recno =  cpu_to_le32(rec->recno); 
 
         rc = presto_write_record(fd->fd_file, &offset, buf, size, 
-                                 path1, len1, path2, len2); 
+                                 string1, len1, string2, len2, string3, len3); 
         if (rc) {
                 printk("presto: error writing record to %s\n",
                         rec->is_kml ? "KML" : "LML"); 
@@ -910,7 +925,7 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           NULL, 0);
+                           NULL, 0, NULL, 0);
 
         BUFF_FREE(buffer);
 
@@ -1159,7 +1174,7 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           NULL, 0);
+                           NULL, 0, NULL, 0);
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1221,7 +1236,7 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           NULL, 0);
+                           NULL, 0, NULL, 0);
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1284,7 +1299,8 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           target, size_round(le32_to_cpu(targetlen)));
+                           target, size_round(le32_to_cpu(targetlen)),
+                           NULL, 0);
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1345,7 +1361,7 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           NULL, 0);
+                           NULL, 0, NULL, 0);
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1405,7 +1421,8 @@
         logrecord = journal_log_suffix(logrecord, record, fset, dir, rec);
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           name, size_round(len));
+                           name, size_round(len),
+                           NULL, 0);
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1474,7 +1491,7 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           NULL, 0);
+                           NULL, 0, NULL, 0);
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1535,7 +1552,8 @@
 
         error = presto_log(fset, rec, record, size,
                            srcpath, size_round(le32_to_cpu(srcpathlen)),
-                           path, size_round(le32_to_cpu(pathlen)));
+                           path, size_round(le32_to_cpu(pathlen)),
+                           NULL, 0);
 
         BUFF_FREE(srcbuffer);
         BUFF_FREE(buffer);
@@ -1598,7 +1616,8 @@
 
         error = presto_log(fset, rec, record, size,
                            srcpath, size_round(le32_to_cpu(srcpathlen)),
-                           path, size_round(le32_to_cpu(pathlen)));
+                           path, size_round(le32_to_cpu(pathlen)),
+                           NULL, 0);
 
         BUFF_FREE(buffer);
         BUFF_FREE(srcbuffer);
@@ -1655,7 +1674,8 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           name, size_round(len));
+                           name, size_round(len), 
+                           NULL, 0);
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1752,7 +1772,7 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           NULL, 0);
+                           NULL, 0, NULL, 0);
         BUFF_FREE(buffer);
 
         EXIT;
@@ -1804,7 +1824,7 @@
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           NULL, 0);
+                           NULL, 0, NULL, 0);
 
         EXIT;
         return error;
@@ -1927,3 +1947,101 @@
         EXIT;
         return -EINVAL;
 }
+
+
+#ifdef CONFIG_FS_EXT_ATTR
+/* Journal an ea operation. A NULL buffer implies the attribute is 
+ * getting deleted. In this case we simply change the opcode, but nothing
+ * else is affected.
+ */
+int presto_journal_set_ext_attr (struct rec_info *rec, 
+                                 struct presto_file_set *fset, 
+                                 struct dentry *dentry, 
+                                 struct presto_version *ver, const char *name, 
+                                 const char *buffer, int buffer_len, 
+                                 int flags) 
+{ 
+        int opcode = (buffer == NULL) ? 
+                     PRESTO_OP_DELEXTATTR : 
+                     PRESTO_OP_SETEXTATTR ;
+        char *temp;
+        char *path;
+        __u32 pathlen;
+        int size;
+        char *logrecord;
+        char record[292];
+        struct dentry *root;
+        int error;
+        __u32 namelen=cpu_to_le32(strnlen(name,PRESTO_EXT_ATTR_NAME_MAX));
+        __u32 buflen=(buffer != NULL)? cpu_to_le32(buffer_len): cpu_to_le32(0);
+        __u32 mode;
+
+
+        ENTRY;
+        if ( presto_no_journal(fset) ) {
+                EXIT;
+                return 0;
+        }
+
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+                EXIT;
+                return 0;
+        }
+
+        root = fset->fset_mtpt;
+
+        BUFF_ALLOC(temp, NULL);
+        path = presto_path(dentry, root, temp, PAGE_SIZE);
+        pathlen = cpu_to_le32(MYPATHLEN(temp, path));
+
+        flags=cpu_to_le32(flags);
+        /* Ugly, but needed. posix ACLs change the mode without using
+         * setattr, we need to record these changes. The EA code per se
+         * is not really affected.
+         */
+        mode=cpu_to_le32(dentry->d_inode->i_mode);
+
+        size =  sizeof(__u32) * current->ngroups + 
+                sizeof(struct journal_prefix) + 
+                2 * sizeof(struct presto_version) +
+                sizeof(flags) + sizeof(mode) + sizeof(namelen) + 
+                sizeof(buflen) + sizeof(pathlen) + 
+                sizeof(struct journal_suffix);
+
+        if ( size > sizeof(record) ) {
+                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
+        }
+
+        rec->is_kml = 1;
+        /* Make space for a path, a attr name and value*/
+        /* We use the buflen instead of buffer_len to make sure that we 
+         * journal the right length. This may be a little paranoid, but
+         * with 64 bits round the corner, I would rather be safe than sorry!
+         * Also this handles deletes with non-zero buffer_lengths correctly.
+         * SHP
+         */
+        rec->size = size + size_round(le32_to_cpu(pathlen)) +
+                    size_round(le32_to_cpu(namelen)) + 
+                    size_round(le32_to_cpu(buflen));
+
+        logrecord = journal_log_prefix(record, opcode, rec);
+        logrecord = logit(logrecord, ver, sizeof(*ver));
+        logrecord = log_version(logrecord, dentry);
+        logrecord = logit(logrecord, &flags, sizeof(flags));
+        logrecord = logit(logrecord, &mode, sizeof(flags));
+        logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
+        logrecord = logit(logrecord, &namelen, sizeof(namelen));
+        logrecord = logit(logrecord, &buflen, sizeof(buflen));
+        logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
+
+        error = presto_log(fset, rec, record, size,
+                           path, size_round(le32_to_cpu(pathlen)),
+                           name, size_round(le32_to_cpu(namelen)),
+                           buffer, size_round(le32_to_cpu(buflen)));
+
+        BUFF_FREE(temp);
+        EXIT;
+        return error;
+}
+#endif
+
Index: presto/journal_ext3.c
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/journal_ext3.c,v
retrieving revision 1.29.2.6
diff -u -r1.29.2.6 journal_ext3.c
--- presto/journal_ext3.c	2001/04/30 22:28:06	1.29.2.6
+++ presto/journal_ext3.c	2001/07/07 00:56:44
@@ -5,6 +5,9 @@
  * Intermezzo. (C) 2000 Los Alamos National Laboratory
  * Intermezzo. (C) 2000 TurboLinux, Inc.
  * Intermezzo. (C) 2001 Mountain View Data, Inc.
+ *
+ * Support for extended attributes
+ * Copyright (C) 2001, Shirish Phatak, Tacitus Systems, Inc.
  */
 
 #include <linux/types.h>
@@ -35,6 +38,19 @@
 #define MAX_PATH_BLOCKS(inode) (PATH_MAX >> EXT3_BLOCK_SIZE_BITS((inode)->i_sb))
 #define MAX_NAME_BLOCKS(inode) (NAME_MAX >> EXT3_BLOCK_SIZE_BITS((inode)->i_sb))
 
+#ifdef CONFIG_FS_EXT_ATTR
+#define MAX_ATTR_NAME_BLOCKS(inode) (PRESTO_EXT_ATTR_NAME_MAX >> \
EXT3_BLOCK_SIZE_BITS((inode)->i_sb)) +#define MAX_ATTR_VALUE_BLOCKS(inode) \
(PRESTO_EXT_ATTR_VALUE_MAX >> EXT3_BLOCK_SIZE_BITS((inode)->i_sb)) +#endif
+
+/* Extended attributes. It is possible that the EXT3 itself is configured
+ * without extended attribute support even though support is enabled in VFS. 
+ * However, in such a situation, the fs will not define the appropriate 
+ * set_ext_attr inode_operation and we should never invoke EA code for 
+ * such a cache. Hence we do not explicitly test for CONFIG_EXT3_FS_EXT_ATTR
+ * -SHP
+ */
+
 /* space requirements: 
    presto_do_truncate: 
         used to truncate the KML forward to next fset->chunksize boundary
@@ -104,6 +120,16 @@
            and operations involving the LML records 
         */
         switch (op) {
+#ifdef CONFIG_FS_EXT_ATTR
+        case PRESTO_OP_SETEXTATTR:
+                /* Space for a pathname, an attribute name, a value 
+                 * and flags and a potential setattr
+                 */
+                jblocks = one_path_blks + MAX_ATTR_NAME_BLOCKS(inode)
+                          + MAX_ATTR_VALUE_BLOCKS(inode)
+                          + 3 * EXT3_DATA_TRANS_BLOCKS + 6 ; 
+                break;
+#endif
         case PRESTO_OP_TRUNC:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS; 
Index: presto/methods.c
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/methods.c,v
retrieving revision 1.6
diff -u -r1.6 methods.c
--- presto/methods.c	2001/01/22 00:06:17	1.6
+++ presto/methods.c	2001/07/07 00:56:44
@@ -5,7 +5,10 @@
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 Mountain View Data, Inc.
  *
- *
+ *  Modified to support extended attributes
+ *  Copyright (C) 2001
+ *  Shirish Hemant Phatak
+ *  Tacitus Systems, Inc.
  */
 
 #include <stdarg.h>
@@ -282,6 +285,14 @@
 		pr_iops->mknod = filter_iops->mknod;
 	if (cache_iops->permission && filter_iops->permission)
 		pr_iops->permission = filter_iops->permission;
+#ifdef CONFIG_FS_EXT_ATTR
+    /* For now we assume that posix acls are handled through extended
+     * attributes. If this is not the case, we must explicitly trap 
+     * posix_set_acl
+     */
+	if (cache_iops->set_ext_attr && filter_iops->set_ext_attr)
+		pr_iops->set_ext_attr = filter_iops->set_ext_attr;
+#endif
 
 
 	/* copy dir fops */
@@ -324,6 +335,14 @@
 	       sizeof(*cache_iops->default_file_ops));
 	/* assign */
 	filter_c2ufiops(cache)->default_file_ops = filter_c2uffops(cache);
+#ifdef CONFIG_FS_EXT_ATTR
+    /* For now we assume that posix acls are handled through extended
+     * attributes. If this is not the case, we must explicitly trap and 
+     * posix_set_acl
+     */
+	if (cache_iops->set_ext_attr && filter_iops->set_ext_attr)
+		filter_c2ufiops(cache)->set_ext_attr = filter_iops->set_ext_attr;
+#endif
 
 	/* unconditional filtering operations */
 	filter_c2uffops(cache)->open = filter_iops->default_file_ops->open;
@@ -356,6 +375,14 @@
 
 	/* setup our dir iops: copy and modify */
 	memcpy(pr_iops, cache_iops, sizeof(*cache_iops));
+#ifdef CONFIG_FS_EXT_ATTR
+    /* For now we assume that posix acls are handled through extended
+     * attributes. If this is not the case, we must explicitly trap and 
+     * posix_set_acl
+     */
+	if (cache_iops->set_ext_attr && filter_iops->set_ext_attr)
+		pr_iops->set_ext_attr = filter_iops->set_ext_attr;
+#endif
 
 	/* copy fops - careful for symlinks they might be NULL */
 	if ( cache_iops->default_file_ops ) { 
Index: presto/psdev.c
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/psdev.c,v
retrieving revision 1.77.2.3
diff -u -r1.77.2.3 psdev.c
--- presto/psdev.c	2001/04/05 01:09:19	1.77.2.3
+++ presto/psdev.c	2001/07/07 00:56:45
@@ -805,6 +805,100 @@
                 return error;
         }
 
+#ifdef CONFIG_FS_EXT_ATTR
+        /* IOCTL to create/modify an extended attribute */
+        case PRESTO_VFS_SETEXTATTR: {
+                int error;
+                struct lento_input_ext_attr input;
+                char *name;
+                char *buffer;
+
+                error = copy_from_user(&input, (char *)arg, sizeof(input));
+                if ( error ) { 
+                    EXIT;
+                    return error;
+                }
+
+                /* Now setup the input parameters */
+                PRESTO_ALLOC(name, char *, input.name_len+1);
+                /* We need null terminated strings for attr names */
+                name[input.name_len] = '\0';
+                error=copy_from_user(name, input.name, input.name_len);
+                if ( error ) { 
+                    EXIT;
+                    PRESTO_FREE(name,input.name_len+1);
+                    return error;
+                }
+
+                PRESTO_ALLOC(buffer, char *, input.buffer_len+1);
+                error=copy_from_user(buffer, input.buffer, input.buffer_len);
+                if ( error ) { 
+                    EXIT;
+                    PRESTO_FREE(name,input.name_len+1);
+                    PRESTO_FREE(buffer,input.buffer_len+1);
+                    return error;
+                }
+                /* Make null terminated for easy printing */
+                buffer[input.buffer_len]='\0';
+ 
+                CDEBUG(D_PSDEV," setextattr params: name %s, valuelen %d,"
+                       " value %s, attr flags %x, mode %o, slot offset %d,"
+                       " recno %d, kml offset %lu, flags %x, time %d\n", 
+                       name, input.buffer_len, buffer, input.flags, input.mode,
+                       input.info.slot_offset, input.info.recno,
+                       (unsigned long) input.info.kml_offset, input.info.flags,
+                       input.info.updated_time);
+
+                error=lento_set_ext_attr
+                      (input.path,name,buffer,input.buffer_len,
+                       input.flags, input.mode, &input.info);
+
+                PRESTO_FREE(name,input.name_len+1);
+                PRESTO_FREE(buffer,input.buffer_len+1);
+                EXIT;
+                return error;
+        }
+
+        /* IOCTL to delete an extended attribute */
+        case PRESTO_VFS_DELEXTATTR: {
+                int error;
+                struct lento_input_ext_attr input;
+                char *name;
+
+                error = copy_from_user(&input, (char *)arg, sizeof(input));
+                if ( error ) { 
+                    EXIT;
+                    return error;
+                }
+
+                /* Now setup the input parameters */
+                PRESTO_ALLOC(name, char *, input.name_len+1);
+                /* We need null terminated strings for attr names */
+                name[input.name_len] = '\0';
+                error=copy_from_user(name, input.name, input.name_len);
+                if ( error ) { 
+                    EXIT;
+                    PRESTO_FREE(name,input.name_len+1);
+                    return error;
+                }
+
+                CDEBUG(D_PSDEV," delextattr params: name %s,"
+                       " attr flags %x, mode %o, slot offset %d, recno %d,"
+                       " kml offset %lu, flags %x, time %d\n", 
+                       name, input.flags, input.mode,
+                       input.info.slot_offset, input.info.recno,
+                       (unsigned long) input.info.kml_offset, input.info.flags,
+                       input.info.updated_time);
+
+                error=lento_set_ext_attr
+                      (input.path,name,NULL,0,input.flags,
+                       input.mode,&input.info);
+                PRESTO_FREE(name,input.name_len+1);
+                EXIT;
+                return error;
+        }
+#endif
+
         case PRESTO_VFS_IOPEN: {
                 struct lento_input_iopen input;
                 int error;
Index: presto/vfs.c
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/vfs.c,v
retrieving revision 1.59.2.17
diff -u -r1.59.2.17 vfs.c
--- presto/vfs.c	2001/06/29 16:46:37	1.59.2.17
+++ presto/vfs.c	2001/07/07 00:56:46
@@ -10,8 +10,13 @@
  *
  * This code is based on code from namei.c in the linux file system;
  * see copyright notice below.
+ *
+ * Extended Attribute Support 
+ * Copyright (C) 2001, Tacitus Systems, Inc.
+ * Shirish H. Phatak
  */
 
+
 /** namei.c copyright **/
 
 /*
@@ -51,7 +56,15 @@
 #include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
+#ifdef CONFIG_FS_EXT_ATTR
+#include <linux/ext_attr.h>
 
+#ifdef CONFIG_FS_POSIX_ACL
+#include <linux/posix_acl.h>
+#endif
+#endif
+
+
 extern struct inode_operations presto_sym_iops;
 
 /*
@@ -378,6 +391,9 @@
         struct dentry *dentry;
         struct presto_file_set *fset;
         int error;
+#ifdef  CONFIG_FS_POSIX_ACL
+        struct inode_operations *iops_save=NULL;
+#endif
 
         ENTRY;
         CDEBUG(D_PIOCTL,"name %s, valid %#x, mode %#o, uid %d, gid %d, size %ld\n",
@@ -415,8 +431,29 @@
                                  (dentry->d_inode->i_mode & ~S_IALLUGO);
                 CDEBUG(D_PIOCTL, "chmod: orig %#o, set %#o, result %#o\n",
                        dentry->d_inode->i_mode, set_mode, iattr->ia_mode);
+#ifdef CONFIG_FS_POSIX_ACL
+                /* ACl code interacts badly with setattr 
+                 * since it tries to modify the ACL using 
+                 * set_ext_attr which recurses back into presto.  
+                 * This only happens if ATTR_MODE is set.
+                 * Here we are doing a forced mode set 
+                 * (initiated by lento), so we * reset the 
+                 * set_posix_acl operation which 
+                 * prevents such recursion.  -SHP
+                 *
+                 * This will probably still be required when native
+                 * acl journalling is in place.
+                 */
+                iops_save=dentry->d_inode->i_op;
+                dentry->d_inode->i_op->set_posix_acl=NULL;
+#endif
         }
         error = presto_do_setattr(fset, dentry, iattr, info);
+#ifdef CONFIG_FS_POSIX_ACL
+        /* reset the inode_operations if we reset them*/
+        if (iattr->ia_valid & ATTR_MODE) 
+                dentry->d_inode->i_op=iops_save;
+#endif
 
         EXIT;
 exit_lock:
@@ -604,8 +641,13 @@
 
         presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x10);
         presto_getversion(&new_file_ver, dentry->d_inode);
+        /* if acl support is enabled, i_mode gets modified by 
+         * posix_acl_init_cred. We need to journal this change. So instead
+         * of passing mode to presto_journal_create, we pass i_mode. -SHP
+         */
         if ( presto_do_kml(info, dentry->d_inode) )
-                error = presto_journal_create(&rec, fset, dentry, &tgt_dir_ver,      \
&new_file_ver, mode); +                error = presto_journal_create(&rec, fset, \
dentry, &tgt_dir_ver,                                              &new_file_ver,  +  \
dentry->d_inode->i_mode);  
         presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x20);
         if ( presto_do_expect(info, dentry->d_inode) )
@@ -1236,9 +1278,14 @@
 
         presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x10);
         presto_getversion(&new_dir_ver, dentry->d_inode);
+        /* POSIX ACL code modifies mode. Hence we need to pull the actual
+         * mode from the inode rather than the mode passed to us.
+         * Also see comments in presto_do_create. -SHP
+         */
         if ( presto_do_kml(info, dentry->d_inode) ) {
                 error = presto_journal_mkdir(&rec, fset, dentry, &tgt_dir_ver,
-                                             &new_dir_ver, mode);
+                                             &new_dir_ver, 
+                                             dentry->d_inode->i_mode);
         }
 
         presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x20);
@@ -1560,9 +1607,13 @@
 
         presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x10);
         presto_getversion(&new_node_ver, dentry->d_inode);
+        /* journal real mode rather than mode passed to us, since posix acls
+         * can modify the actual mode. -SHP
+         */
         if ( presto_do_kml(info, dentry->d_inode) )
                 error = presto_journal_mknod(&rec, fset, dentry, &tgt_dir_ver,
-                                             &new_node_ver, mode,
+                                             &new_node_ver, 
+                                             dentry->d_inode->i_mode,
                                              MAJOR(dev), MINOR(dev) );
 
         presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x20);
@@ -2239,3 +2290,198 @@
         return error;
 }
 
+
+#ifdef CONFIG_FS_EXT_ATTR
+
+#ifdef CONFIG_FS_POSIX_ACL
+/* Posix ACL code changes i_mode without using a notify_change (or
+ * a mark_inode_dirty!). We need to duplicate this at the reintegrator
+ * which is done by this function. This function also takes care of 
+ * resetting the cached posix acls in this inode. If we don't reset these
+ * VFS continues using the old acl information, which by now may be out of
+ * date.
+ */
+int presto_setmode(struct presto_file_set *fset, struct dentry *dentry,
+                   mode_t mode)
+{
+        struct inode *inode = dentry->d_inode;
+
+        ENTRY;
+        /* The extended attributes for this inode were modified. 
+         * At this point we can not be sure if any of the ACL 
+         * information * for this inode was updated. So we will 
+         * force VFS to reread the acls. Note that we do this 
+         * only when called from the ioctl, which is why we
+         * do this while setting the mode of the file. Also note
+         * that mark_inode_dirty is not be needed for i_*acl only
+         * to force i_mode info to disk, and should be removed once
+         * we use notify_change to update the mode.
+         * XXX: is mode setting really needed? Just setting acl's should
+         * be enough! VFS should change the i_mode as needed? SHP
+         */
+        if (inode->i_acl && 
+            inode->i_acl != POSIX_ACL_NOT_CACHED) 
+            posix_acl_release(inode->i_acl);
+        if (inode->i_default_acl && 
+            inode->i_default_acl != POSIX_ACL_NOT_CACHED) 
+            posix_acl_release(inode->i_default_acl);
+        inode->i_acl = POSIX_ACL_NOT_CACHED;
+        inode->i_default_acl = POSIX_ACL_NOT_CACHED;
+        inode->i_mode = mode;
+        /* inode should already be dirty...but just in case */
+        mark_inode_dirty(inode);
+        return 0;
+
+#if 0
+        /* XXX: The following code is the preferred way to set mode, 
+         * however, I need to carefully go through possible recursion
+         * paths back into presto. See comments in presto_do_setattr.
+         */
+        {    
+        int error=0; 
+        struct super_operations *sops;
+        struct iattr iattr;
+
+        iattr.ia_mode = mode;
+        iattr.ia_valid = ATTR_MODE|ATTR_FORCE;
+
+        error = -EPERM;
+        sops = filter_c2csops(fset->fset_cache->cache_filter); 
+        if (!sops &&
+            !sops->notify_change) {
+                EXIT;
+                return error;
+        }
+
+        error = sops->notify_change(dentry, &iattr);
+
+        EXIT;
+        return error;
+        }
+#endif
+}
+#endif
+
+/* setextattr Interface to cache filesystem */
+int presto_do_set_ext_attr(struct presto_file_set *fset, 
+                           struct dentry *dentry, 
+                           const char *name, void *buffer,
+                           size_t buffer_len, int flags, mode_t *mode,
+                           struct lento_vfs_context *info) 
+{
+        struct rec_info rec;
+        struct inode *inode = dentry->d_inode;
+        struct inode_operations *iops;
+        int error;
+        struct presto_version ver;
+        void *handle;
+        char temp[PRESTO_EXT_ATTR_NAME_MAX+1];
+
+        ENTRY;
+        error = -EROFS;
+        if (IS_RDONLY(inode)) {
+                EXIT;
+                return -EROFS;
+        }
+
+        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+                EXIT;
+                return -EPERM;
+        }
+
+        presto_getversion(&ver, inode);
+        error = -EPERM;
+        /* We need to invoke different filters based on whether
+         * this dentry is a regular file, directory or symlink.
+         */
+        switch (inode->i_mode & S_IFMT) {
+                case S_IFLNK: /* symlink */
+                    iops = filter_c2csiops(fset->fset_cache->cache_filter); 
+                    break;
+                case S_IFDIR: /* directory */
+                    iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
+                    break;
+                case S_IFREG:
+                default: /* everything else including regular files */
+                    iops = filter_c2cfiops(fset->fset_cache->cache_filter); 
+        }
+
+        if (!iops && !iops->set_ext_attr) {
+                EXIT;
+                return error;
+        }
+
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                return error;
+        }
+
+        
+        handle = presto_trans_start(fset,dentry->d_inode,PRESTO_OP_SETEXTATTR);
+        if ( IS_ERR(handle) ) {
+                printk("presto_do_set_ext_attr: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                return -ENOSPC;
+        }
+
+        /* We first "truncate" name to the maximum allowable in presto */
+        /* This simulates the strncpy_from_use code in fs/ext_attr.c */
+        strncpy(temp,name,sizeof(temp));
+
+        /* Pass down to cache*/
+        error = iops->set_ext_attr(inode,temp,buffer,buffer_len,flags);
+        if (error) {
+                EXIT;
+                goto exit;
+        }
+
+#ifdef CONFIG_FS_POSIX_ACL
+        /* Reset mode if specified*/
+        /* XXX: when we do native acl support, move this code out! */
+        if (mode != NULL) {
+                error = presto_setmode(fset, dentry, *mode);
+                if (error) { 
+                    EXIT;
+                    goto exit;
+                }
+        }
+#endif
+
+        /* Reset ctime. Only inode change time (ctime) is affected */
+        error = presto_settime(fset, dentry, info, ATTR_CTIME);
+        if (error) { 
+                EXIT;
+                goto exit;
+        }
+
+        if (flags & EXT_ATTR_FLAG_USER) {
+                printk(" USER flag passed to presto_do_set_ext_attr!\n");
+                *(int *)0 = 1;
+        }
+
+        /* We are here, so set_ext_attr succeeded. We no longer need to keep
+         * track of EXT_ATTR_FLAG_{EXISTS,CREATE}, instead, we will force
+         * the attribute value during log replay. -SHP
+         */
+        flags &= ~(EXT_ATTR_FLAG_EXISTS | EXT_ATTR_FLAG_CREATE);
+
+        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x10);
+        if ( presto_do_kml(info, dentry->d_inode) )
+                error = presto_journal_set_ext_attr
+                        (&rec, fset, dentry, &ver, name, buffer, 
+                         buffer_len, flags);
+
+        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x20);
+        if ( presto_do_expect(info, dentry->d_inode) )
+                error = presto_write_last_rcvd(&rec, fset, info);
+
+        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x30);
+        EXIT;
+exit:
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_trans_commit(fset, handle);
+
+        return error;
+}
+#endif
Index: presto/linux/intermezzo_fs.h
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/linux/intermezzo_fs.h,v
retrieving revision 1.74.2.10
diff -u -r1.74.2.10 intermezzo_fs.h
--- presto/linux/intermezzo_fs.h	2001/06/11 21:13:54	1.74.2.10
+++ presto/linux/intermezzo_fs.h	2001/07/07 00:56:46
@@ -4,7 +4,16 @@
 #ifdef __KERNEL__
 #include <linux/smp.h>
 #include <linux/filter.h>
+#include <linux/version.h>
 
+/* We will be more tolerant than the default ea patch with attr name sizes and
+ * the size of value. If these come via VFS from the default ea patches, the
+ * corresponding character strings will be truncated anyway. During journalling
+ * we journal length for both name and value. See journal_set_ext_attr.
+ */
+#define PRESTO_EXT_ATTR_NAME_MAX 128
+#define PRESTO_EXT_ATTR_VALUE_MAX 8192
+
 /* fixups for fs.h */
 #ifndef fs_down
 #define fs_down(sem) down(sem)
@@ -291,7 +300,6 @@
                      struct dentry *new_dentry, struct lento_vfs_context *info);
 int presto_do_statfs (struct presto_file_set *fset, 
                       struct statfs * buf, int bufsiz);
-
 int lento_setattr(const char *name, struct iattr *iattr,
                   struct lento_vfs_context *info);
 int lento_create(const char *name, int mode, struct lento_vfs_context *info);
@@ -380,6 +388,33 @@
 int init_intermezzo_sysctl(void);
 void cleanup_intermezzo_sysctl(void);
 
+/* ext_attr.c */
+#ifdef CONFIG_FS_EXT_ATTR
+/* XXX: Borrowed from vfs.c. Once the ea patch is into CVS 
+ * move this prototype -SHP
+ */
+int presto_do_set_ext_attr(struct presto_file_set *fset,
+                           struct dentry *dentry,
+                           const char *name, void *buffer,
+                           size_t buffer_len, int flags, mode_t *mode,
+                           struct lento_vfs_context *info);
+int presto_set_ext_attr(struct inode *inode,
+                        const char *name, void *buffer,
+                        size_t buffer_len, int flags);
+int lento_set_ext_attr(const char *path, const char *name,
+                       void *buffer, size_t buffer_len, int flags,
+                       mode_t mode, struct lento_vfs_context *info);
+/* XXX: Borrowed from journal.c. Once the ea patch is into CVS 
+ * move this prototype -SHP
+ */
+int presto_journal_set_ext_attr (struct rec_info *rec,
+                                 struct presto_file_set *fset,
+                                 struct dentry *dentry,
+                                 struct presto_version *ver, const char *name,
+                                 const char *buffer, int buffer_len,
+                                 int flags);
+#endif
+
 
 /* global variables */
 extern int presto_debug;
@@ -550,6 +585,18 @@
         struct lento_vfs_context info;
 };
 
+/* XXX: check for alignment */
+struct lento_input_ext_attr {
+        char  *path;
+        char  *name;
+        __u32 name_len;
+        char  *buffer;
+        __u32 buffer_len;
+        __u32 flags;
+        __u32 mode;
+        struct lento_vfs_context info;
+};
+
 /* XXX should PRESTO_GET_* actually be of type _IOR, since we are reading? */
 #define PRESTO_GETMOUNT         _IOW ('p',0x03, struct readmount *)
 #define PRESTO_SETPID           _IOW ('p',0x04, struct readmount *)
@@ -571,6 +618,8 @@
 #define PRESTO_VFS_RENAME       _IOW ('p',0x18, struct lento_input_old_new *)
 #define PRESTO_VFS_CLOSE        _IOW ('p',0x1a, struct lento_input_close *)
 #define PRESTO_VFS_IOPEN        _IOW ('p',0x1b, struct lento_input_iopen *)
+#define PRESTO_VFS_SETEXTATTR   _IOW ('p',0x1c, struct lento_input_ext_attr *)
+#define PRESTO_VFS_DELEXTATTR   _IOW ('p',0x1d, struct lento_input_ext_attr *)
 
 #define PRESTO_MARK             _IOW ('p',0x20, struct lento_input_open *)
 #define PRESTO_RELEASE_PERMIT   _IOW ('p',0x21, struct lento_input_open *)
Index: presto/linux/intermezzo_kml.h
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/presto/linux/intermezzo_kml.h,v
retrieving revision 1.8.2.2
diff -u -r1.8.2.2 intermezzo_kml.h
--- presto/linux/intermezzo_kml.h	2001/03/09 03:09:23	1.8.2.2
+++ presto/linux/intermezzo_kml.h	2001/07/07 00:56:46
@@ -22,6 +22,8 @@
 #define PRESTO_OP_WRITE         12
 #define PRESTO_OP_RELEASE       13
 #define PRESTO_OP_TRUNC         14
+#define PRESTO_OP_SETEXTATTR    15
+#define PRESTO_OP_DELEXTATTR    16
 
 #define PRESTO_LML_DONE     1 /* flag to get first write to do LML */
 
Index: lento/Lento/Psdev.pm
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/lento/Lento/Psdev.pm,v
retrieving revision 1.77.2.8
diff -u -r1.77.2.8 Psdev.pm
--- lento/Lento/Psdev.pm	2001/04/19 22:04:01	1.77.2.8
+++ lento/Lento/Psdev.pm	2001/07/07 00:56:47
@@ -437,6 +437,107 @@
     }
 }
 
+eval 'sub PRESTO_VFS_SETEXTATTR () { &_IOC(1, ord(\'p\'),0x1c, 4);}';
+eval 'sub PRESTO_VFS_DELEXTATTR () { &_IOC(1, ord(\'p\'),0x1d, 4);}';
+
+sub lento_setextattr {
+    my $psdev = shift;
+    my $path = shift;
+    my $name = shift;
+    my $value = shift;
+    my $attrflags = shift;
+    my $mode = shift;
+    my $slot_offset  = shift;
+    my $recno = shift;
+    my $kml_offset  = shift;
+    my $flags = shift;
+    my $updated_time = shift;
+
+    # pack data for ioctl into buffer.  Format:
+    #   - path (pointer, p)
+    #   - name (pointer, p)
+    #   - namelen (number, i)
+    #   - value (pointer, p)
+    #   - valuelen (number, i)
+    #   - attr flags (number, i)
+    #   - mode (number, i)
+    #   - slot_offset (number, i)
+    #   - recno (number, i)
+    #   - kml offset (number, i)
+    #   - (dummy for 64 bit padding)
+    #   - flags (number, i)
+    #   - new ctime (number, i)
+
+
+    DEBUG(" ** path $path, name $name, value $value length ".length($value).
+          " ,attrflags $attrflags, mode $mode, slotoffset: $slot_offset,".
+          " kml_offset $kml_offset, recno $recno, flags $flags,".
+          " time $updated_time\n");     
+
+    my $buf = pack("ppipiiiiiiiii", $path, $name, length($name), 
+                   $value, length($value), $attrflags, $mode, $slot_offset, 
+                   $recno, $kml_offset, 0, $flags, $updated_time);
+    
+    my $rc = ioctl($psdev->{handle}, &PRESTO_VFS_SETEXTATTR(), $buf);
+
+    if (!defined $rc) { 
+        confess "PRESTO_VFS_SETEXTATTR ioctl failed (os error = $!)\n";
+    } elsif ($rc eq "0 but true") {
+        DEBUG "PRESTO_VFS_SETEXTATTR finished (success)\n";
+    } else {
+        confess "PRESTO_VFS_SETEXTATTR: non-zero return $rc\n";
+    }
+}
+
+sub lento_delextattr {
+    my $psdev = shift;
+    my $path = shift;
+    my $name = shift;
+    my $dummy;
+    my $attrflags = shift;
+    my $mode = shift;
+    my $slot_offset  = shift;
+    my $recno = shift;
+    my $kml_offset  = shift;
+    my $flags = shift;
+    my $updated_time = shift;
+
+    # pack data for ioctl into buffer.  Format:
+    #   - path (pointer, p)
+    #   - name (pointer, p)
+    #   - namelen (number, i)
+    #   - dummy value (pointer, p)
+    #   - 0 valuelen (number, i)
+    #   - attr flags (number, i)
+    #   - mode (number, i)
+    #   - slot_offset (number, i)
+    #   - recno (number, i)
+    #   - kml offset (number, i)
+    #   - (dummy for 64 bit padding)
+    #   - flags (number, i)
+    #   - new ctime (number, i)
+
+
+    DEBUG(" ** path $path, name $name, ".
+          " attrflags $attrflags, mode $mode, slotoffset: $slot_offset,".
+          " kml_offset $kml_offset, recno $recno, flags $flags,".
+          " time $updated_time\n");     
+
+    my $buf = pack("ppipiiiiiiiii", $path, $name, length($name), $dummy, 
+                   0, $attrflags, $mode, $slot_offset, $recno, $kml_offset, 
+                   0, $flags, $updated_time);
+    
+    my $rc = ioctl($psdev->{handle}, &PRESTO_VFS_DELEXTATTR(), $buf);
+
+    if (!defined $rc) { 
+        confess "PRESTO_VFS_DELEXTATTR ioctl failed (os error = $!)\n";
+    } elsif ($rc eq "0 but true") {
+        DEBUG "PRESTO_VFS_DELEXTATTR finished (success)\n";
+    } else {
+        confess "PRESTO_VFS_DELEXTATTR: non-zero return $rc\n";
+    }
+}
+
 
 sub dogetopt { 
     my $psdev = shift;
Index: lento/Lento/KML/Rec.pm
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/lento/Lento/KML/Rec.pm,v
retrieving revision 1.41.2.3
diff -u -r1.41.2.3 Rec.pm
--- lento/Lento/KML/Rec.pm	2001/04/24 00:30:10	1.41.2.3
+++ lento/Lento/KML/Rec.pm	2001/07/07 00:56:47
@@ -12,13 +12,15 @@
                      2 => \&unpack_mkdir,
                      3 => \&unpack_unlink,
                      4 => \&unpack_rmdir,
-                 5 => \&unpack_close,
+                     5 => \&unpack_close,
                      6 => \&unpack_symlink,
                      7 => \&unpack_rename,
                      8 => \&unpack_setattr,
                      9 => \&unpack_link,
                     10 => \&unpack_open,
-                    11 => \&unpack_mknod);
+                    11 => \&unpack_mknod,
+                    15 => \&unpack_extattr,
+                    16 => \&unpack_extattr);
 
 sub size_round {
     my $val = shift;
@@ -177,6 +179,17 @@
         if defined $self->{flags};
     $str .= sprintf "    Major     $self->{major}\n" if defined $self->{major};
     $str .= sprintf "    Minor     $self->{minor}\n" if defined $self->{minor};
+    $str .= sprintf "    EA Flags  $self->{attr_flags}\n" 
+        if defined $self->{attr_flags};
+    $str .= sprintf "    EA Namlen $self->{namelen}\n" 
+        if defined $self->{namelen};
+    $str .= sprintf "    EA Name   $self->{attr_name}\n" 
+        if defined $self->{attr_name};
+    # do this to detect null value attributes
+    $str .= sprintf "    EA Buflen $self->{buflen}\n" 
+        if defined $self->{buflen};
+    $str .= sprintf "    EA Value  $self->{attr_value}\n" 
+        if defined $self->{attr_value};
 
     $str .= " -- Version:\n";
     # object information
@@ -426,6 +439,42 @@
     $self->{op} = "CLOSE";
     $self->{path} = substr($buf, $pos + $unpack_size, $self->{pathlen});
     $self->{offs} = $pos + $unpack_size + size_round($self->{pathlen});
+
+    return $self;
+}
+
+
+# Unpack extended attributes
+sub unpack_extattr {
+    my ($self, $buf, $pos) = @_;
+    my $unpack_size = 68;
+
+    DEBUG("POS $pos\n");
+    ($self->{old_obj_mtime}, $self->{old_obj_ctime}, $self->{old_obj_size}, 
+     $self->{new_obj_mtime}, $self->{new_obj_ctime}, $self->{new_obj_size}, 
+     $self->{attr_flags}, $self->{mode}, $self->{pathlen}, $self->{namelen}, 
+     $self->{buflen}) = unpack("x$pos ix4ix4ix4 ix4ix4ix4 iiiii", $buf);
+
+    #XXX: Ugh...lazy shirish, using raw opcodes!!! write a new function? 
+    $self->{op} = ($self->{opcode} == 15) ? "SETEXTATTR" : "DELEXTATTR";
+    $self->{path} = substr($buf, $pos + $unpack_size, $self->{pathlen});
+    $self->{attr_name} = substr($buf, $pos + $unpack_size 
+                               +size_round($self->{pathlen}), 
+                               $self->{namelen});
+
+    # only unpack value if this is not a delete 
+    if ($self->{opcode} == 15) {
+        # Note that buflen can be zero for null attribute values 
+        $self->{attr_value} = substr($buf, $pos + $unpack_size 
+                                     +size_round($self->{pathlen})
+                                     +size_round($self->{namelen}), 
+                                     $self->{buflen});
+    } else {
+        $self->{buflen} = 0;
+    }
+
+    $self->{offs} = $pos + $unpack_size + size_round($self->{pathlen}) + 
+                    size_round($self->{namelen}) + size_round($self->{buflen});
 
     return $self;
 }
Index: lento/Lento/KML/Reint.pm
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/lento/Lento/KML/Reint.pm,v
retrieving revision 1.43.2.2
diff -u -r1.43.2.2 Reint.pm
--- lento/Lento/KML/Reint.pm	2001/04/06 20:20:44	1.43.2.2
+++ lento/Lento/KML/Reint.pm	2001/07/07 00:56:47
@@ -32,7 +32,9 @@
           8 => "reint_setattr",
           9 => "reint_link",
           10 => "reint_open",
-          11 => "reint_mknod");
+          11 => "reint_mknod",
+          15 => "reint_setextattr",
+          16 => "reint_delextattr");
 
 my $parentclass = "Lento::KML";
 
Index: lento/Lento/KML/ReintLento.pm
===================================================================
RCS file: /cvsroot/intermezzo/intermezzo/lento/Lento/KML/ReintLento.pm,v
retrieving revision 1.31.2.20
diff -u -r1.31.2.20 ReintLento.pm
--- lento/Lento/KML/ReintLento.pm	2001/06/10 02:54:12	1.31.2.20
+++ lento/Lento/KML/ReintLento.pm	2001/07/07 00:56:47
@@ -580,6 +580,47 @@
     return 1;
 }
 
+sub reint_setextattr {
+    my $rec = shift;
+    my $mtpt = shift;
+    my $psdev = shift;
+    my $slot_offset = shift;
+    my $flags = shift;
+    # right now no atime, but lento_setattr needs it
+    my $atime = 0;
+    my $path = $mtpt . $rec->{path};
+    
+    reint_pre_secure($rec);
+    
+    $psdev->lento_setextattr($path, $rec->{attr_name}, $rec->{attr_value}, 
+                             $rec->{attr_flags}, $rec->{mode},
+                             $slot_offset, $rec->{recno},
+                             $rec->{kml_offset} + $rec->{len}, $flags,
+                             $rec->{new_obj_ctime});
+    reint_post_secure($rec);
+    return 0;
+}
+
+sub reint_delextattr {
+    my $rec = shift;
+    my $mtpt = shift;
+    my $psdev = shift;
+    my $slot_offset = shift;
+    my $flags = shift;
+    # right now no atime, but lento_setattr needs it
+    my $atime = 0;
+    my $path = $mtpt . $rec->{path};
+    
+    reint_pre_secure($rec);
+    
+    $psdev->lento_delextattr($path, $rec->{attr_name}, $rec->{attr_flags}, 
+                             $rec->{mode}, $slot_offset, $rec->{recno},
+                             $rec->{kml_offset} + $rec->{len}, $flags,
+                             $rec->{new_obj_ctime});
+    reint_post_secure($rec);
+    return 0;
+}
+
 1;
 
 __END__
Index: lento/tests/lento-extattr.pl
===================================================================
RCS file: lento-extattr.pl
diff -N lento-extattr.pl
--- /dev/null	Thu May 24 22:33:05 2001
+++ lento-extattr.pl	Fri Jul  6 17:56:47 2001
@@ -0,0 +1,32 @@
+# Test extended attribute psdev interface
+package TestExtAttr;
+use lib qw(.. ../..);
+
+use strict;
+use Lento::Psdev;
+use Lento::Debuggable;
+
+$TestExtAttr::level=1;
+$Lento::Psdev::level=1;
+$::global_debug=1000;
+$::prestodev = "/dev/intermezzo0";
+my $mnt = "/izo-test";
+
+$::psdev = Lento::Psdev->new($::prestodev);
+$::psdev->open();
+
+#time 91109202
+
+# note the 0x100xyz mode. If this is not specified, files will end with bad
+# type and may be inaccessible/lost.
+$::psdev->lento_create($mnt . "/newfile", 0755, 0, 4711, 0, 3);
+print `stat /izo-test/newfile`;
+# null attribute
+$::psdev->lento_setextattr($mnt . "/newfile", "first", "", 0, 0100717, 153, 222, \
555, 0x0003, 10); +print `stat /izo-test/newfile`;
+$::psdev->lento_setextattr($mnt . "/newfile", "second", "string1", 0, 0100727, 153, \
222, 555, 0x0003, 100000); +$::psdev->lento_setextattr($mnt . "/newfile", "third", \
"string2", 0, 0100333, 153, 222, 555, 0x0003, 100000); +print `aget -ds \
"/izo-test/newfile"`; +$::psdev->lento_delextattr($mnt . "/newfile", "first", 0, \
0100757, 153, 222, 555, 0x0003, 100000); +$::psdev->lento_delextattr($mnt . \
"/newfile", "second", 0, 0100222, 153, 222, 555, 0x0003, 100000); +print `aget -ds \
"/izo-test/newfile"`;


_______________________________________________
intermezzo-discuss mailing list
intermezzo-discuss@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/intermezzo-discuss


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic