support-reiserfs-20010129
[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 #if defined(AFS_LINUX24_ENV)
719     if (atomic_read(&ip->i_count) == 0 || atomic_read(&ip->i_count) & 0xffff0000) {
720 #else
721     if (ip->i_count == 0 || ip->i_count & 0xffff0000) {
722 #endif
723         osi_Panic("Bad refCount %d on inode 0x%x\n",
724 #if defined(AFS_LINUX24_ENV)
725                   atomic_read(&ip->i_count), ip);
726 #else
727                   ip->i_count, ip);
728 #endif
729     }
730 #if defined(AFS_LINUX24_ENV)
731     atomic_dec(&ip->i_count);
732     if (!atomic_read(&ip->i_count)) {
733 #else
734     ip->i_count --;
735     if (!ip->i_count) {
736 #endif
737         afs_delete_inode(ip);
738     }
739 }
740
741 #if defined(AFS_LINUX24_ENV)
742 struct dentry_operations afs_dentry_operations = {
743        d_revalidate:   afs_linux_dentry_revalidate,
744        d_iput:         afs_dentry_iput,
745 };
746 struct dentry_operations *afs_dops = &afs_dentry_operations;
747 #else
748 struct dentry_operations afs_dentry_operations = {
749         afs_linux_dentry_revalidate,    /* d_validate(struct dentry *) */
750         NULL,                   /* d_hash */
751         NULL,                   /* d_compare */
752         NULL,                   /* d_delete(struct dentry *) */
753         NULL,                   /* d_release(struct dentry *) */
754         afs_dentry_iput         /* d_iput(struct dentry *, struct inode *) */
755 };
756 struct dentry_operations *afs_dops = &afs_dentry_operations;
757 #endif
758
759 /**********************************************************************
760  * AFS Linux inode operations
761  **********************************************************************/
762
763 /* afs_linux_create
764  *
765  * Merely need to set enough of vattr to get us through the create. Note
766  * that the higher level code (open_namei) will take care of any tuncation
767  * explicitly. Exclusive open is also taken care of in open_namei.
768  *
769  * name is in kernel space at this point.
770  */
771 int afs_linux_create(struct inode *dip, struct dentry *dp, int mode)
772 {
773     int code;
774     cred_t *credp = crref();
775     struct vattr vattr;
776     enum vcexcl excl;
777     const char *name = dp->d_name.name;
778     struct inode *ip;
779
780     VATTR_NULL(&vattr);
781     vattr.va_mode = mode;
782
783     AFS_GLOCK();
784     code = afs_create((struct vcache*)dip, name, &vattr, NONEXCL, mode,
785                       (struct vcache**)&ip, credp);
786
787     if (!code) {
788         vattr2inode(ip, &vattr);
789         /* Reset ops if symlink or directory. */
790 #if defined(AFS_LINUX24_ENV)
791        if (S_ISREG(ip->i_mode)) {
792            ip->i_op = &afs_file_iops;
793            ip->i_fop = &afs_file_fops;
794            ip->i_data.a_ops = &afs_file_aops;
795         } else if (S_ISDIR(ip->i_mode)) {
796            ip->i_op = &afs_dir_iops;
797            ip->i_fop = &afs_dir_fops;
798         } else if (S_ISLNK(ip->i_mode)) {
799            ip->i_op = &afs_symlink_iops;
800            ip->i_data.a_ops = &afs_symlink_aops;
801            ip->i_mapping = &ip->i_data;
802         } else
803            printk("afs_linux_create: FIXME\n");
804 #else
805         if (S_ISDIR(ip->i_mode))
806             ip->i_op = &afs_dir_iops;
807         else if (S_ISLNK(ip->i_mode))
808             ip->i_op = &afs_symlink_iops;
809 #endif
810
811         dp->d_op = afs_dops;
812         d_instantiate(dp, ip);
813     }
814
815     AFS_GUNLOCK();
816     crfree(credp);
817     return -code;
818 }
819
820 /* afs_linux_lookup */
821 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
822 struct dentry *afs_linux_lookup(struct inode *dip, struct dentry *dp)
823 #else
824 int afs_linux_lookup(struct inode *dip, struct dentry *dp)
825 #endif
826 {
827     int code = 0;
828     cred_t *credp = crref();
829     struct vcache *vcp=NULL;
830     const char *comp = dp->d_name.name;
831     AFS_GLOCK();
832     code = afs_lookup((struct vcache *)dip, comp, &vcp, credp);
833
834     if (vcp) {
835         struct inode *ip = (struct inode*)vcp;
836         /* Reset ops if symlink or directory. */
837 #if defined(AFS_LINUX24_ENV)
838        if (S_ISREG(ip->i_mode)) {
839            ip->i_op = &afs_file_iops;
840            ip->i_fop = &afs_file_fops;
841            ip->i_data.a_ops = &afs_file_aops;
842         } else if (S_ISDIR(ip->i_mode)) {
843            ip->i_op = &afs_dir_iops;
844            ip->i_fop = &afs_dir_fops;
845         } else if (S_ISLNK(ip->i_mode)) {
846            ip->i_op = &afs_symlink_iops;
847            ip->i_data.a_ops = &afs_symlink_aops;
848            ip->i_mapping = &ip->i_data;
849         } else
850            printk("afs_linux_lookup: FIXME\n");
851 #else
852         if (S_ISDIR(ip->i_mode))
853             ip->i_op = &afs_dir_iops;
854         else if (S_ISLNK(ip->i_mode))
855             ip->i_op = &afs_symlink_iops;
856 #endif
857     }
858     dp->d_op = afs_dops;
859     d_add(dp, (struct inode*)vcp);
860
861     AFS_GUNLOCK();
862     crfree(credp);
863
864     /* It's ok for the file to not be found. That's noted by the caller by
865      * seeing that the dp->d_inode field is NULL.
866      */
867 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
868     if (code == ENOENT)
869         return ERR_PTR(0);
870     else
871         return ERR_PTR(-code);
872 #else
873     if (code == ENOENT)
874         code = 0;
875     return -code;
876 #endif
877 }
878
879 int afs_linux_link(struct dentry *olddp, struct inode *dip,
880                    struct dentry *newdp)
881 {
882     int code;
883     cred_t *credp = crref();
884     const char *name = newdp->d_name.name;
885     struct inode *oldip = olddp->d_inode;
886
887     /* If afs_link returned the vnode, we could instantiate the
888      * dentry. Since it's not, we drop this one and do a new lookup.
889      */
890     d_drop(newdp);
891
892     AFS_GLOCK();
893     code = afs_link((struct vcache*)oldip, (struct vcache*)dip, name, credp);
894
895     AFS_GUNLOCK();
896     crfree(credp);
897     return -code;
898 }
899
900 int afs_linux_unlink(struct inode *dip, struct dentry *dp)
901 {
902     int code;
903     cred_t *credp = crref();
904     const char *name = dp->d_name.name;
905     int putback = 0;
906
907     if (!list_empty(&dp->d_hash)) {
908         d_drop(dp);
909         /* Install a definite non-existence if we're the only user. */
910 #if defined(AFS_LINUX24_ENV)
911         if (atomic_read(&dp->d_count) == 1)
912 #else
913         if (dp->d_count == 1)
914 #endif
915             putback = 1;
916     }
917
918     AFS_GLOCK();
919     code = afs_remove((struct vcache*)dip, name, credp);
920     AFS_GUNLOCK();
921     if (!code) {
922         d_delete(dp);
923         if (putback)
924             d_add(dp, NULL); /* means definitely does _not_ exist */
925     }
926     crfree(credp);
927     return -code;
928 }
929
930
931 int afs_linux_symlink(struct inode *dip, struct dentry *dp,
932                       const char *target)
933 {
934     int code;
935     cred_t *credp = crref();
936     struct vattr vattr;
937     const char *name = dp->d_name.name;
938
939     /* If afs_symlink returned the vnode, we could instantiate the
940      * dentry. Since it's not, we drop this one and do a new lookup.
941      */
942     d_drop(dp);
943
944     AFS_GLOCK();
945     VATTR_NULL(&vattr);
946     code = afs_symlink((struct vcache*)dip, name, &vattr, target, credp);
947     AFS_GUNLOCK();
948     crfree(credp);
949     return -code;
950 }
951
952 int afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode)
953 {
954     int code;
955     cred_t *credp = crref();
956     struct vcache *tvcp = NULL;
957     struct vattr vattr;
958     const char *name = dp->d_name.name;
959
960     AFS_GLOCK();
961     VATTR_NULL(&vattr);
962     vattr.va_mask = ATTR_MODE;
963     vattr.va_mode = mode;
964     code = afs_mkdir((struct vcache*)dip, name, &vattr, &tvcp, credp);
965
966     if (tvcp) {
967         tvcp->v.v_op = &afs_dir_iops;
968 #if defined(AFS_LINUX24_ENV)
969         tvcp->v.v_fop = &afs_dir_fops;
970 #endif
971         dp->d_op = afs_dops;
972         d_instantiate(dp, (struct inode*)tvcp);
973     }
974     AFS_GUNLOCK();
975     crfree(credp);
976     return -code;
977 }
978
979 int afs_linux_rmdir(struct inode *dip, struct dentry *dp)
980 {
981     int code;
982     cred_t *credp = crref();
983     const char *name = dp->d_name.name;
984
985     AFS_GLOCK();
986     code = afs_rmdir((struct vcache*)dip, name, credp);
987
988     /* Linux likes to see ENOTDIR returned from an rmdir() syscall
989      * that failed because a directory is not empty. So, we map
990      * EEXIST to ENOTDIR on linux.
991      */
992     if (code == EEXIST) {
993         code = ENOTDIR;
994     }
995     
996     if (!code) {
997         d_delete(dp);
998     }
999
1000     AFS_GUNLOCK();
1001     crfree(credp);
1002     return -code;
1003 }
1004
1005
1006
1007 int afs_linux_rename(struct inode *oldip, struct dentry *olddp,
1008                      struct inode *newip, struct dentry *newdp)
1009 {
1010     int code;
1011     cred_t *credp = crref();
1012     const char *oldname = olddp->d_name.name;
1013     const char *newname = newdp->d_name.name;
1014
1015     /* Remove old and new entries from name hash. New one will change below.
1016      * While it's optimal to catch failures and re-insert newdp into hash,
1017      * it's also error prone and in that case we're already dealing with error
1018      * cases. Let another lookup put things right, if need be.
1019      */
1020     if (!list_empty(&olddp->d_hash)) {
1021         d_drop(olddp);
1022     }
1023     if (!list_empty(&newdp->d_hash)) {
1024         d_drop(newdp);
1025     }
1026     AFS_GLOCK();
1027     code = afs_rename((struct vcache*)oldip, oldname, (struct vcache*)newip,
1028                       newname, credp);
1029     AFS_GUNLOCK();
1030
1031     if (!code)
1032         d_move(olddp, newdp);
1033
1034     crfree(credp);
1035     return -code;
1036 }
1037
1038
1039 /* afs_linux_ireadlink 
1040  * Internal readlink which can return link contents to user or kernel space.
1041  * Note that the buffer is NOT supposed to be null-terminated.
1042  */
1043 static int afs_linux_ireadlink(struct inode *ip, char *target, int maxlen,
1044                         uio_seg_t seg)
1045 {
1046     int code;
1047     cred_t *credp = crref();
1048     uio_t tuio;
1049     struct iovec iov;
1050
1051     setup_uio(&tuio, &iov, target, 0, maxlen, UIO_READ, seg);
1052     code = afs_readlink((struct vcache*)ip, &tuio, credp);
1053     crfree(credp);
1054
1055     if (!code)
1056         return maxlen - tuio.uio_resid;
1057     else
1058         return -code;
1059 }
1060
1061 #if !defined(AFS_LINUX24_ENV)
1062 /* afs_linux_readlink 
1063  * Fill target (which is in user space) with contents of symlink.
1064  */
1065 int afs_linux_readlink(struct dentry *dp, char *target, int maxlen)
1066 {
1067     int code;
1068     struct inode *ip = dp->d_inode;
1069
1070     AFS_GLOCK();
1071     code = afs_linux_ireadlink(ip, target, maxlen, AFS_UIOUSER);
1072     AFS_GUNLOCK();
1073     return code;
1074 }
1075
1076
1077 /* afs_linux_follow_link
1078  * a file system dependent link following routine.
1079  */
1080 struct dentry * afs_linux_follow_link(struct dentry *dp,
1081                                       struct dentry *basep,
1082                                       unsigned int follow)
1083 {
1084     int code = 0;
1085     char *name;
1086     struct dentry *res;
1087
1088     AFS_GLOCK();
1089     name = osi_Alloc(PATH_MAX+1);
1090     if (!name) {
1091         AFS_GUNLOCK();
1092         dput(basep);
1093         return ERR_PTR(-EIO);
1094     }
1095
1096     code = afs_linux_ireadlink(dp->d_inode, name, PATH_MAX, AFS_UIOSYS);
1097     AFS_GUNLOCK();
1098
1099     if (code<0) {
1100         dput(basep);
1101         res = ERR_PTR(code);
1102     }
1103     else {
1104         name[code] = '\0';
1105         res = lookup_dentry(name, basep, follow);
1106     }
1107
1108     AFS_GLOCK();
1109     osi_Free(name, PATH_MAX+1);
1110     AFS_GUNLOCK();
1111     return res;
1112 }
1113 #endif
1114
1115 /* afs_linux_readpage
1116  * all reads come through here. A strategy-like read call.
1117  */
1118 int afs_linux_readpage(struct file *fp, struct page *pp)
1119 {
1120     int code;
1121     cred_t *credp = crref();
1122     ulong address = afs_linux_page_address(pp);
1123     uio_t tuio;
1124     struct iovec iovec;
1125     struct inode *ip = FILE_INODE(fp);
1126     int cnt = atomic_read(&pp->count);
1127
1128     AFS_GLOCK();
1129     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE,
1130                ICL_TYPE_POINTER, ip,
1131                ICL_TYPE_POINTER, pp,
1132                ICL_TYPE_INT32, cnt,
1133                ICL_TYPE_INT32, 99999); /* not a possible code value */
1134     atomic_add(1, &pp->count);
1135 #if defined(AFS_LINUX24_ENV)
1136     ClearPageError(pp);
1137 #else
1138     set_bit(PG_locked, &pp->flags); /* other bits? See mm.h */
1139     clear_bit(PG_error, &pp->flags);
1140 #endif
1141
1142 #if defined(AFS_LINUX24_ENV)
1143     setup_uio(&tuio, &iovec, (char*)address, pp->index << PAGE_CACHE_SHIFT,
1144               PAGESIZE, UIO_READ, AFS_UIOSYS);
1145 #else
1146     setup_uio(&tuio, &iovec, (char*)address, pageoff(pp), PAGESIZE,
1147               UIO_READ, AFS_UIOSYS);
1148 #endif
1149 #ifdef AFS_LINUX24_ENV
1150     lock_kernel();
1151 #endif
1152     code = afs_rdwr((struct vcache*)ip, &tuio, UIO_READ, 0, credp);
1153 #ifdef AFS_LINUX24_ENV
1154     unlock_kernel();
1155 #endif
1156
1157     if (!code) {
1158         if (tuio.uio_resid) /* zero remainder of page */
1159             memset((void*)(address+(PAGESIZE-tuio.uio_resid)), 0,
1160                    tuio.uio_resid);
1161 #if defined(AFS_LINUX24_ENV)
1162         SetPageUptodate(pp);
1163 #else
1164         set_bit(PG_uptodate, &pp->flags);
1165 #endif
1166     }
1167
1168 #if defined(AFS_LINUX24_ENV)
1169     UnlockPage(pp);
1170 #else
1171     clear_bit(PG_locked, &pp->flags);
1172 #endif
1173     wake_up(&pp->wait);
1174     free_page(address);
1175
1176     crfree(credp);
1177     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE,
1178                ICL_TYPE_POINTER, ip,
1179                ICL_TYPE_POINTER, pp,
1180                ICL_TYPE_INT32, cnt,
1181                ICL_TYPE_INT32, code);
1182     AFS_GUNLOCK();
1183     return -code;
1184 }
1185
1186 #if defined(AFS_LINUX24_ENV)
1187 int afs_linux_writepage(struct page *pp)
1188 {
1189     struct address_space *mapping = pp->mapping;
1190     struct inode *inode;
1191     unsigned long end_index;
1192     unsigned offset = PAGE_CACHE_SIZE;
1193     long status;
1194  
1195     inode = (struct inode *) mapping->host;
1196     end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1197
1198     /* easy case */
1199     if (pp->index < end_index)
1200         goto do_it;
1201     /* things got complicated... */
1202     offset = inode->i_size & (PAGE_CACHE_SIZE-1);
1203     /* OK, are we completely out? */
1204     if (pp->index >= end_index+1 || !offset)
1205         return -EIO;
1206 do_it:
1207     status = afs_linux_writepage_sync(inode, pp, 0, offset);
1208     SetPageUptodate(pp);
1209     UnlockPage(pp);
1210     /* kunmap(pp); */
1211     if (status == offset)
1212         return 0;
1213     else
1214         return status;
1215 }
1216 #endif
1217
1218 #ifdef NOTUSED
1219 /* afs_linux_bmap - supports generic_readpage, but we roll our own. */
1220 int afs_linux_bmap(struct inode *ip, int) { return -EINVAL; }
1221
1222 /* afs_linux_truncate
1223  * Handles discarding disk blocks if this were a device. ext2 indicates we
1224  * may need to zero partial last pages of memory mapped files.
1225  */
1226 void afs_linux_truncate(struct inode *ip)
1227 {
1228 }
1229 #endif
1230
1231 /* afs_linux_permission
1232  * Check access rights - returns error if can't check or permission denied.
1233  */
1234 int afs_linux_permission(struct inode *ip, int mode)
1235 {
1236     int code;
1237     cred_t *credp = crref();
1238     int tmp = 0;
1239
1240     AFS_GLOCK();
1241     if (mode & MAY_EXEC) tmp |= VEXEC;
1242     if (mode & MAY_READ) tmp |= VREAD;
1243     if (mode & MAY_WRITE) tmp |= VWRITE;
1244     code = afs_access((struct vcache*)ip, tmp, credp);
1245
1246     AFS_GUNLOCK();
1247     crfree(credp);
1248     return -code;
1249 }
1250
1251
1252 #ifdef NOTUSED
1253 /* msdos sector mapping hack for memory mapping. */
1254 int afs_linux_smap(struct inode *ip, int) { return -EINVAL; }
1255 #endif
1256
1257 #if defined(AFS_LINUX24_ENV)
1258 int afs_linux_writepage_sync(struct inode *ip, struct page *pp,
1259                         unsigned long offset,
1260                         unsigned int count)
1261 {
1262     struct vcache *vcp = (struct vcache *) ip;
1263     u8 *page_addr = (u8*) afs_linux_page_address(pp);
1264     int code = 0;
1265     cred_t *credp;
1266     uio_t tuio;
1267     struct iovec iovec;
1268     int f_flags = 0;
1269
1270     credp = crref();
1271     AFS_GLOCK();
1272     lock_kernel();
1273     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1274               ICL_TYPE_POINTER, pp,
1275               ICL_TYPE_INT32, atomic_read(&pp->count),
1276               ICL_TYPE_INT32, 99999);
1277     setup_uio(&tuio, &iovec, page_addr + offset,
1278              (pp->index << PAGE_CACHE_SHIFT) + offset, count,
1279              UIO_WRITE, AFS_UIOSYS);
1280
1281     code = afs_write(vcp, &tuio, f_flags, credp, 0);
1282
1283     vcache2inode(vcp);
1284
1285     code = code ? -code : count - tuio.uio_resid;
1286     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1287               ICL_TYPE_POINTER, pp,
1288               ICL_TYPE_INT32, atomic_read(&pp->count),
1289               ICL_TYPE_INT32, code);
1290
1291     unlock_kernel();
1292     AFS_GUNLOCK();
1293     crfree(credp);
1294
1295     return code;
1296 }
1297
1298 static int
1299 afs_linux_updatepage(struct file *file, struct page *page, 
1300                      unsigned long offset, unsigned int count)
1301 {
1302     struct dentry *dentry = file->f_dentry;
1303
1304     return afs_linux_writepage_sync(dentry->d_inode, page, offset, count);
1305 }
1306 #else
1307 /* afs_linux_updatepage
1308  * What one would have thought was writepage - write dirty page to file.
1309  * Called from generic_file_write. buffer is still in user space. pagep
1310  * has been filled in with old data if we're updating less than a page.
1311  */
1312 int afs_linux_updatepage(struct file *fp, struct page *pp,
1313                          unsigned long offset,
1314                          unsigned int count, int sync)
1315 {
1316     struct vcache *vcp = (struct vcache *)FILE_INODE(fp);
1317     u8 *page_addr = (u8*) afs_linux_page_address(pp);
1318     int code = 0;
1319     cred_t *credp;
1320     uio_t tuio;
1321     struct iovec iovec;
1322     
1323     set_bit(PG_locked, &pp->flags);
1324
1325     credp = crref();
1326     AFS_GLOCK();
1327     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1328                ICL_TYPE_POINTER, pp,
1329                ICL_TYPE_INT32, atomic_read(&pp->count),
1330                ICL_TYPE_INT32, 99999);
1331     setup_uio(&tuio, &iovec, page_addr + offset, pageoff(pp) + offset, count,
1332               UIO_WRITE, AFS_UIOSYS);
1333
1334     code = afs_write(vcp, &tuio, fp->f_flags, credp, 0);
1335
1336     vcache2inode(vcp);
1337
1338     code = code ? -code : count - tuio.uio_resid;
1339     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1340                ICL_TYPE_POINTER, pp,
1341                ICL_TYPE_INT32, atomic_read(&pp->count),
1342                ICL_TYPE_INT32, code);
1343
1344     AFS_GUNLOCK();
1345     crfree(credp);
1346
1347     clear_bit(PG_locked, &pp->flags);
1348     return code;
1349 }
1350 #endif
1351
1352 #if defined(AFS_LINUX24_ENV)
1353 static int afs_linux_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
1354 {
1355     long status;
1356
1357     /* lock_kernel(); */
1358     status = afs_linux_updatepage(file, page, offset, to-offset);
1359     /* unlock_kernel(); */
1360     kunmap(page);
1361
1362     return status;
1363 }
1364
1365 static int afs_linux_prepare_write(struct file *file, struct page *page,
1366                                    unsigned from, unsigned to)
1367 {
1368     kmap(page);
1369     return 0;
1370 }
1371
1372 extern int afs_notify_change(struct dentry *dp, struct iattr* iattrp);
1373 #endif
1374
1375 #if defined(AFS_LINUX24_ENV)
1376 struct inode_operations afs_file_iops = {
1377     revalidate:                afs_linux_revalidate,
1378     setattr:           afs_notify_change,
1379     permission:                afs_linux_permission,
1380 };
1381 struct address_space_operations afs_file_aops = {
1382         readpage: afs_linux_readpage,
1383         writepage: afs_linux_writepage,
1384         commit_write: afs_linux_commit_write,
1385         prepare_write: afs_linux_prepare_write,
1386 };
1387
1388 struct inode_operations *afs_ops = &afs_file_iops;
1389 #else
1390 struct inode_operations afs_iops = {
1391     &afs_file_fops,     /* file operations */
1392     NULL,               /* afs_linux_create */
1393     NULL,               /* afs_linux_lookup */
1394     NULL,               /* afs_linux_link */
1395     NULL,               /* afs_linux_unlink */
1396     NULL,               /* afs_linux_symlink */
1397     NULL,               /* afs_linux_mkdir */
1398     NULL,               /* afs_linux_rmdir */
1399     NULL,               /* afs_linux_mknod */
1400     NULL,               /* afs_linux_rename */
1401     NULL,               /* afs_linux_readlink */
1402     NULL,               /* afs_linux_follow_link */
1403     afs_linux_readpage,
1404     NULL,               /* afs_linux_writepage */
1405     NULL,               /* afs_linux_bmap */
1406     NULL,               /* afs_linux_truncate */
1407     afs_linux_permission,
1408     NULL,               /* afs_linux_smap */
1409     afs_linux_updatepage,
1410     afs_linux_revalidate,
1411 };
1412
1413 struct inode_operations *afs_ops = &afs_iops;
1414 #endif
1415
1416 /* Separate ops vector for directories. Linux 2.2 tests type of inode
1417  * by what sort of operation is allowed.....
1418  */
1419 #if defined(AFS_LINUX24_ENV)
1420 struct inode_operations afs_dir_iops = {
1421     create:    afs_linux_create,
1422     lookup:    afs_linux_lookup,
1423     link:      afs_linux_link,
1424     unlink:    afs_linux_unlink,
1425     symlink:   afs_linux_symlink,
1426     mkdir:     afs_linux_mkdir,
1427     rmdir:     afs_linux_rmdir,
1428     rename:    afs_linux_rename,
1429     revalidate:        afs_linux_revalidate,
1430     setattr:   afs_notify_change,
1431     permission:        afs_linux_permission,
1432 };
1433 #else
1434 struct inode_operations afs_dir_iops = {
1435     &afs_dir_fops,      /* file operations for directories */
1436     afs_linux_create,
1437     afs_linux_lookup,
1438     afs_linux_link,
1439     afs_linux_unlink,
1440     afs_linux_symlink,
1441     afs_linux_mkdir,
1442     afs_linux_rmdir,
1443     NULL,               /* afs_linux_mknod */
1444     afs_linux_rename,
1445     NULL,               /* afs_linux_readlink */
1446     NULL,               /* afs_linux_follow_link */
1447     NULL,               /* afs_linux_readpage */
1448     NULL,               /* afs_linux_writepage */
1449     NULL,               /* afs_linux_bmap */
1450     NULL,               /* afs_linux_truncate */
1451     afs_linux_permission,
1452     NULL,               /* afs_linux_smap */
1453     NULL,               /* afs_linux_updatepage */
1454     afs_linux_revalidate,
1455 };
1456 #endif
1457
1458 /* We really need a separate symlink set of ops, since do_follow_link()
1459  * determines if it _is_ a link by checking if the follow_link op is set.
1460  */
1461 #if defined(AFS_LINUX24_ENV)
1462 static int afs_symlink_filler(struct file *file, struct page *page)
1463 {
1464     struct inode *ip = (struct inode *) page->mapping->host;
1465     char *p = (char *)kmap(page);
1466     int code;
1467
1468     AFS_GLOCK();
1469     lock_kernel();
1470     code = afs_linux_ireadlink(ip, p, PAGE_SIZE, AFS_UIOSYS);
1471     unlock_kernel();
1472     AFS_GUNLOCK();
1473
1474     if (code<0)
1475            goto fail;
1476     p[code] = '\0';            /* null terminate? */
1477     SetPageUptodate(page);
1478     kunmap(page);
1479     UnlockPage(page);
1480     return 0;
1481
1482 fail:
1483     SetPageError(page);
1484     kunmap(page);
1485     UnlockPage(page);
1486     return code;
1487 }
1488
1489 struct address_space_operations afs_symlink_aops = {
1490        readpage:       afs_symlink_filler
1491 };
1492
1493 struct inode_operations afs_symlink_iops = {
1494     readlink:          page_readlink,
1495     follow_link:       page_follow_link,
1496     setattr:           afs_notify_change,
1497 };
1498 #else
1499 struct inode_operations afs_symlink_iops = {
1500     NULL,               /* file operations */
1501     NULL,               /* create */
1502     NULL,               /* lookup */
1503     NULL,               /* link */
1504     NULL,               /* unlink */
1505     NULL,               /* symlink */
1506     NULL,               /* mkdir */
1507     NULL,               /* rmdir */
1508     NULL,               /* afs_linux_mknod */
1509     NULL,               /* rename */
1510     afs_linux_readlink,
1511     afs_linux_follow_link,
1512     NULL,               /* readpage */
1513     NULL,               /* afs_linux_writepage */
1514     NULL,               /* afs_linux_bmap */
1515     NULL,               /* afs_linux_truncate */
1516     afs_linux_permission, /* tho the code appears to indicate not used? */
1517     NULL,               /* afs_linux_smap */
1518     NULL,               /* updatepage */
1519     afs_linux_revalidate, /* tho the code appears to indicate not used? */
1520 };
1521 #endif