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