afs: clarify cold and warm shutdown logic
[openafs.git] / src / afs / LINUX / osi_vfsops.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * VFS operations for Linux
12  *
13  * super_block operations should return negated errno to Linux.
14  */
15 #include <afsconfig.h>
16 #include "afs/param.h"
17
18
19 #define __NO_VERSION__          /* don't define kernel_version in module.h */
20 #include <linux/module.h> /* early to avoid printf->printk mapping */
21 #include "afs/sysincludes.h"
22 #include "afsincludes.h"
23 #include "afs/afs_stats.h"
24
25 #include "osi_compat.h"
26
27 struct vcache *afs_globalVp = 0;
28 struct vfs *afs_globalVFS = 0;
29 struct vfsmount *afs_cacheMnt;
30 int afs_was_mounted = 0;        /* Used to force reload if mount/unmount/mount */
31
32 extern struct super_operations afs_sops;
33 #if !defined(AFS_NONFSTRANS)
34 extern struct export_operations afs_export_ops;
35 #endif
36 extern struct afs_q VLRU;
37
38 extern struct dentry_operations afs_dentry_operations;
39
40 /* Forward declarations */
41 static int afs_root(struct super_block *afsp);
42 static int afs_fill_super(struct super_block *sb, void *data, int silent);
43
44
45 /*
46  * afs_mount (2.6.37+) and afs_get_sb (2.6.36-) are the entry
47  * points from the vfs when mounting afs.  The super block
48  * structure is setup in the afs_fill_super callback function.
49  */
50
51 #if defined(STRUCT_FILE_SYSTEM_TYPE_HAS_MOUNT)
52 static struct dentry *
53 afs_mount(struct file_system_type *fs_type, int flags,
54           const char *dev_name, void *data)
55 {
56     return mount_nodev(fs_type, flags, data, afs_fill_super);
57 }
58 #elif defined(GET_SB_HAS_STRUCT_VFSMOUNT)
59 static int
60 afs_get_sb(struct file_system_type *fs_type, int flags,
61            const char *dev_name, void *data, struct vfsmount *mnt)
62 {
63     return get_sb_nodev(fs_type, flags, data, afs_fill_super, mnt);
64 }
65 #else
66 static struct super_block *
67 afs_get_sb(struct file_system_type *fs_type, int flags,
68            const char *dev_name, void *data)
69 {
70     return get_sb_nodev(fs_type, flags, data, afs_fill_super);
71 }
72 #endif
73
74 struct file_system_type afs_fs_type = {
75     .owner = THIS_MODULE,
76     .name = "afs",
77 #if defined(STRUCT_FILE_SYSTEM_TYPE_HAS_MOUNT)
78     .mount = afs_mount,
79 #else
80     .get_sb = afs_get_sb,
81 #endif
82     .kill_sb = kill_anon_super,
83     .fs_flags = FS_BINARY_MOUNTDATA,
84 };
85
86 struct backing_dev_info *afs_backing_dev_info;
87
88 static int
89 afs_fill_super(struct super_block *sb, void *data, int silent)
90 {
91     int code = 0;
92 #if defined(HAVE_LINUX_BDI_INIT)
93     int bdi_init_done = 0;
94 #endif
95
96     AFS_GLOCK();
97     if (afs_was_mounted) {
98         printf
99             ("You must reload the AFS kernel extensions before remounting AFS.\n");
100         AFS_GUNLOCK();
101         return -EINVAL;
102     }
103     afs_was_mounted = 1;
104
105     /* Set basics of super_block */
106    __module_get(THIS_MODULE);
107
108     afs_globalVFS = sb;
109 #if defined(SB_NOATIME)
110     sb->s_flags |= SB_NOATIME;
111 #else
112     sb->s_flags |= MS_NOATIME;
113 #endif
114     sb->s_blocksize = 1024;
115     sb->s_blocksize_bits = 10;
116     sb->s_magic = AFS_VFSMAGIC;
117     sb->s_op = &afs_sops;       /* Super block (vfs) ops */
118
119 #if defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP)
120     sb->s_d_op = &afs_dentry_operations;
121 #endif
122 #if defined(HAVE_LINUX_SUPER_SETUP_BDI)
123     code = super_setup_bdi(sb);
124     if (code)
125         goto out;
126 # if defined(STRUCT_BACKING_DEV_INFO_HAS_NAME)
127     sb->s_bdi->name = "openafs";
128 # endif
129     sb->s_bdi->ra_pages = 32;
130 #else
131     /* used for inodes backing_dev_info field, also */
132     afs_backing_dev_info = kzalloc(sizeof(struct backing_dev_info), GFP_NOFS);
133 #if defined(HAVE_LINUX_BDI_INIT)
134     code = bdi_init(afs_backing_dev_info);
135     if (code)
136         goto out;
137     bdi_init_done = 1;
138 #endif
139 #if defined(STRUCT_BACKING_DEV_INFO_HAS_NAME)
140     afs_backing_dev_info->name = "openafs";
141 #endif
142     afs_backing_dev_info->ra_pages = 32;
143 #if defined (STRUCT_SUPER_BLOCK_HAS_S_BDI)
144     sb->s_bdi = afs_backing_dev_info;
145     /* The name specified here will appear in the flushing thread name - flush-afs */
146     bdi_register(afs_backing_dev_info, NULL, "afs");
147 #endif
148 #endif /* HAVE_LINUX_SUPER_SETUP_BDI */
149 #if !defined(AFS_NONFSTRANS)
150     sb->s_export_op = &afs_export_ops;
151 #endif
152 #if defined(MAX_NON_LFS)
153 #ifdef AFS_64BIT_CLIENT
154 #if !defined(MAX_LFS_FILESIZE)
155 #if BITS_PER_LONG==32
156 #define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) 
157 #elif BITS_PER_LONG==64
158 #define MAX_LFS_FILESIZE 0x7fffffffffffffff
159 #endif
160 #endif
161     sb->s_maxbytes = MAX_LFS_FILESIZE;
162 #else
163     sb->s_maxbytes = MAX_NON_LFS;
164 #endif
165 #endif
166     code = afs_root(sb);
167 out:
168     if (code) {
169         afs_globalVFS = NULL;
170         afs_FlushAllVCaches();
171 #if defined(HAVE_LINUX_BDI_INIT)
172         if (bdi_init_done)
173             bdi_destroy(afs_backing_dev_info);
174 #endif
175 #if !defined(HAVE_LINUX_SUPER_SETUP_BDI)
176         kfree(afs_backing_dev_info);
177 #endif
178         module_put(THIS_MODULE);
179     }
180
181     AFS_GUNLOCK();
182     return code ? -EINVAL : 0;
183 }
184
185
186 /* afs_root - stat the root of the file system. AFS global held on entry. */
187 static int
188 afs_root(struct super_block *afsp)
189 {
190     afs_int32 code = 0;
191     struct vcache *tvp = 0;
192
193     AFS_STATCNT(afs_root);
194     if (afs_globalVp && (afs_globalVp->f.states & CStatd)) {
195         tvp = afs_globalVp;
196     } else {
197         struct vrequest *treq = NULL;
198         cred_t *credp = crref();
199
200         if (afs_globalVp) {
201             afs_PutVCache(afs_globalVp);
202             afs_globalVp = NULL;
203         }
204
205         if (!(code = afs_CreateReq(&treq, credp)) && !(code = afs_CheckInit())) {
206             tvp = afs_GetVCache(&afs_rootFid, treq);
207             if (tvp) {
208                 struct inode *ip = AFSTOV(tvp);
209                 struct vattr *vattr = NULL;
210
211                 code = afs_CreateAttr(&vattr);
212                 if (!code) {
213                     afs_getattr(tvp, vattr, credp);
214                     afs_fill_inode(ip, vattr);
215
216                     /* setup super_block and mount point inode. */
217                     afs_globalVp = tvp;
218 #if defined(HAVE_LINUX_D_MAKE_ROOT)
219                     afsp->s_root = d_make_root(ip);
220 #else
221                     afsp->s_root = d_alloc_root(ip);
222 #endif
223 #if !defined(STRUCT_SUPER_BLOCK_HAS_S_D_OP)
224                     afsp->s_root->d_op = &afs_dentry_operations;
225 #endif
226                     afs_DestroyAttr(vattr);
227                 }
228             } else
229                 code = EIO;
230         }
231         crfree(credp);
232         afs_DestroyReq(treq);
233     }
234
235     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, afs_globalVp,
236                ICL_TYPE_INT32, code);
237     return code;
238 }
239
240 /* super_operations */
241
242 #if defined(STRUCT_SUPER_OPERATIONS_HAS_ALLOC_INODE)
243 static afs_kmem_cache_t *afs_inode_cachep;
244
245 static struct inode *
246 afs_alloc_inode(struct super_block *sb)
247 {
248     struct vcache *vcp;
249
250     vcp = (struct vcache *) kmem_cache_alloc(afs_inode_cachep, KALLOC_TYPE);
251     if (!vcp)
252         return NULL;
253
254     return AFSTOV(vcp);
255 }
256
257 static void
258 afs_destroy_inode(struct inode *inode)
259 {
260     kmem_cache_free(afs_inode_cachep, inode);
261 }
262
263 void
264 init_once(void * foo)
265 {
266     struct vcache *vcp = (struct vcache *) foo;
267
268     inode_init_once(AFSTOV(vcp));
269 }
270
271 int
272 afs_init_inodecache(void)
273 {
274 #if defined(KMEM_CACHE_TAKES_DTOR)
275     afs_inode_cachep = kmem_cache_create("afs_inode_cache",
276                 sizeof(struct vcache), 0,
277                 SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT, init_once_func, NULL);
278 #else
279     afs_inode_cachep = kmem_cache_create("afs_inode_cache",
280                 sizeof(struct vcache), 0,
281                 SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT, init_once_func);
282 #endif
283     if (afs_inode_cachep == NULL)
284         return -ENOMEM;
285     return 0;
286 }
287
288 void
289 afs_destroy_inodecache(void)
290 {
291     if (afs_inode_cachep)
292         (void) kmem_cache_destroy(afs_inode_cachep);
293 }
294 #else
295 int
296 afs_init_inodecache(void)
297 {
298     return 0;
299 }
300
301 void
302 afs_destroy_inodecache(void)
303 {
304     return;
305 }
306 #endif
307
308 #if defined(STRUCT_SUPER_OPERATIONS_HAS_EVICT_INODE)
309 static void
310 afs_evict_inode(struct inode *ip)
311 {
312     struct vcache *vcp = VTOAFS(ip);
313
314     if (vcp->vlruq.prev || vcp->vlruq.next)
315         osi_Panic("inode freed while on LRU");
316     if (vcp->hnext)
317         osi_Panic("inode freed while still hashed");
318
319     truncate_inode_pages(&ip->i_data, 0);
320 #if defined(HAVE_LINUX_CLEAR_INODE)
321     clear_inode(ip);
322 #else
323     end_writeback(ip);
324 #endif
325
326 #if !defined(STRUCT_SUPER_OPERATIONS_HAS_ALLOC_INODE)
327     afs_osi_Free(ip->u.generic_ip, sizeof(struct vcache));
328 #endif
329 }
330 #else
331 static void
332 afs_clear_inode(struct inode *ip)
333 {
334     struct vcache *vcp = VTOAFS(ip);
335
336     if (vcp->vlruq.prev || vcp->vlruq.next)
337         osi_Panic("inode freed while on LRU");
338     if (vcp->hnext)
339         osi_Panic("inode freed while still hashed");
340
341 #if !defined(STRUCT_SUPER_OPERATIONS_HAS_ALLOC_INODE)
342     afs_osi_Free(ip->u.generic_ip, sizeof(struct vcache));
343 #endif
344 }
345 #endif
346
347 /* afs_put_super
348  * Called from unmount to release super_block. */
349 static void
350 afs_put_super(struct super_block *sbp)
351 {
352     AFS_GLOCK();
353     AFS_STATCNT(afs_unmount);
354
355     afs_globalVFS = 0;
356     afs_globalVp = 0;
357
358     afs_shutdown(AFS_WARM);
359     mntput(afs_cacheMnt);
360
361     osi_linux_verify_alloced_memory();
362 #if defined(HAVE_LINUX_BDI_INIT)
363     bdi_destroy(afs_backing_dev_info);
364 #endif
365     kfree(afs_backing_dev_info);
366     AFS_GUNLOCK();
367
368     sbp->s_dev = 0;
369     module_put(THIS_MODULE);
370 }
371
372
373 /* afs_statfs
374  * statp is in user space, so we need to cobble together a statfs, then
375  * copy it.
376  */
377 static int
378 #if defined(STATFS_TAKES_DENTRY)
379 afs_statfs(struct dentry *dentry, struct kstatfs *statp)
380 #else
381 afs_statfs(struct super_block *sbp, struct kstatfs *statp)
382 #endif
383 {
384     memset(statp, 0, sizeof(*statp));
385
386     AFS_STATCNT(afs_statfs);
387
388     /* hardcode in case that which is giveth is taken away */
389     statp->f_type = 0x5346414F;
390 #if defined(STATFS_TAKES_DENTRY)
391     statp->f_bsize = dentry->d_sb->s_blocksize;
392 #else
393     statp->f_bsize = sbp->s_blocksize;
394 #endif
395     statp->f_blocks = statp->f_bfree = statp->f_bavail = statp->f_files =
396         statp->f_ffree = AFS_VFS_FAKEFREE;
397     statp->f_fsid.val[0] = AFS_VFSMAGIC;
398     statp->f_fsid.val[1] = AFS_VFSFSID;
399     statp->f_namelen = 256;
400
401     return 0;
402 }
403
404 struct super_operations afs_sops = {
405 #if defined(STRUCT_SUPER_OPERATIONS_HAS_ALLOC_INODE)
406   .alloc_inode =        afs_alloc_inode,
407   .destroy_inode =      afs_destroy_inode,
408 #endif
409 #if defined(STRUCT_SUPER_OPERATIONS_HAS_EVICT_INODE)
410   .evict_inode =        afs_evict_inode,
411 #else
412   .clear_inode =        afs_clear_inode,
413 #endif
414   .put_super =          afs_put_super,
415   .statfs =             afs_statfs,
416 };