1/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- 2 * vim:expandtab:shiftwidth=8:tabstop=8: 3 * 4 * Copyright (C) 2001 Tacit Networks, Inc. 5 * Author: Shirish H. Phatak <shirish@tacitnetworks.com> 6 * 7 * This file is part of InterMezzo, http://www.inter-mezzo.org. 8 * 9 * InterMezzo is free software; you can redistribute it and/or 10 * modify it under the terms of version 2 of the GNU General Public 11 * License as published by the Free Software Foundation. 12 * 13 * InterMezzo is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with InterMezzo; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 * 22 * Extended attribute handling for presto. 23 */ 24 25#define __NO_VERSION__ 26#include <linux/module.h> 27#include <linux/kernel.h> 28#include <linux/mm.h> 29#include <linux/string.h> 30#include <linux/stat.h> 31#include <linux/errno.h> 32#include <linux/locks.h> 33#include <linux/unistd.h> 34 35#include <asm/system.h> 36#include <asm/uaccess.h> 37 38#include <linux/fs.h> 39#include <linux/stat.h> 40#include <linux/errno.h> 41#include <linux/locks.h> 42#include <linux/string.h> 43#include <asm/uaccess.h> 44#include <linux/slab.h> 45#include <linux/vmalloc.h> 46#include <asm/segment.h> 47#include <linux/smp_lock.h> 48 49#include <linux/intermezzo_fs.h> 50#include <linux/intermezzo_psdev.h> 51 52#ifdef CONFIG_FS_EXT_ATTR 53#include <linux/ext_attr.h> 54 55extern inline void presto_debug_fail_blkdev(struct presto_file_set *fset, 56 unsigned long value); 57 58 59/* VFS interface */ 60int presto_set_ext_attr(struct inode *inode, 61 const char *name, void *buffer, 62 size_t buffer_len, int flags) 63{ 64 int error; 65 struct presto_cache *cache; 66 struct presto_file_set *fset; 67 struct lento_vfs_context info; 68 struct dentry *dentry; 69 int minor = presto_i2m(inode); 70 char *buf = NULL; 71 72 ENTRY; 73 if (minor < 0) { 74 EXIT; 75 return -1; 76 } 77 78 if ( ISLENTO(minor) ) { 79 EXIT; 80 return -EINVAL; 81 } 82 83 /* BAD...vfs should really pass down the dentry to use, especially 84 * since every other operation in iops does. But for now 85 * we do a reverse mapping from inode to the first dentry 86 */ 87 if (list_empty(&inode->i_dentry)) { 88 CERROR("No alias for inode %d\n", (int) inode->i_ino); 89 EXIT; 90 return -EINVAL; 91 } 92 93 dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); 94 95 error = presto_prep(dentry, &cache, &fset); 96 if ( error ) { 97 EXIT; 98 return error; 99 } 100 101 if ((buffer != NULL) && (buffer_len != 0)) { 102 if (flags & EXT_ATTR_FLAG_USER) { 103 PRESTO_ALLOC(buf, buffer_len); 104 if (!buf) { 105 CERROR("InterMezzo: out of memory!!!\n"); 106 return -ENOMEM; 107 } 108 error = copy_from_user(buf, buffer, buffer_len); 109 if (error) 110 return -EFAULT; 111 } else 112 buf = buffer; 113 } else 114 buf = buffer; 115 116 if ( presto_get_permit(inode) < 0 ) { 117 EXIT; 118 if (buffer_len && (flags & EXT_ATTR_FLAG_USER)) 119 PRESTO_FREE(buf, buffer_len); 120 return -EROFS; 121 } 122 123 /* Simulate presto_setup_info */ 124 memset(&info, 0, sizeof(info)); 125 /* For now redundant..but we keep it around just in case */ 126 info.flags = LENTO_FL_IGNORE_TIME; 127 if (!ISLENTO(cache->cache_psdev->uc_minor)) 128 info.flags |= LENTO_FL_KML; 129 130 /* We pass in the kernel space pointer and reset the 131 * EXT_ATTR_FLAG_USER flag. 132 * See comments above. 133 */ 134 /* Note that mode is already set by VFS so we send in a NULL */ 135 error = presto_do_set_ext_attr(fset, dentry, name, buf, 136 buffer_len, flags & ~EXT_ATTR_FLAG_USER, 137 NULL, &info); 138 presto_put_permit(inode); 139 140 if (buffer_len && (flags & EXT_ATTR_FLAG_USER)) 141 PRESTO_FREE(buf, buffer_len); 142 EXIT; 143 return error; 144} 145 146/* Lento Interface */ 147int lento_set_ext_attr(const char *path, const char *name, 148 void *buffer, size_t buffer_len, int flags, mode_t mode, 149 struct lento_vfs_context *info) 150{ 151 int error; 152 char * pathname; 153 struct nameidata nd; 154 struct dentry *dentry; 155 struct presto_file_set *fset; 156 157 ENTRY; 158 lock_kernel(); 159 160 pathname=getname(path); 161 error = PTR_ERR(pathname); 162 if (IS_ERR(pathname)) { 163 EXIT; 164 goto exit; 165 } 166 167 /* Note that ext_attrs apply to both files and directories..*/ 168 error=presto_walk(pathname,&nd); 169 if (error) 170 goto exit; 171 dentry = nd.dentry; 172 173 fset = presto_fset(dentry); 174 error = -EINVAL; 175 if ( !fset ) { 176 CERROR("No fileset!\n"); 177 EXIT; 178 goto exit_dentry; 179 } 180 181 if (buffer==NULL) buffer_len=0; 182 183 error = presto_do_set_ext_attr(fset, dentry, name, buffer, 184 buffer_len, flags, &mode, info); 185exit_dentry: 186 path_release(&nd); 187exit_path: 188 putname(pathname); 189exit: 190 unlock_kernel(); 191 return error; 192} 193 194#endif /*CONFIG_FS_EXT_ATTR*/ 195