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
55 extern inline void presto_debug_fail_blkdev(struct presto_file_set *fset,
56 unsigned long value);
57
58
59 /* VFS interface */
60 /* XXX! Fixme test for user defined attributes */
presto_set_ext_attr(struct inode * inode,const char * name,void * buffer,size_t buffer_len,int flags)61 int presto_set_ext_attr(struct inode *inode,
62 const char *name, void *buffer,
63 size_t buffer_len, int flags)
64 {
65 int error;
66 struct presto_cache *cache;
67 struct presto_file_set *fset;
68 struct lento_vfs_context info;
69 struct dentry *dentry;
70 int minor = presto_i2m(inode);
71 char *buf = NULL;
72
73 ENTRY;
74 if (minor < 0) {
75 EXIT;
76 return -1;
77 }
78
79 if ( ISLENTO(minor) ) {
80 EXIT;
81 return -EINVAL;
82 }
83
84 /* BAD...vfs should really pass down the dentry to use, especially
85 * since every other operation in iops does. But for now
86 * we do a reverse mapping from inode to the first dentry
87 */
88 if (list_empty(&inode->i_dentry)) {
89 CERROR("No alias for inode %d\n", (int) inode->i_ino);
90 EXIT;
91 return -EINVAL;
92 }
93
94 dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
95
96 error = presto_prep(dentry, &cache, &fset);
97 if ( error ) {
98 EXIT;
99 return error;
100 }
101
102 if ((buffer != NULL) && (buffer_len != 0)) {
103 /* If buffer is a user space pointer copy it to kernel space
104 * and reset the flag. We do this since the journal functions need
105 * access to the contents of the buffer, and the file system
106 * does not care. When we actually invoke the function, we remove
107 * the EXT_ATTR_FLAG_USER flag.
108 *
109 * XXX:Check if the "fs does not care" assertion is always true -SHP
110 * (works for ext3)
111 */
112 if (flags & EXT_ATTR_FLAG_USER) {
113 PRESTO_ALLOC(buf, buffer_len);
114 if (!buf) {
115 CERROR("InterMezzo: out of memory!!!\n");
116 return -ENOMEM;
117 }
118 error = copy_from_user(buf, buffer, buffer_len);
119 if (error)
120 return -EFAULT;
121 } else
122 buf = buffer;
123 } else
124 buf = buffer;
125
126 if ( presto_get_permit(inode) < 0 ) {
127 EXIT;
128 if (buffer_len && (flags & EXT_ATTR_FLAG_USER))
129 PRESTO_FREE(buf, buffer_len);
130 return -EROFS;
131 }
132
133 /* Simulate presto_setup_info */
134 memset(&info, 0, sizeof(info));
135 /* For now redundant..but we keep it around just in case */
136 info.flags = LENTO_FL_IGNORE_TIME;
137 if (!ISLENTO(cache->cache_psdev->uc_minor))
138 info.flags |= LENTO_FL_KML;
139
140 /* We pass in the kernel space pointer and reset the
141 * EXT_ATTR_FLAG_USER flag.
142 * See comments above.
143 */
144 /* Note that mode is already set by VFS so we send in a NULL */
145 error = presto_do_set_ext_attr(fset, dentry, name, buf,
146 buffer_len, flags & ~EXT_ATTR_FLAG_USER,
147 NULL, &info);
148 presto_put_permit(inode);
149
150 if (buffer_len && (flags & EXT_ATTR_FLAG_USER))
151 PRESTO_FREE(buf, buffer_len);
152 EXIT;
153 return error;
154 }
155
156 /* Lento Interface */
157 /* XXX: ignore flags? We should be forcing these operations through? -SHP*/
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)158 int lento_set_ext_attr(const char *path, const char *name,
159 void *buffer, size_t buffer_len, int flags, mode_t mode,
160 struct lento_vfs_context *info)
161 {
162 int error;
163 char * pathname;
164 struct nameidata nd;
165 struct dentry *dentry;
166 struct presto_file_set *fset;
167
168 ENTRY;
169 lock_kernel();
170
171 pathname=getname(path);
172 error = PTR_ERR(pathname);
173 if (IS_ERR(pathname)) {
174 EXIT;
175 goto exit;
176 }
177
178 /* Note that ext_attrs apply to both files and directories..*/
179 error=presto_walk(pathname,&nd);
180 if (error)
181 goto exit;
182 dentry = nd.dentry;
183
184 fset = presto_fset(dentry);
185 error = -EINVAL;
186 if ( !fset ) {
187 CERROR("No fileset!\n");
188 EXIT;
189 goto exit_dentry;
190 }
191
192 if (buffer==NULL) buffer_len=0;
193
194 error = presto_do_set_ext_attr(fset, dentry, name, buffer,
195 buffer_len, flags, &mode, info);
196 exit_dentry:
197 path_release(&nd);
198 exit_path:
199 putname(pathname);
200 exit:
201 unlock_kernel();
202 return error;
203 }
204
205 #endif /*CONFIG_FS_EXT_ATTR*/
206