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