1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
5  *    Michael Callahan <callahan@maths.ox.ac.uk>
6  *  Copyright (C) 1999 Carnegie Mellon University
7  *    Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>
8  *
9  *   This file is part of InterMezzo, http://www.inter-mezzo.org.
10  *
11  *   InterMezzo is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   InterMezzo is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with InterMezzo; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  * Super block/filesystem wide operations
25  */
26 
27 #define __NO_VERSION__
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/mm.h>
31 #include <linux/string.h>
32 #include <linux/stat.h>
33 #include <linux/errno.h>
34 #include <linux/locks.h>
35 #include <linux/unistd.h>
36 
37 #include <asm/system.h>
38 #include <asm/uaccess.h>
39 
40 #include <linux/fs.h>
41 #include <linux/stat.h>
42 #include <linux/errno.h>
43 #include <linux/locks.h>
44 #include <linux/string.h>
45 #include <asm/uaccess.h>
46 #include <linux/slab.h>
47 #include <linux/vmalloc.h>
48 #include <asm/segment.h>
49 
50 #include <linux/intermezzo_fs.h>
51 #include <linux/intermezzo_psdev.h>
52 
53 extern void presto_free_cache(struct presto_cache *);
54 
presto_set_ops(struct inode * inode,struct filter_fs * filter)55 void presto_set_ops(struct inode *inode, struct  filter_fs *filter)
56 {
57         ENTRY;
58 
59         if (!inode || is_bad_inode(inode))
60                 return;
61 
62         if (S_ISREG(inode->i_mode)) {
63                 if ( !filter_c2cfiops(filter) ) {
64                        filter_setup_file_ops(filter,
65                                              inode, &presto_file_iops,
66                                              &presto_file_fops);
67                 }
68                 inode->i_op = filter_c2ufiops(filter);
69                 inode->i_fop = filter_c2uffops(filter);
70                 CDEBUG(D_INODE, "set file methods for %ld to %p\n",
71                        inode->i_ino, inode->i_op);
72         } else if (S_ISDIR(inode->i_mode)) {
73                 inode->i_op = filter_c2udiops(filter);
74                 inode->i_fop = filter_c2udfops(filter);
75                 CDEBUG(D_INODE, "set dir methods for %ld to %p ioctl %p\n",
76                        inode->i_ino, inode->i_op, inode->i_fop->ioctl);
77         } else if (S_ISLNK(inode->i_mode)) {
78                 if ( !filter_c2csiops(filter)) {
79                         filter_setup_symlink_ops(filter,
80                                                  inode,
81                                                  &presto_sym_iops,
82                                                  &presto_sym_fops);
83                 }
84                 inode->i_op = filter_c2usiops(filter);
85                 inode->i_fop = filter_c2usfops(filter);
86                 CDEBUG(D_INODE, "set link methods for %ld to %p\n",
87                        inode->i_ino, inode->i_op);
88         }
89         EXIT;
90 }
91 
presto_read_inode(struct inode * inode)92 void presto_read_inode(struct inode *inode)
93 {
94         struct presto_cache *cache;
95 
96         cache = presto_get_cache(inode);
97         if ( !cache ) {
98                 CERROR("PRESTO: BAD, BAD: cannot find cache\n");
99                 make_bad_inode(inode);
100                 return ;
101         }
102 
103         filter_c2csops(cache->cache_filter)->read_inode(inode);
104 
105         CDEBUG(D_INODE, "presto_read_inode: ino %ld, gid %d\n",
106                inode->i_ino, inode->i_gid);
107 
108         presto_set_ops(inode, cache->cache_filter);
109         /* XXX handle special inodes here or not - probably not? */
110 }
111 
presto_put_super(struct super_block * sb)112 static void presto_put_super(struct super_block *sb)
113 {
114         struct presto_cache *cache;
115         struct upc_channel *channel;
116         struct super_operations *sops;
117         struct list_head *lh;
118         int err;
119 
120         ENTRY;
121         cache = presto_cache_find(sb->s_dev);
122         if (!cache) {
123                 EXIT;
124                 goto exit;
125         }
126         channel = &izo_channels[presto_c2m(cache)];
127         sops = filter_c2csops(cache->cache_filter);
128         err = izo_clear_all_fsetroots(cache);
129         if (err) {
130                 CERROR("%s: err %d\n", __FUNCTION__, err);
131         }
132         PRESTO_FREE(cache->cache_vfsmount, sizeof(struct vfsmount));
133 
134         /* look at kill_super - fsync_super is not exported GRRR but
135            probably not needed */
136         unlock_super(sb);
137         shrink_dcache_parent(cache->cache_root);
138         dput(cache->cache_root);
139         //fsync_super(sb);
140         lock_super(sb);
141 
142         if (sops->write_super)
143                 sops->write_super(sb);
144 
145         if (sops->put_super)
146                 sops->put_super(sb);
147 
148         /* free any remaining async upcalls when the filesystem is unmounted */
149         spin_lock(&channel->uc_lock);
150         lh = channel->uc_pending.next;
151         while ( lh != &channel->uc_pending) {
152                 struct upc_req *req;
153                 req = list_entry(lh, struct upc_req, rq_chain);
154 
155                 /* assignment must be here: we are about to free &lh */
156                 lh = lh->next;
157                 if ( ! (req->rq_flags & REQ_ASYNC) )
158                         continue;
159                 list_del(&(req->rq_chain));
160                 PRESTO_FREE(req->rq_data, req->rq_bufsize);
161                 PRESTO_FREE(req, sizeof(struct upc_req));
162         }
163         list_del(&cache->cache_channel_list);
164         spin_unlock(&channel->uc_lock);
165 
166         presto_free_cache(cache);
167 
168 exit:
169         CDEBUG(D_MALLOC, "after umount: kmem %ld, vmem %ld\n",
170                presto_kmemory, presto_vmemory);
171         MOD_DEC_USE_COUNT;
172         return ;
173 }
174 
175 struct super_operations presto_super_ops = {
176         .read_inode    = presto_read_inode,
177         .put_super     = presto_put_super,
178 };
179 
180 
181 /* symlinks can be chowned */
182 struct inode_operations presto_sym_iops = {
183         .setattr       = presto_setattr
184 };
185 
186 /* NULL for now */
187 struct file_operations presto_sym_fops;
188