960d54c36899daf9584be3c984ceb528c9c80f9e
[openafs.git] / src / afs / LINUX / osi_vnodeops.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  * Linux specific vnodeops. Also includes the glue routines required to call
12  * AFS vnodeops. The "NOTUSED" #define is used to indicate routines and
13  * calling sequences present in an ops table that we don't actually use.
14  * They are present solely for documentation purposes.
15  *
16  * So far the only truly scary part is that Linux relies on the inode cache
17  * to be up to date. Don't you dare break a callback and expect an fstat
18  * to give you meaningful information. This appears to be fixed in the 2.1
19  * development kernels. As it is we can fix this now by intercepting the 
20  * stat calls.
21  */
22
23 #include "../afs/param.h"
24 #include "../afs/sysincludes.h"
25 #include "../afs/afsincludes.h"
26 #include "../afs/afs_stats.h"
27 #include "../h/mm.h"
28 #include "../h/pagemap.h"
29 #if defined(AFS_LINUX24_ENV)
30 #include "../h/smp_lock.h"
31 #endif
32
33 #ifdef pgoff2loff
34 #define pageoff(pp) pgoff2loff((pp)->index)
35 #else
36 #define pageoff(pp) pp->offset
37 #endif
38
39 extern struct vcache *afs_globalVp;
40
41 extern struct dentry_operations *afs_dops;
42 #if defined(AFS_LINUX24_ENV)
43 extern struct inode_operations afs_file_iops;
44 extern struct address_space_operations afs_file_aops;
45 struct address_space_operations afs_symlink_aops;
46 #endif
47 extern struct inode_operations afs_dir_iops;
48 extern struct inode_operations afs_symlink_iops;
49
50
51 #ifdef NOTUSED
52 static int afs_linux_lseek(struct inode *ip, struct file *fp, off_t, int) {}
53 #endif
54
55 static ssize_t afs_linux_read(struct file *fp, char *buf, size_t count,
56                               loff_t *offp)
57 {
58     ssize_t code;
59     struct vcache *vcp = (struct vcache*)fp->f_dentry->d_inode;
60     cred_t *credp = crref();
61     struct vrequest treq;
62
63     AFS_GLOCK();
64     afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
65                ICL_TYPE_INT32, (int)*offp,
66                ICL_TYPE_INT32, count,
67                ICL_TYPE_INT32, 99999);
68
69     /* get a validated vcache entry */
70     code = afs_InitReq(&treq, credp);
71     if (!code)
72         code = afs_VerifyVCache(vcp, &treq);
73
74     if (code)
75         code = -code;
76     else {
77         osi_FlushPages(vcp, credp);     /* ensure stale pages are gone */
78         AFS_GUNLOCK();
79         code = generic_file_read(fp, buf, count, offp);
80         AFS_GLOCK();
81     }
82
83     afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
84                ICL_TYPE_INT32, (int)*offp,
85                ICL_TYPE_INT32, count,
86                ICL_TYPE_INT32, code);
87
88     AFS_GUNLOCK();
89     crfree(credp);
90     return code;
91 }
92
93
94 /* Now we have integrated VM for writes as well as reads. generic_file_write
95  * also takes care of re-positioning the pointer if file is open in append
96  * mode. Call fake open/close to ensure we do writes of core dumps.
97  */
98 static ssize_t afs_linux_write(struct file *fp, const char *buf, size_t count,
99                            loff_t *offp)
100 {
101     ssize_t code = 0;
102     int code2;
103     struct vcache *vcp = (struct vcache *)fp->f_dentry->d_inode;
104     struct vrequest treq;
105     cred_t *credp = crref();
106
107     AFS_GLOCK();
108
109     afs_Trace4(afs_iclSetp, CM_TRACE_WRITEOP, ICL_TYPE_POINTER, vcp,
110                ICL_TYPE_INT32, (int)*offp, ICL_TYPE_INT32, count,
111                ICL_TYPE_INT32, (fp->f_flags & O_APPEND) ? 99998 : 99999);
112
113
114     /* get a validated vcache entry */
115     code = (ssize_t)afs_InitReq(&treq, credp);
116     if (!code)
117         code = (ssize_t)afs_VerifyVCache(vcp, &treq);
118
119     ObtainWriteLock(&vcp->lock, 529);
120     afs_FakeOpen(vcp);
121     ReleaseWriteLock(&vcp->lock);
122     AFS_GUNLOCK();
123     if (code)
124         code = -code;
125     else {
126         code = generic_file_write(fp, buf, count, offp);
127     }
128     AFS_GLOCK();
129
130     ObtainWriteLock(&vcp->lock, 530);
131     vcp->m.Date = osi_Time(); /* set modification time */
132     afs_FakeClose(vcp, credp);
133     if (code>=0)
134         code2 = afs_DoPartialWrite(vcp, &treq);
135     if (code2 && code >=0)
136         code = (ssize_t) -code2;
137     ReleaseWriteLock(&vcp->lock);
138         
139     afs_Trace4(afs_iclSetp, CM_TRACE_WRITEOP, ICL_TYPE_POINTER, vcp,
140                ICL_TYPE_INT32, (int)*offp, ICL_TYPE_INT32, count,
141                ICL_TYPE_INT32, code);
142
143     AFS_GUNLOCK();
144     crfree(credp);
145     return code;
146 }
147
148 /* This is a complete rewrite of afs_readdir, since we can make use of
149  * filldir instead of afs_readdir_move. Note that changes to vcache/dcache
150  * handling and use of bulkstats will need to be reflected here as well.
151  */
152 static int afs_linux_readdir(struct file *fp,
153                              void *dirbuf, filldir_t filldir)
154 {
155     extern struct DirEntry * afs_dir_GetBlob();
156     struct vcache *avc = (struct vcache*)FILE_INODE(fp);
157     struct vrequest treq;
158     register struct dcache *tdc;
159     int code;
160     int offset;
161     int dirpos;
162     struct DirEntry *de;
163     ino_t ino;
164     int len;
165     int origOffset;
166     cred_t *credp = crref();
167
168     AFS_GLOCK();
169     AFS_STATCNT(afs_readdir);
170
171     code = afs_InitReq(&treq, credp);
172     crfree(credp);
173     if (code) {
174         AFS_GUNLOCK();
175         return -code;
176     }
177
178     /* update the cache entry */
179 tagain:
180     code = afs_VerifyVCache(avc, &treq);
181     if (code) {
182         AFS_GUNLOCK();
183         return -code;
184     }
185
186     /* get a reference to the entire directory */
187     tdc = afs_GetDCache(avc, 0, &treq, &origOffset, &len, 1);
188     if (!tdc) {
189         AFS_GUNLOCK();
190         return -ENOENT;
191     }
192     ObtainReadLock(&avc->lock);
193     /*
194      * Make sure that the data in the cache is current. There are two
195      * cases we need to worry about:
196      * 1. The cache data is being fetched by another process.
197      * 2. The cache data is no longer valid
198      */
199     while ((avc->states & CStatd)
200            && (tdc->flags & DFFetching)
201            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
202         tdc->flags |= DFWaiting;
203         ReleaseReadLock(&avc->lock);
204         afs_osi_Sleep(&tdc->validPos);
205         ObtainReadLock(&avc->lock);
206     }
207     if (!(avc->states & CStatd)
208         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
209         ReleaseReadLock(&avc->lock);
210         afs_PutDCache(tdc);
211         goto tagain;
212     }
213
214     /* Fill in until we get an error or we're done. This implementation
215      * takes an offset in units of blobs, rather than bytes.
216      */
217     code = 0;
218     offset = (int)fp->f_pos;
219     while(1) { 
220         dirpos = BlobScan(&tdc->f.inode, offset);
221         if (!dirpos)
222             break;
223
224         de = (struct DirEntry*)afs_dir_GetBlob(&tdc->f.inode, dirpos);
225         if (!de)
226             break;
227
228         ino = (avc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
229         ino &= 0x7fffffff; /* Assumes 32 bit ino_t ..... */
230         len = strlen(de->name);
231
232         /* filldir returns -EINVAL when the buffer is full. */
233 #ifdef AFS_LINUX24_ENV
234         code = (*filldir)(dirbuf, de->name, len, offset, ino, DT_DIR);
235 #else
236         code = (*filldir)(dirbuf, de->name, len, offset, ino); 
237 #endif
238         DRelease(de, 0);
239         if (code)
240             break;
241         offset = dirpos + 1 + ((len+16)>>5);
242     }
243     /* If filldir didn't fill in the last one this is still pointing to that
244      * last attempt.
245      */
246     fp->f_pos = (loff_t)offset;
247
248     afs_PutDCache(tdc);
249     ReleaseReadLock(&avc->lock);
250     AFS_GUNLOCK();
251     return 0;
252 }
253
254 #ifdef NOTUSED
255 int afs_linux_select(struct inode *ip, struct file *fp, int, select_table *);
256 #endif
257
258 /* in afs_pioctl.c */
259 extern int afs_xioctl(struct inode *ip, struct file *fp,
260                           unsigned int com, unsigned long arg);
261
262
263 /* We need to detect unmap's after close. To do that, we need our own
264  * vm_operations_struct's. And we need to set them up for both the
265  * private and shared mappings. The fun part is that these are all static
266  * so we'll have to initialize on the fly!
267  */
268 static struct vm_operations_struct afs_private_mmap_ops;
269 static int afs_private_mmap_ops_inited = 0;
270 static struct vm_operations_struct afs_shared_mmap_ops;
271 static int afs_shared_mmap_ops_inited = 0;
272
273 void afs_linux_vma_close(struct vm_area_struct *vmap)
274 {
275     struct vcache *vcp;
276     cred_t *credp;
277
278     if (!vmap->vm_file)
279         return;
280
281     vcp = (struct vcache*)FILE_INODE(vmap->vm_file);
282     if (!vcp)
283         return;
284
285     AFS_GLOCK();
286     afs_Trace4(afs_iclSetp, CM_TRACE_VM_CLOSE,
287                ICL_TYPE_POINTER, vcp,
288                ICL_TYPE_INT32, vcp->mapcnt,
289                ICL_TYPE_INT32, vcp->opens,
290                ICL_TYPE_INT32, vcp->execsOrWriters);
291     ObtainWriteLock(&vcp->lock, 532);
292     if (vcp->mapcnt) {
293         vcp->mapcnt--;
294         ReleaseWriteLock(&vcp->lock);
295         if (!vcp->mapcnt) {
296             credp = crref();
297             (void) afs_close(vcp, vmap->vm_file->f_flags, credp);
298             /* only decrement the execsOrWriters flag if this is not a writable
299              * file. */
300             if (! (vmap->vm_file->f_flags & (FWRITE | FTRUNC)))
301                 vcp->execsOrWriters--;
302
303             vcp->states &= ~CMAPPED;
304             crfree(credp);
305         }
306     }
307     else {
308         ReleaseWriteLock(&vcp->lock);
309     }
310
311  unlock_exit:
312     AFS_GUNLOCK();
313 }
314
315 static int afs_linux_mmap(struct file *fp, struct vm_area_struct *vmap)
316 {
317     struct vcache *vcp = (struct vcache*)FILE_INODE(fp);
318     cred_t *credp = crref();
319     struct vrequest treq;
320     int code;
321
322     AFS_GLOCK();
323 #if defined(AFS_LINUX24_ENV)
324     afs_Trace3(afs_iclSetp, CM_TRACE_GMAP, ICL_TYPE_POINTER, vcp,
325                ICL_TYPE_POINTER, vmap->vm_start,
326                ICL_TYPE_INT32, vmap->vm_end - vmap->vm_start);
327 #else
328     afs_Trace4(afs_iclSetp, CM_TRACE_GMAP, ICL_TYPE_POINTER, vcp,
329                ICL_TYPE_POINTER, vmap->vm_start,
330                ICL_TYPE_INT32, vmap->vm_end - vmap->vm_start,
331                ICL_TYPE_INT32, vmap->vm_offset);
332 #endif
333
334     /* get a validated vcache entry */
335     code = afs_InitReq(&treq, credp);
336     if (!code)
337         code = afs_VerifyVCache(vcp, &treq);
338
339
340     if (code)
341         code = -code;
342     else {
343         osi_FlushPages(vcp, credp);     /* ensure stale pages are gone */
344
345         AFS_GUNLOCK();
346         code = generic_file_mmap(fp, vmap);
347         AFS_GLOCK();
348     }
349
350     if (code == 0) {
351         ObtainWriteLock(&vcp->lock,531);
352         /* Set out vma ops so we catch the close. The following test should be
353          * the same as used in generic_file_mmap.
354          */
355         if ((vmap->vm_flags & VM_SHARED) && (vmap->vm_flags & VM_MAYWRITE)) {
356             if (!afs_shared_mmap_ops_inited) {
357                 afs_shared_mmap_ops_inited = 1;
358                 afs_shared_mmap_ops = *vmap->vm_ops;
359                 afs_shared_mmap_ops.close = afs_linux_vma_close;
360             }
361             vmap->vm_ops = &afs_shared_mmap_ops;
362         }
363         else {
364             if (!afs_private_mmap_ops_inited) {
365                 afs_private_mmap_ops_inited = 1;
366                 afs_private_mmap_ops = *vmap->vm_ops;
367                 afs_private_mmap_ops.close = afs_linux_vma_close;
368             }
369             vmap->vm_ops = &afs_private_mmap_ops;
370         }
371     
372     
373         /* Add an open reference on the first mapping. */
374         if (vcp->mapcnt == 0) {
375             vcp->execsOrWriters++;
376             vcp->opens++;
377             vcp->states |= CMAPPED;
378         }
379         ReleaseWriteLock(&vcp->lock);
380         vcp->mapcnt++;
381     }
382
383     AFS_GUNLOCK();
384     crfree(credp);
385     return code;
386 }
387
388 int afs_linux_open(struct inode *ip, struct file *fp)
389 {
390     int code;
391     cred_t *credp = crref();
392
393     AFS_GLOCK();
394 #ifdef AFS_LINUX24_ENV
395     lock_kernel();
396 #endif
397     code = afs_open((struct vcache**)&ip, fp->f_flags, credp);
398 #ifdef AFS_LINUX24_ENV
399     unlock_kernel();
400 #endif
401     AFS_GUNLOCK();
402
403     crfree(credp);
404     return -code;
405 }
406
407 /* afs_Close is called from release, since release is used to handle all
408  * file closings. In addition afs_linux_flush is called from sys_close to
409  * handle flushing the data back to the server. The kicker is that we could
410  * ignore flush completely if only sys_close took it's return value from
411  * fput. See afs_linux_flush for notes on interactions between release and
412  * flush.
413  */
414 static int afs_linux_release(struct inode *ip, struct file *fp)
415 {
416     int code = 0;
417     cred_t *credp = crref();
418     struct vcache *vcp = (struct vcache*)ip;
419
420     AFS_GLOCK();
421 #ifdef AFS_LINUX24_ENV
422     lock_kernel();
423 #endif
424     if (vcp->flushcnt) {
425         vcp->flushcnt--; /* protected by AFS global lock. */
426     }
427     else {
428         code = afs_close(vcp, fp->f_flags, credp);
429     }
430 #ifdef AFS_LINUX24_ENV
431     unlock_kernel();
432 #endif
433     AFS_GUNLOCK();
434
435     crfree(credp);
436     return -code;
437 }
438
439 #if defined(AFS_LINUX24_ENV)
440 static int afs_linux_fsync(struct file *fp, struct dentry *dp, int datasync)
441 #else
442 static int afs_linux_fsync(struct file *fp, struct dentry *dp)
443 #endif
444 {
445     int code;
446     struct inode *ip = FILE_INODE(fp);
447     cred_t *credp = crref();
448
449     AFS_GLOCK();
450 #ifdef AFS_LINUX24_ENV
451     lock_kernel();
452 #endif
453     code = afs_fsync((struct vcache*)ip, credp);
454 #ifdef AFS_LINUX24_ENV
455     unlock_kernel();
456 #endif
457     AFS_GUNLOCK();
458     crfree(credp);
459     return -code;
460     
461 }
462
463 #ifdef NOTUSED
464 /* No support for async i/o */
465 int afs_linux_fasync(struct inode *ip, struct file *fp, int);
466
467 /* I don't think it will, at least not as can be detected here. */
468 int afs_linux_check_media_change(kdev_t dev);
469
470 /* Revalidate media and file system. */
471 int afs_linux_file_revalidate(kdev_t dev);
472 #endif /* NOTUSED */
473
474 static int afs_linux_lock(struct file *fp, int cmd, struct file_lock *flp)
475 {
476     int code = 0;
477     struct vcache *vcp = (struct vcache*)FILE_INODE(fp);
478     cred_t *credp = crref();
479     struct flock flock;
480     
481     /* Convert to a lock format afs_lockctl understands. */
482     memset((char*)&flock, 0, sizeof(flock));
483     flock.l_type = flp->fl_type;
484     flock.l_pid = flp->fl_pid;
485     flock.l_whence = 0;
486     flock.l_start = flp->fl_start;
487     flock.l_len = flp->fl_end - flp->fl_start;
488
489     AFS_GLOCK();
490     code = afs_lockctl(vcp, &flock, cmd, credp);
491     AFS_GUNLOCK();
492     crfree(credp);
493     return -code;
494     
495 }
496
497 /* afs_linux_flush
498  * flush is called from sys_close. We could ignore it, but sys_close return
499  * code comes from flush, not release. We need to use release to keep
500  * the vcache open count correct. Note that flush is called before release
501  * (via fput) in sys_close. vcp->flushcnt is a bit of ugliness to avoid
502  * races and also avoid calling afs_close twice when closing the file.
503  * If we merely checked for opens > 0 in afs_linux_release, then if an
504  * new open occurred when storing back the file, afs_linux_release would
505  * incorrectly close the file and decrement the opens count. Calling afs_close
506  * on the just flushed file is wasteful, since the background daemon will
507  * execute the code that finally decides there is nothing to do.
508  */
509 int afs_linux_flush(struct file *fp)
510 {
511     struct vcache *vcp = (struct vcache *)FILE_INODE(fp);
512     int code = 0;
513     cred_t *credp;
514
515     /* Only do this on the last close of the file pointer. */
516 #if defined(AFS_LINUX24_ENV)
517     if (atomic_read(&fp->f_count) > 1)
518 #else
519     if (fp->f_count > 1)
520 #endif
521         return 0;
522
523     credp = crref();
524
525     AFS_GLOCK();
526     code = afs_close(vcp, fp->f_flags, credp);
527     vcp->flushcnt++; /* protected by AFS global lock. */
528     AFS_GUNLOCK();
529
530     crfree(credp);
531     return -code;
532 }
533
534 /* Not allowed to directly read a directory. */
535 ssize_t afs_linux_dir_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
536 {
537     return -EISDIR;
538 }
539
540
541
542 #if defined(AFS_LINUX24_ENV)
543 struct file_operations afs_dir_fops = {
544     read:      generic_read_dir,
545     readdir:   afs_linux_readdir,
546     ioctl:     afs_xioctl,
547     open:      afs_linux_open,
548     release:   afs_linux_release,
549 };
550 #else
551 struct file_operations afs_dir_fops = {
552     NULL,               /* afs_linux_lseek */
553     afs_linux_dir_read,
554     NULL,               /* afs_linux_write */
555     afs_linux_readdir,
556     NULL,               /* afs_linux_select */
557     afs_xioctl,         /* close enough to use the ported AFS one */
558     NULL,               /* afs_linux_mmap */
559     afs_linux_open,
560     NULL,               /* afs_linux_flush */
561     afs_linux_release,
562     afs_linux_fsync,
563     NULL,               /* afs_linux_fasync */
564     NULL,               /* afs_linux_check_media_change */
565     NULL,               /* afs_linux_file_revalidate */
566     afs_linux_lock,
567 };
568 #endif
569
570 #if defined(AFS_LINUX24_ENV)
571 struct file_operations afs_file_fops = {
572     read:      afs_linux_read,
573     write:     afs_linux_write,
574     ioctl:     afs_xioctl,
575     mmap:      afs_linux_mmap,
576     open:      afs_linux_open,
577     flush:     afs_linux_flush,
578     release:   afs_linux_release,
579     fsync:     afs_linux_fsync,
580     lock:      afs_linux_lock,
581 };
582 #else
583 struct file_operations afs_file_fops = {
584     NULL,               /* afs_linux_lseek */
585     afs_linux_read,
586     afs_linux_write,
587     NULL,               /* afs_linux_readdir */
588     NULL,               /* afs_linux_select */
589     afs_xioctl,         /* close enough to use the ported AFS one */
590     afs_linux_mmap,
591     afs_linux_open,
592     afs_linux_flush,
593     afs_linux_release,
594     afs_linux_fsync,
595     NULL,               /* afs_linux_fasync */
596     NULL,               /* afs_linux_check_media_change */
597     NULL,               /* afs_linux_file_revalidate */
598     afs_linux_lock,
599 };
600 #endif
601    
602
603 /**********************************************************************
604  * AFS Linux dentry operations
605  **********************************************************************/
606
607 /* afs_linux_revalidate
608  * Ensure vcache is stat'd before use. Return 0 if entry is valid.
609  */
610 static int afs_linux_revalidate(struct dentry *dp)
611 {
612     int code;
613     cred_t *credp;
614     struct vrequest treq;
615     struct vcache *vcp = (struct vcache*)dp->d_inode;
616
617     AFS_GLOCK();
618 #ifdef AFS_LINUX24_ENV
619     lock_kernel();
620 #endif
621
622     /* If it's a negative dentry, then there's nothing to do. */
623     if (!vcp) {
624 #ifdef AFS_LINUX24_ENV
625         unlock_kernel();
626 #endif
627         AFS_GUNLOCK();
628         return 0;
629     }
630
631     /* Make this a fast path (no crref), since it's called so often. */
632     if (vcp->states & CStatd) {
633         if (*dp->d_name.name != '/' && vcp->mvstat == 2) /* root vnode */
634             check_bad_parent(dp); /* check and correct mvid */
635         vcache2inode(vcp);
636 #ifdef AFS_LINUX24_ENV
637         unlock_kernel();
638 #endif
639         AFS_GUNLOCK();
640         return 0;
641     }
642
643     credp = crref();
644     code = afs_InitReq(&treq, credp);
645     if (!code)
646         code = afs_VerifyVCache(vcp, &treq);
647
648 #ifdef AFS_LINUX24_ENV
649     unlock_kernel();
650 #endif
651     AFS_GUNLOCK();
652     crfree(credp);
653
654     return -code ;
655 }
656
657 /* Validate a dentry. Return 0 if unchanged, 1 if VFS layer should re-evaluate.
658  * In kernels 2.2.10 and above, we are passed an additional flags var which
659  * may have either the LOOKUP_FOLLOW OR LOOKUP_DIRECTORY set in which case
660  * we are advised to follow the entry if it is a link or to make sure that 
661  * it is a directory. But since the kernel itself checks these possibilities
662  * later on, we shouldn't have to do it until later. Perhaps in the future..
663  */
664 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
665 static int afs_linux_dentry_revalidate(struct dentry *dp, int flags)
666 #else
667 static int afs_linux_dentry_revalidate(struct dentry *dp)
668 #endif
669 {
670     int code;
671     cred_t *credp;
672     struct vrequest treq;
673     struct vcache *vcp = (struct vcache*)dp->d_inode;
674
675     AFS_GLOCK();
676 #ifdef AFS_LINUX24_ENV
677     lock_kernel();
678 #endif
679
680     /* If it's a negative dentry, then there's nothing to do. */
681     if (!vcp) {
682 #ifdef AFS_LINUX24_ENV
683         unlock_kernel();
684 #endif
685         AFS_GUNLOCK();
686         return 0;
687     }
688
689     /* Make this a fast path (no crref), since it's called so often. */
690     if (vcp->states & CStatd) {
691         if (*dp->d_name.name != '/' && vcp->mvstat == 2) /* root vnode */
692             check_bad_parent(dp); /* check and correct mvid */
693         vcache2inode(vcp);
694 #ifdef AFS_LINUX24_ENV
695         unlock_kernel();
696 #endif
697         AFS_GUNLOCK();
698         return 0;
699     }
700
701     credp = crref();
702     code = afs_InitReq(&treq, credp);
703     if (!code)
704         code = afs_VerifyVCache(vcp, &treq);
705
706 #ifdef AFS_LINUX24_ENV
707     unlock_kernel();
708 #endif
709     AFS_GUNLOCK();
710     crfree(credp);
711
712     return 1;
713 }
714
715 /* afs_dentry_iput */
716 static void afs_dentry_iput(struct dentry *dp, struct inode *ip)
717 {
718     osi_iput(ip);
719 }
720
721 #if defined(AFS_LINUX24_ENV)
722 struct dentry_operations afs_dentry_operations = {
723        d_revalidate:   afs_linux_dentry_revalidate,
724        d_iput:         afs_dentry_iput,
725 };
726 struct dentry_operations *afs_dops = &afs_dentry_operations;
727 #else
728 struct dentry_operations afs_dentry_operations = {
729         afs_linux_dentry_revalidate,    /* d_validate(struct dentry *) */
730         NULL,                   /* d_hash */
731         NULL,                   /* d_compare */
732         NULL,                   /* d_delete(struct dentry *) */
733         NULL,                   /* d_release(struct dentry *) */
734         afs_dentry_iput         /* d_iput(struct dentry *, struct inode *) */
735 };
736 struct dentry_operations *afs_dops = &afs_dentry_operations;
737 #endif
738
739 /**********************************************************************
740  * AFS Linux inode operations
741  **********************************************************************/
742
743 /* afs_linux_create
744  *
745  * Merely need to set enough of vattr to get us through the create. Note
746  * that the higher level code (open_namei) will take care of any tuncation
747  * explicitly. Exclusive open is also taken care of in open_namei.
748  *
749  * name is in kernel space at this point.
750  */
751 int afs_linux_create(struct inode *dip, struct dentry *dp, int mode)
752 {
753     int code;
754     cred_t *credp = crref();
755     struct vattr vattr;
756     enum vcexcl excl;
757     const char *name = dp->d_name.name;
758     struct inode *ip;
759
760     VATTR_NULL(&vattr);
761     vattr.va_mode = mode;
762
763     AFS_GLOCK();
764     code = afs_create((struct vcache*)dip, name, &vattr, NONEXCL, mode,
765                       (struct vcache**)&ip, credp);
766
767     if (!code) {
768         vattr2inode(ip, &vattr);
769         /* Reset ops if symlink or directory. */
770 #if defined(AFS_LINUX24_ENV)
771        if (S_ISREG(ip->i_mode)) {
772            ip->i_op = &afs_file_iops;
773            ip->i_fop = &afs_file_fops;
774            ip->i_data.a_ops = &afs_file_aops;
775         } else if (S_ISDIR(ip->i_mode)) {
776            ip->i_op = &afs_dir_iops;
777            ip->i_fop = &afs_dir_fops;
778         } else if (S_ISLNK(ip->i_mode)) {
779            ip->i_op = &afs_symlink_iops;
780            ip->i_data.a_ops = &afs_symlink_aops;
781            ip->i_mapping = &ip->i_data;
782         } else
783            printk("afs_linux_create: FIXME\n");
784 #else
785         if (S_ISDIR(ip->i_mode))
786             ip->i_op = &afs_dir_iops;
787         else if (S_ISLNK(ip->i_mode))
788             ip->i_op = &afs_symlink_iops;
789 #endif
790
791         dp->d_op = afs_dops;
792         d_instantiate(dp, ip);
793     }
794
795     AFS_GUNLOCK();
796     crfree(credp);
797     return -code;
798 }
799
800 /* afs_linux_lookup */
801 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
802 struct dentry *afs_linux_lookup(struct inode *dip, struct dentry *dp)
803 #else
804 int afs_linux_lookup(struct inode *dip, struct dentry *dp)
805 #endif
806 {
807     int code = 0;
808     cred_t *credp = crref();
809     struct vcache *vcp=NULL;
810     const char *comp = dp->d_name.name;
811     AFS_GLOCK();
812     code = afs_lookup((struct vcache *)dip, comp, &vcp, credp);
813
814     if (vcp) {
815         struct inode *ip = (struct inode*)vcp;
816         /* Reset ops if symlink or directory. */
817 #if defined(AFS_LINUX24_ENV)
818        if (S_ISREG(ip->i_mode)) {
819            ip->i_op = &afs_file_iops;
820            ip->i_fop = &afs_file_fops;
821            ip->i_data.a_ops = &afs_file_aops;
822         } else if (S_ISDIR(ip->i_mode)) {
823            ip->i_op = &afs_dir_iops;
824            ip->i_fop = &afs_dir_fops;
825         } else if (S_ISLNK(ip->i_mode)) {
826            ip->i_op = &afs_symlink_iops;
827            ip->i_data.a_ops = &afs_symlink_aops;
828            ip->i_mapping = &ip->i_data;
829         } else
830            printk("afs_linux_lookup: FIXME\n");
831 #else
832         if (S_ISDIR(ip->i_mode))
833             ip->i_op = &afs_dir_iops;
834         else if (S_ISLNK(ip->i_mode))
835             ip->i_op = &afs_symlink_iops;
836 #endif
837     }
838     dp->d_op = afs_dops;
839     d_add(dp, (struct inode*)vcp);
840
841     AFS_GUNLOCK();
842     crfree(credp);
843
844     /* It's ok for the file to not be found. That's noted by the caller by
845      * seeing that the dp->d_inode field is NULL.
846      */
847 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
848     if (code == ENOENT)
849         return ERR_PTR(0);
850     else
851         return ERR_PTR(-code);
852 #else
853     if (code == ENOENT)
854         code = 0;
855     return -code;
856 #endif
857 }
858
859 int afs_linux_link(struct dentry *olddp, struct inode *dip,
860                    struct dentry *newdp)
861 {
862     int code;
863     cred_t *credp = crref();
864     const char *name = newdp->d_name.name;
865     struct inode *oldip = olddp->d_inode;
866
867     /* If afs_link returned the vnode, we could instantiate the
868      * dentry. Since it's not, we drop this one and do a new lookup.
869      */
870     d_drop(newdp);
871
872     AFS_GLOCK();
873     code = afs_link((struct vcache*)oldip, (struct vcache*)dip, name, credp);
874
875     AFS_GUNLOCK();
876     crfree(credp);
877     return -code;
878 }
879
880 int afs_linux_unlink(struct inode *dip, struct dentry *dp)
881 {
882     int code;
883     cred_t *credp = crref();
884     const char *name = dp->d_name.name;
885     int putback = 0;
886
887     if (!list_empty(&dp->d_hash)) {
888         d_drop(dp);
889         /* Install a definite non-existence if we're the only user. */
890 #if defined(AFS_LINUX24_ENV)
891         if (atomic_read(&dp->d_count) == 1)
892 #else
893         if (dp->d_count == 1)
894 #endif
895             putback = 1;
896     }
897
898     AFS_GLOCK();
899     code = afs_remove((struct vcache*)dip, name, credp);
900     AFS_GUNLOCK();
901     if (!code) {
902         d_delete(dp);
903         if (putback)
904             d_add(dp, NULL); /* means definitely does _not_ exist */
905     }
906     crfree(credp);
907     return -code;
908 }
909
910
911 int afs_linux_symlink(struct inode *dip, struct dentry *dp,
912                       const char *target)
913 {
914     int code;
915     cred_t *credp = crref();
916     struct vattr vattr;
917     const char *name = dp->d_name.name;
918
919     /* If afs_symlink returned the vnode, we could instantiate the
920      * dentry. Since it's not, we drop this one and do a new lookup.
921      */
922     d_drop(dp);
923
924     AFS_GLOCK();
925     VATTR_NULL(&vattr);
926     code = afs_symlink((struct vcache*)dip, name, &vattr, target, credp);
927     AFS_GUNLOCK();
928     crfree(credp);
929     return -code;
930 }
931
932 int afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode)
933 {
934     int code;
935     cred_t *credp = crref();
936     struct vcache *tvcp = NULL;
937     struct vattr vattr;
938     const char *name = dp->d_name.name;
939
940     AFS_GLOCK();
941     VATTR_NULL(&vattr);
942     vattr.va_mask = ATTR_MODE;
943     vattr.va_mode = mode;
944     code = afs_mkdir((struct vcache*)dip, name, &vattr, &tvcp, credp);
945
946     if (tvcp) {
947         tvcp->v.v_op = &afs_dir_iops;
948 #if defined(AFS_LINUX24_ENV)
949         tvcp->v.v_fop = &afs_dir_fops;
950 #endif
951         dp->d_op = afs_dops;
952         d_instantiate(dp, (struct inode*)tvcp);
953     }
954     AFS_GUNLOCK();
955     crfree(credp);
956     return -code;
957 }
958
959 int afs_linux_rmdir(struct inode *dip, struct dentry *dp)
960 {
961     int code;
962     cred_t *credp = crref();
963     const char *name = dp->d_name.name;
964
965     AFS_GLOCK();
966     code = afs_rmdir((struct vcache*)dip, name, credp);
967
968     /* Linux likes to see ENOTDIR returned from an rmdir() syscall
969      * that failed because a directory is not empty. So, we map
970      * EEXIST to ENOTDIR on linux.
971      */
972     if (code == EEXIST) {
973         code = ENOTDIR;
974     }
975     
976     if (!code) {
977         d_delete(dp);
978     }
979
980     AFS_GUNLOCK();
981     crfree(credp);
982     return -code;
983 }
984
985
986
987 int afs_linux_rename(struct inode *oldip, struct dentry *olddp,
988                      struct inode *newip, struct dentry *newdp)
989 {
990     int code;
991     cred_t *credp = crref();
992     const char *oldname = olddp->d_name.name;
993     const char *newname = newdp->d_name.name;
994
995     /* Remove old and new entries from name hash. New one will change below.
996      * While it's optimal to catch failures and re-insert newdp into hash,
997      * it's also error prone and in that case we're already dealing with error
998      * cases. Let another lookup put things right, if need be.
999      */
1000     if (!list_empty(&olddp->d_hash)) {
1001         d_drop(olddp);
1002     }
1003     if (!list_empty(&newdp->d_hash)) {
1004         d_drop(newdp);
1005     }
1006     AFS_GLOCK();
1007     code = afs_rename((struct vcache*)oldip, oldname, (struct vcache*)newip,
1008                       newname, credp);
1009     AFS_GUNLOCK();
1010
1011     if (!code)
1012         d_move(olddp, newdp);
1013
1014     crfree(credp);
1015     return -code;
1016 }
1017
1018
1019 /* afs_linux_ireadlink 
1020  * Internal readlink which can return link contents to user or kernel space.
1021  * Note that the buffer is NOT supposed to be null-terminated.
1022  */
1023 static int afs_linux_ireadlink(struct inode *ip, char *target, int maxlen,
1024                         uio_seg_t seg)
1025 {
1026     int code;
1027     cred_t *credp = crref();
1028     uio_t tuio;
1029     struct iovec iov;
1030
1031     setup_uio(&tuio, &iov, target, 0, maxlen, UIO_READ, seg);
1032     code = afs_readlink((struct vcache*)ip, &tuio, credp);
1033     crfree(credp);
1034
1035     if (!code)
1036         return maxlen - tuio.uio_resid;
1037     else
1038         return -code;
1039 }
1040
1041 #if !defined(AFS_LINUX24_ENV)
1042 /* afs_linux_readlink 
1043  * Fill target (which is in user space) with contents of symlink.
1044  */
1045 int afs_linux_readlink(struct dentry *dp, char *target, int maxlen)
1046 {
1047     int code;
1048     struct inode *ip = dp->d_inode;
1049
1050     AFS_GLOCK();
1051     code = afs_linux_ireadlink(ip, target, maxlen, AFS_UIOUSER);
1052     AFS_GUNLOCK();
1053     return code;
1054 }
1055
1056
1057 /* afs_linux_follow_link
1058  * a file system dependent link following routine.
1059  */
1060 struct dentry * afs_linux_follow_link(struct dentry *dp,
1061                                       struct dentry *basep,
1062                                       unsigned int follow)
1063 {
1064     int code = 0;
1065     char *name;
1066     struct dentry *res;
1067
1068     AFS_GLOCK();
1069     name = osi_Alloc(PATH_MAX+1);
1070     if (!name) {
1071         AFS_GUNLOCK();
1072         dput(basep);
1073         return ERR_PTR(-EIO);
1074     }
1075
1076     code = afs_linux_ireadlink(dp->d_inode, name, PATH_MAX, AFS_UIOSYS);
1077     AFS_GUNLOCK();
1078
1079     if (code<0) {
1080         dput(basep);
1081         res = ERR_PTR(code);
1082     }
1083     else {
1084         name[code] = '\0';
1085         res = lookup_dentry(name, basep, follow);
1086     }
1087
1088     AFS_GLOCK();
1089     osi_Free(name, PATH_MAX+1);
1090     AFS_GUNLOCK();
1091     return res;
1092 }
1093 #endif
1094
1095 /* afs_linux_readpage
1096  * all reads come through here. A strategy-like read call.
1097  */
1098 int afs_linux_readpage(struct file *fp, struct page *pp)
1099 {
1100     int code;
1101     cred_t *credp = crref();
1102     ulong address = afs_linux_page_address(pp);
1103     uio_t tuio;
1104     struct iovec iovec;
1105     struct inode *ip = FILE_INODE(fp);
1106     int cnt = atomic_read(&pp->count);
1107
1108     AFS_GLOCK();
1109     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE,
1110                ICL_TYPE_POINTER, ip,
1111                ICL_TYPE_POINTER, pp,
1112                ICL_TYPE_INT32, cnt,
1113                ICL_TYPE_INT32, 99999); /* not a possible code value */
1114     atomic_add(1, &pp->count);
1115 #if defined(AFS_LINUX24_ENV)
1116     ClearPageError(pp);
1117 #else
1118     set_bit(PG_locked, &pp->flags); /* other bits? See mm.h */
1119     clear_bit(PG_error, &pp->flags);
1120 #endif
1121
1122 #if defined(AFS_LINUX24_ENV)
1123     setup_uio(&tuio, &iovec, (char*)address, pp->index << PAGE_CACHE_SHIFT,
1124               PAGESIZE, UIO_READ, AFS_UIOSYS);
1125 #else
1126     setup_uio(&tuio, &iovec, (char*)address, pageoff(pp), PAGESIZE,
1127               UIO_READ, AFS_UIOSYS);
1128 #endif
1129 #if defined(AFS_LINUX24_ENV)
1130     lock_kernel();
1131 #endif
1132     code = afs_rdwr((struct vcache*)ip, &tuio, UIO_READ, 0, credp);
1133 #if defined(AFS_LINUX24_ENV)
1134     unlock_kernel();
1135 #endif
1136
1137     if (!code) {
1138         if (tuio.uio_resid) /* zero remainder of page */
1139             memset((void*)(address+(PAGESIZE-tuio.uio_resid)), 0,
1140                    tuio.uio_resid);
1141 #if defined(AFS_LINUX24_ENV)
1142 #ifndef __powerpc__
1143         flush_dcache_page(pp);
1144 #endif
1145         SetPageUptodate(pp);
1146 #else
1147         set_bit(PG_uptodate, &pp->flags);
1148 #endif
1149     }
1150
1151 #if defined(AFS_LINUX24_ENV)
1152     UnlockPage(pp);
1153 #else
1154     clear_bit(PG_locked, &pp->flags);
1155     wake_up(&pp->wait);
1156 #endif
1157     free_page(address);
1158
1159     crfree(credp);
1160     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE,
1161                ICL_TYPE_POINTER, ip,
1162                ICL_TYPE_POINTER, pp,
1163                ICL_TYPE_INT32, cnt,
1164                ICL_TYPE_INT32, code);
1165     AFS_GUNLOCK();
1166     return -code;
1167 }
1168
1169 #if defined(AFS_LINUX24_ENV)
1170 int afs_linux_writepage(struct page *pp)
1171 {
1172     struct address_space *mapping = pp->mapping;
1173     struct inode *inode;
1174     unsigned long end_index;
1175     unsigned offset = PAGE_CACHE_SIZE;
1176     long status;
1177  
1178     inode = (struct inode *) mapping->host;
1179     end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1180
1181     /* easy case */
1182     if (pp->index < end_index)
1183         goto do_it;
1184     /* things got complicated... */
1185     offset = inode->i_size & (PAGE_CACHE_SIZE-1);
1186     /* OK, are we completely out? */
1187     if (pp->index >= end_index+1 || !offset)
1188         return -EIO;
1189 do_it:
1190     AFS_GLOCK();
1191     status = afs_linux_writepage_sync(inode, pp, 0, offset);
1192     AFS_GUNLOCK();
1193     SetPageUptodate(pp);
1194     UnlockPage(pp);
1195     /* kunmap(pp); */
1196     if (status == offset)
1197         return 0;
1198     else
1199         return status;
1200 }
1201 #endif
1202
1203 #ifdef NOTUSED
1204 /* afs_linux_bmap - supports generic_readpage, but we roll our own. */
1205 int afs_linux_bmap(struct inode *ip, int) { return -EINVAL; }
1206
1207 /* afs_linux_truncate
1208  * Handles discarding disk blocks if this were a device. ext2 indicates we
1209  * may need to zero partial last pages of memory mapped files.
1210  */
1211 void afs_linux_truncate(struct inode *ip)
1212 {
1213 }
1214 #endif
1215
1216 /* afs_linux_permission
1217  * Check access rights - returns error if can't check or permission denied.
1218  */
1219 int afs_linux_permission(struct inode *ip, int mode)
1220 {
1221     int code;
1222     cred_t *credp = crref();
1223     int tmp = 0;
1224
1225     AFS_GLOCK();
1226     if (mode & MAY_EXEC) tmp |= VEXEC;
1227     if (mode & MAY_READ) tmp |= VREAD;
1228     if (mode & MAY_WRITE) tmp |= VWRITE;
1229     code = afs_access((struct vcache*)ip, tmp, credp);
1230
1231     AFS_GUNLOCK();
1232     crfree(credp);
1233     return -code;
1234 }
1235
1236
1237 #ifdef NOTUSED
1238 /* msdos sector mapping hack for memory mapping. */
1239 int afs_linux_smap(struct inode *ip, int) { return -EINVAL; }
1240 #endif
1241
1242 #if defined(AFS_LINUX24_ENV)
1243 int afs_linux_writepage_sync(struct inode *ip, struct page *pp,
1244                         unsigned long offset,
1245                         unsigned int count)
1246 {
1247     struct vcache *vcp = (struct vcache *) ip;
1248     u8 *page_addr = (u8*) afs_linux_page_address(pp);
1249     int code = 0;
1250     cred_t *credp;
1251     uio_t tuio;
1252     struct iovec iovec;
1253     int f_flags = 0;
1254
1255     credp = crref();
1256     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1257               ICL_TYPE_POINTER, pp,
1258               ICL_TYPE_INT32, atomic_read(&pp->count),
1259               ICL_TYPE_INT32, 99999);
1260     setup_uio(&tuio, &iovec, page_addr + offset,
1261              (pp->index << PAGE_CACHE_SHIFT) + offset, count,
1262              UIO_WRITE, AFS_UIOSYS);
1263
1264     code = afs_write(vcp, &tuio, f_flags, credp, 0);
1265
1266     vcache2inode(vcp);
1267
1268     code = code ? -code : count - tuio.uio_resid;
1269     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1270               ICL_TYPE_POINTER, pp,
1271               ICL_TYPE_INT32, atomic_read(&pp->count),
1272               ICL_TYPE_INT32, code);
1273
1274     crfree(credp);
1275
1276     return code;
1277 }
1278
1279 static int
1280 afs_linux_updatepage(struct file *file, struct page *page, 
1281                      unsigned long offset, unsigned int count)
1282 {
1283     struct dentry *dentry = file->f_dentry;
1284
1285     return afs_linux_writepage_sync(dentry->d_inode, page, offset, count);
1286 }
1287 #else
1288 /* afs_linux_updatepage
1289  * What one would have thought was writepage - write dirty page to file.
1290  * Called from generic_file_write. buffer is still in user space. pagep
1291  * has been filled in with old data if we're updating less than a page.
1292  */
1293 int afs_linux_updatepage(struct file *fp, struct page *pp,
1294                          unsigned long offset,
1295                          unsigned int count, int sync)
1296 {
1297     struct vcache *vcp = (struct vcache *)FILE_INODE(fp);
1298     u8 *page_addr = (u8*) afs_linux_page_address(pp);
1299     int code = 0;
1300     cred_t *credp;
1301     uio_t tuio;
1302     struct iovec iovec;
1303     
1304     set_bit(PG_locked, &pp->flags);
1305
1306     credp = crref();
1307     AFS_GLOCK();
1308     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1309                ICL_TYPE_POINTER, pp,
1310                ICL_TYPE_INT32, atomic_read(&pp->count),
1311                ICL_TYPE_INT32, 99999);
1312     setup_uio(&tuio, &iovec, page_addr + offset, pageoff(pp) + offset, count,
1313               UIO_WRITE, AFS_UIOSYS);
1314
1315     code = afs_write(vcp, &tuio, fp->f_flags, credp, 0);
1316
1317     vcache2inode(vcp);
1318
1319     code = code ? -code : count - tuio.uio_resid;
1320     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1321                ICL_TYPE_POINTER, pp,
1322                ICL_TYPE_INT32, atomic_read(&pp->count),
1323                ICL_TYPE_INT32, code);
1324
1325     AFS_GUNLOCK();
1326     crfree(credp);
1327
1328     clear_bit(PG_locked, &pp->flags);
1329     return code;
1330 }
1331 #endif
1332
1333 #if defined(AFS_LINUX24_ENV)
1334 static int afs_linux_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
1335 {
1336     long status;
1337
1338     AFS_GLOCK();
1339     lock_kernel();
1340     status = afs_linux_updatepage(file, page, offset, to-offset);
1341     unlock_kernel();
1342     AFS_GUNLOCK();
1343     kunmap(page);
1344
1345     return status;
1346 }
1347
1348 static int afs_linux_prepare_write(struct file *file, struct page *page,
1349                                    unsigned from, unsigned to)
1350 {
1351     kmap(page);
1352     return 0;
1353 }
1354
1355 extern int afs_notify_change(struct dentry *dp, struct iattr* iattrp);
1356 #endif
1357
1358 #if defined(AFS_LINUX24_ENV)
1359 struct inode_operations afs_file_iops = {
1360     revalidate:                afs_linux_revalidate,
1361     setattr:           afs_notify_change,
1362     permission:                afs_linux_permission,
1363 };
1364 struct address_space_operations afs_file_aops = {
1365         readpage: afs_linux_readpage,
1366         writepage: afs_linux_writepage,
1367         commit_write: afs_linux_commit_write,
1368         prepare_write: afs_linux_prepare_write,
1369 };
1370
1371 struct inode_operations *afs_ops = &afs_file_iops;
1372 #else
1373 struct inode_operations afs_iops = {
1374     &afs_file_fops,     /* file operations */
1375     NULL,               /* afs_linux_create */
1376     NULL,               /* afs_linux_lookup */
1377     NULL,               /* afs_linux_link */
1378     NULL,               /* afs_linux_unlink */
1379     NULL,               /* afs_linux_symlink */
1380     NULL,               /* afs_linux_mkdir */
1381     NULL,               /* afs_linux_rmdir */
1382     NULL,               /* afs_linux_mknod */
1383     NULL,               /* afs_linux_rename */
1384     NULL,               /* afs_linux_readlink */
1385     NULL,               /* afs_linux_follow_link */
1386     afs_linux_readpage,
1387     NULL,               /* afs_linux_writepage */
1388     NULL,               /* afs_linux_bmap */
1389     NULL,               /* afs_linux_truncate */
1390     afs_linux_permission,
1391     NULL,               /* afs_linux_smap */
1392     afs_linux_updatepage,
1393     afs_linux_revalidate,
1394 };
1395
1396 struct inode_operations *afs_ops = &afs_iops;
1397 #endif
1398
1399 /* Separate ops vector for directories. Linux 2.2 tests type of inode
1400  * by what sort of operation is allowed.....
1401  */
1402 #if defined(AFS_LINUX24_ENV)
1403 struct inode_operations afs_dir_iops = {
1404     create:    afs_linux_create,
1405     lookup:    afs_linux_lookup,
1406     link:      afs_linux_link,
1407     unlink:    afs_linux_unlink,
1408     symlink:   afs_linux_symlink,
1409     mkdir:     afs_linux_mkdir,
1410     rmdir:     afs_linux_rmdir,
1411     rename:    afs_linux_rename,
1412     revalidate:        afs_linux_revalidate,
1413     setattr:   afs_notify_change,
1414     permission:        afs_linux_permission,
1415 };
1416 #else
1417 struct inode_operations afs_dir_iops = {
1418     &afs_dir_fops,      /* file operations for directories */
1419     afs_linux_create,
1420     afs_linux_lookup,
1421     afs_linux_link,
1422     afs_linux_unlink,
1423     afs_linux_symlink,
1424     afs_linux_mkdir,
1425     afs_linux_rmdir,
1426     NULL,               /* afs_linux_mknod */
1427     afs_linux_rename,
1428     NULL,               /* afs_linux_readlink */
1429     NULL,               /* afs_linux_follow_link */
1430     NULL,               /* afs_linux_readpage */
1431     NULL,               /* afs_linux_writepage */
1432     NULL,               /* afs_linux_bmap */
1433     NULL,               /* afs_linux_truncate */
1434     afs_linux_permission,
1435     NULL,               /* afs_linux_smap */
1436     NULL,               /* afs_linux_updatepage */
1437     afs_linux_revalidate,
1438 };
1439 #endif
1440
1441 /* We really need a separate symlink set of ops, since do_follow_link()
1442  * determines if it _is_ a link by checking if the follow_link op is set.
1443  */
1444 #if defined(AFS_LINUX24_ENV)
1445 static int afs_symlink_filler(struct file *file, struct page *page)
1446 {
1447     struct inode *ip = (struct inode *) page->mapping->host;
1448     char *p = (char *)kmap(page);
1449     int code;
1450
1451     AFS_GLOCK();
1452     lock_kernel();
1453     code = afs_linux_ireadlink(ip, p, PAGE_SIZE, AFS_UIOSYS);
1454     unlock_kernel();
1455     AFS_GUNLOCK();
1456
1457     if (code<0)
1458            goto fail;
1459     p[code] = '\0';            /* null terminate? */
1460     SetPageUptodate(page);
1461     kunmap(page);
1462     UnlockPage(page);
1463     return 0;
1464
1465 fail:
1466     SetPageError(page);
1467     kunmap(page);
1468     UnlockPage(page);
1469     return code;
1470 }
1471
1472 struct address_space_operations afs_symlink_aops = {
1473        readpage:       afs_symlink_filler
1474 };
1475
1476 struct inode_operations afs_symlink_iops = {
1477     readlink:          page_readlink,
1478     follow_link:       page_follow_link,
1479     setattr:           afs_notify_change,
1480 };
1481 #else
1482 struct inode_operations afs_symlink_iops = {
1483     NULL,               /* file operations */
1484     NULL,               /* create */
1485     NULL,               /* lookup */
1486     NULL,               /* link */
1487     NULL,               /* unlink */
1488     NULL,               /* symlink */
1489     NULL,               /* mkdir */
1490     NULL,               /* rmdir */
1491     NULL,               /* afs_linux_mknod */
1492     NULL,               /* rename */
1493     afs_linux_readlink,
1494     afs_linux_follow_link,
1495     NULL,               /* readpage */
1496     NULL,               /* afs_linux_writepage */
1497     NULL,               /* afs_linux_bmap */
1498     NULL,               /* afs_linux_truncate */
1499     afs_linux_permission, /* tho the code appears to indicate not used? */
1500     NULL,               /* afs_linux_smap */
1501     NULL,               /* updatepage */
1502     afs_linux_revalidate, /* tho the code appears to indicate not used? */
1503 };
1504 #endif