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