/* * Extended attribute handling for presto. * * Copyright (C) 2001. All rights reserved. * Shirish H. Phatak * Tacit Networks, Inc. * */ #define __NO_VERSION__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_FS_EXT_ATTR #include 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 nameidata nd; 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; } /* Note that ext_attrs apply to both files and directories..*/ error=presto_walk(pathname,&nd); if (error) goto exit; dentry = nd.dentry; 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: path_release(&nd); exit_path: putname(pathname); exit: unlock_kernel(); return error; } #endif /*CONFIG_FS_EXT_ATTR*/