b88c62d994ab9555f26f235e312d8a10cbbc6f4d
[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.
13  *
14  * So far the only truly scary part is that Linux relies on the inode cache
15  * to be up to date. Don't you dare break a callback and expect an fstat
16  * to give you meaningful information. This appears to be fixed in the 2.1
17  * development kernels. As it is we can fix this now by intercepting the 
18  * stat calls.
19  */
20
21 #include <afsconfig.h>
22 #include "afs/param.h"
23
24 RCSID
25     ("$Header$");
26
27 #include "afs/sysincludes.h"
28 #include "afsincludes.h"
29 #include "afs/afs_stats.h"
30 #include "h/mm.h"
31 #ifdef HAVE_MM_INLINE_H
32 #include "h/mm_inline.h"
33 #endif
34 #include "h/pagemap.h"
35 #if defined(AFS_LINUX24_ENV)
36 #include "h/smp_lock.h"
37 #endif
38 #if defined(AFS_LINUX26_ENV)
39 #include "h/writeback.h"
40 #endif
41
42 #ifdef pgoff2loff
43 #define pageoff(pp) pgoff2loff((pp)->index)
44 #else
45 #define pageoff(pp) pp->offset
46 #endif
47
48 #if defined(AFS_LINUX26_ENV)
49 #define UnlockPage(pp) unlock_page(pp)
50 #endif
51
52 extern struct vcache *afs_globalVp;
53 static ssize_t
54 afs_linux_read(struct file *fp, char *buf, size_t count, loff_t * offp)
55 {
56     ssize_t code;
57     struct vcache *vcp = VTOAFS(fp->f_dentry->d_inode);
58     cred_t *credp = crref();
59     struct vrequest treq;
60
61     AFS_GLOCK();
62     afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
63                ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
64                99999);
65
66     /* get a validated vcache entry */
67     code = afs_InitReq(&treq, credp);
68     if (!code)
69         code = afs_VerifyVCache(vcp, &treq);
70
71     if (code)
72         code = -code;
73     else {
74             osi_FlushPages(vcp, credp); /* ensure stale pages are gone */
75             AFS_GUNLOCK();
76             code = generic_file_read(fp, buf, count, offp);
77             AFS_GLOCK();
78     }
79
80     afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
81                ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
82                code);
83
84     AFS_GUNLOCK();
85     crfree(credp);
86     return code;
87 }
88
89
90 /* Now we have integrated VM for writes as well as reads. generic_file_write
91  * also takes care of re-positioning the pointer if file is open in append
92  * mode. Call fake open/close to ensure we do writes of core dumps.
93  */
94 static ssize_t
95 afs_linux_write(struct file *fp, const char *buf, size_t count, loff_t * offp)
96 {
97     ssize_t code = 0;
98     int code2 = 0;
99     struct vcache *vcp = VTOAFS(fp->f_dentry->d_inode);
100     struct vrequest treq;
101     cred_t *credp = crref();
102
103     AFS_GLOCK();
104
105     afs_Trace4(afs_iclSetp, CM_TRACE_WRITEOP, ICL_TYPE_POINTER, vcp,
106                ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
107                (fp->f_flags & O_APPEND) ? 99998 : 99999);
108
109
110     /* get a validated vcache entry */
111     code = (ssize_t) afs_InitReq(&treq, credp);
112     if (!code)
113         code = (ssize_t) afs_VerifyVCache(vcp, &treq);
114
115     ObtainWriteLock(&vcp->lock, 529);
116     afs_FakeOpen(vcp);
117     ReleaseWriteLock(&vcp->lock);
118     if (code)
119         code = -code;
120     else {
121             AFS_GUNLOCK();
122             code = generic_file_write(fp, buf, count, offp);
123             AFS_GLOCK();
124     }
125
126     ObtainWriteLock(&vcp->lock, 530);
127     afs_FakeClose(vcp, credp);
128     ReleaseWriteLock(&vcp->lock);
129
130     afs_Trace4(afs_iclSetp, CM_TRACE_WRITEOP, ICL_TYPE_POINTER, vcp,
131                ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
132                code);
133
134     AFS_GUNLOCK();
135     crfree(credp);
136     return code;
137 }
138
139 extern int BlobScan(struct dcache * afile, afs_int32 ablob);
140
141 /* This is a complete rewrite of afs_readdir, since we can make use of
142  * filldir instead of afs_readdir_move. Note that changes to vcache/dcache
143  * handling and use of bulkstats will need to be reflected here as well.
144  */
145 static int
146 afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
147 {
148     extern struct DirEntry *afs_dir_GetBlob();
149     struct vcache *avc = VTOAFS(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     afs_size_t origOffset, tlen;
159     cred_t *credp = crref();
160     struct afs_fakestat_state fakestat;
161
162 #if defined(AFS_LINUX26_ENV)
163     lock_kernel();
164 #endif
165     AFS_GLOCK();
166     AFS_STATCNT(afs_readdir);
167
168     code = afs_InitReq(&treq, credp);
169     crfree(credp);
170     if (code)
171         goto out1;
172
173     afs_InitFakeStat(&fakestat);
174     code = afs_EvalFakeStat(&avc, &fakestat, &treq);
175     if (code)
176         goto out;
177
178     /* update the cache entry */
179   tagain:
180     code = afs_VerifyVCache(avc, &treq);
181     if (code)
182         goto out;
183
184     /* get a reference to the entire directory */
185     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
186     len = tlen;
187     if (!tdc) {
188         code = -ENOENT;
189         goto out;
190     }
191     ObtainReadLock(&avc->lock);
192     ObtainReadLock(&tdc->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->dflags & DFFetching)
201            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
202         ReleaseReadLock(&tdc->lock);
203         ReleaseReadLock(&avc->lock);
204         afs_osi_Sleep(&tdc->validPos);
205         ObtainReadLock(&avc->lock);
206         ObtainReadLock(&tdc->lock);
207     }
208     if (!(avc->states & CStatd)
209         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
210         ReleaseReadLock(&tdc->lock);
211         ReleaseReadLock(&avc->lock);
212         afs_PutDCache(tdc);
213         goto tagain;
214     }
215
216     /* Fill in until we get an error or we're done. This implementation
217      * takes an offset in units of blobs, rather than bytes.
218      */
219     code = 0;
220     offset = (int) fp->f_pos;
221     while (1) {
222         dirpos = BlobScan(tdc, offset);
223         if (!dirpos)
224             break;
225
226         de = afs_dir_GetBlob(tdc, dirpos);
227         if (!de)
228             break;
229
230         ino = afs_calc_inum (avc->fid.Fid.Volume, ntohl(de->fid.vnode));
231
232         if (de->name)
233             len = strlen(de->name);
234         else {
235             printf("afs_linux_readdir: afs_dir_GetBlob failed, null name (inode %lx, dirpos %d)\n", 
236                    (unsigned long)&tdc->f.inode, dirpos);
237             DRelease((struct buffer *) de, 0);
238             afs_PutDCache(tdc);
239             ReleaseReadLock(&avc->lock);
240             code = -ENOENT;
241             goto out;
242         }
243
244         /* filldir returns -EINVAL when the buffer is full. */
245 #if defined(AFS_LINUX26_ENV) || ((defined(AFS_LINUX24_ENV) || defined(pgoff2loff)) && defined(DECLARE_FSTYPE))
246         {
247             unsigned int type = DT_UNKNOWN;
248             struct VenusFid afid;
249             struct vcache *tvc;
250             int vtype;
251             afid.Cell = avc->fid.Cell;
252             afid.Fid.Volume = avc->fid.Fid.Volume;
253             afid.Fid.Vnode = ntohl(de->fid.vnode);
254             afid.Fid.Unique = ntohl(de->fid.vunique);
255             if ((avc->states & CForeign) == 0 && (ntohl(de->fid.vnode) & 1)) {
256                 type = DT_DIR;
257             } else if ((tvc = afs_FindVCache(&afid, 0, 0))) {
258                 if (tvc->mvstat) {
259                     type = DT_DIR;
260                 } else if (((tvc->states) & (CStatd | CTruth))) {
261                     /* CTruth will be set if the object has
262                      *ever* been statd */
263                     vtype = vType(tvc);
264                     if (vtype == VDIR)
265                         type = DT_DIR;
266                     else if (vtype == VREG)
267                         type = DT_REG;
268                     /* Don't do this until we're sure it can't be a mtpt */
269                     /* else if (vtype == VLNK)
270                      * type=DT_LNK; */
271                     /* what other types does AFS support? */
272                 }
273                 /* clean up from afs_FindVCache */
274                 afs_PutVCache(tvc);
275             }
276             code = (*filldir) (dirbuf, de->name, len, offset, ino, type);
277         }
278 #else
279         code = (*filldir) (dirbuf, de->name, len, offset, ino);
280 #endif
281         DRelease((struct buffer *)de, 0);
282         if (code)
283             break;
284         offset = dirpos + 1 + ((len + 16) >> 5);
285     }
286     /* If filldir didn't fill in the last one this is still pointing to that
287      * last attempt.
288      */
289     fp->f_pos = (loff_t) offset;
290
291     ReleaseReadLock(&tdc->lock);
292     afs_PutDCache(tdc);
293     ReleaseReadLock(&avc->lock);
294     code = 0;
295
296 out:
297     afs_PutFakeStat(&fakestat);
298 out1:
299     AFS_GUNLOCK();
300 #if defined(AFS_LINUX26_ENV)
301     unlock_kernel();
302 #endif
303     return code;
304 }
305
306
307 /* in afs_pioctl.c */
308 extern int afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
309                       unsigned long arg);
310
311 #if defined(HAVE_UNLOCKED_IOCTL) || defined(HAVE_COMPAT_IOCTL)
312 static long afs_unlocked_xioctl(struct file *fp, unsigned int com,
313                                unsigned long arg) {
314     return afs_xioctl(FILE_INODE(fp), fp, com, arg);
315
316 }
317 #endif
318
319
320 static int
321 afs_linux_mmap(struct file *fp, struct vm_area_struct *vmap)
322 {
323     struct vcache *vcp = VTOAFS(FILE_INODE(fp));
324     cred_t *credp = crref();
325     struct vrequest treq;
326     int code;
327
328     AFS_GLOCK();
329 #if defined(AFS_LINUX24_ENV)
330     afs_Trace3(afs_iclSetp, CM_TRACE_GMAP, ICL_TYPE_POINTER, vcp,
331                ICL_TYPE_POINTER, vmap->vm_start, ICL_TYPE_INT32,
332                vmap->vm_end - vmap->vm_start);
333 #else
334     afs_Trace4(afs_iclSetp, CM_TRACE_GMAP, ICL_TYPE_POINTER, vcp,
335                ICL_TYPE_POINTER, vmap->vm_start, ICL_TYPE_INT32,
336                vmap->vm_end - vmap->vm_start, ICL_TYPE_INT32,
337                vmap->vm_offset);
338 #endif
339
340     /* get a validated vcache entry */
341     code = afs_InitReq(&treq, credp);
342     if (code)
343         goto out_err;
344
345     code = afs_VerifyVCache(vcp, &treq);
346     if (code)
347         goto out_err;
348
349     osi_FlushPages(vcp, credp); /* ensure stale pages are gone */
350
351     AFS_GUNLOCK();
352     code = generic_file_mmap(fp, vmap);
353     AFS_GLOCK();
354     if (!code)
355         vcp->states |= CMAPPED;
356
357 out:
358     AFS_GUNLOCK();
359     crfree(credp);
360     return code;
361
362 out_err:
363     code = -code;
364     goto out;
365 }
366
367 static int
368 afs_linux_open(struct inode *ip, struct file *fp)
369 {
370     struct vcache *vcp = VTOAFS(ip);
371     cred_t *credp = crref();
372     int code;
373
374 #ifdef AFS_LINUX24_ENV
375     lock_kernel();
376 #endif
377     AFS_GLOCK();
378     code = afs_open(&vcp, fp->f_flags, credp);
379     AFS_GUNLOCK();
380 #ifdef AFS_LINUX24_ENV
381     unlock_kernel();
382 #endif
383
384     crfree(credp);
385     return -code;
386 }
387
388 static int
389 afs_linux_release(struct inode *ip, struct file *fp)
390 {
391     struct vcache *vcp = VTOAFS(ip);
392     cred_t *credp = crref();
393     int code = 0;
394
395 #ifdef AFS_LINUX24_ENV
396     lock_kernel();
397 #endif
398     AFS_GLOCK();
399     code = afs_close(vcp, fp->f_flags, credp);
400     AFS_GUNLOCK();
401 #ifdef AFS_LINUX24_ENV
402     unlock_kernel();
403 #endif
404
405     crfree(credp);
406     return -code;
407 }
408
409 static int
410 #if defined(AFS_LINUX24_ENV)
411 afs_linux_fsync(struct file *fp, struct dentry *dp, int datasync)
412 #else
413 afs_linux_fsync(struct file *fp, struct dentry *dp)
414 #endif
415 {
416     int code;
417     struct inode *ip = FILE_INODE(fp);
418     cred_t *credp = crref();
419
420 #ifdef AFS_LINUX24_ENV
421     lock_kernel();
422 #endif
423     AFS_GLOCK();
424     code = afs_fsync(VTOAFS(ip), credp);
425     AFS_GUNLOCK();
426 #ifdef AFS_LINUX24_ENV
427     unlock_kernel();
428 #endif
429     crfree(credp);
430     return -code;
431
432 }
433
434
435 static int
436 afs_linux_lock(struct file *fp, int cmd, struct file_lock *flp)
437 {
438     int code = 0;
439     struct vcache *vcp = VTOAFS(FILE_INODE(fp));
440     cred_t *credp = crref();
441     struct AFS_FLOCK flock;
442     /* Convert to a lock format afs_lockctl understands. */
443     memset((char *)&flock, 0, sizeof(flock));
444     flock.l_type = flp->fl_type;
445     flock.l_pid = flp->fl_pid;
446     flock.l_whence = 0;
447     flock.l_start = flp->fl_start;
448     flock.l_len = flp->fl_end - flp->fl_start;
449
450     /* Safe because there are no large files, yet */
451 #if defined(F_GETLK64) && (F_GETLK != F_GETLK64)
452     if (cmd == F_GETLK64)
453         cmd = F_GETLK;
454     else if (cmd == F_SETLK64)
455         cmd = F_SETLK;
456     else if (cmd == F_SETLKW64)
457         cmd = F_SETLKW;
458 #endif /* F_GETLK64 && F_GETLK != F_GETLK64 */
459
460     AFS_GLOCK();
461     code = afs_lockctl(vcp, &flock, cmd, credp);
462     AFS_GUNLOCK();
463
464 #ifdef AFS_LINUX24_ENV
465     if (code == 0 && (cmd == F_SETLK || cmd == F_SETLKW)) {
466        struct file_lock flp2;
467        flp2 = *flp;
468 #ifdef AFS_LINUX26_ENV
469        flp2.fl_flags &=~ FL_SLEEP;
470 #endif
471        code = posix_lock_file(fp, &flp2);
472        osi_Assert(code != -EAGAIN); /* there should be no conflicts */
473        if (code) {
474            struct AFS_FLOCK flock2;
475            flock2 = flock;
476            flock2.l_type = F_UNLCK;
477            AFS_GLOCK();
478            afs_lockctl(vcp, &flock2, F_SETLK, credp);
479            AFS_GUNLOCK();
480        }
481     }
482 #endif
483     /* Convert flock back to Linux's file_lock */
484     flp->fl_type = flock.l_type;
485     flp->fl_pid = flock.l_pid;
486     flp->fl_start = flock.l_start;
487     flp->fl_end = flock.l_start + flock.l_len;
488
489     crfree(credp);
490     return -code;
491
492 }
493
494 /* afs_linux_flush
495  * essentially the same as afs_fsync() but we need to get the return
496  * code for the sys_close() here, not afs_linux_release(), so call
497  * afs_StoreAllSegments() with AFS_LASTSTORE
498  */
499 static int
500 afs_linux_flush(struct file *fp)
501 {
502     struct vrequest treq;
503     struct vcache *vcp = VTOAFS(FILE_INODE(fp));
504     cred_t *credp = crref();
505     int code;
506
507     AFS_GLOCK();
508
509     code = afs_InitReq(&treq, credp);
510     if (code)
511         goto out;
512
513     ObtainSharedLock(&vcp->lock, 535);
514     if (vcp->execsOrWriters > 0) {
515         UpgradeSToWLock(&vcp->lock, 536);
516         code = afs_StoreAllSegments(vcp, &treq, AFS_SYNC | AFS_LASTSTORE);
517         ConvertWToSLock(&vcp->lock);
518     }
519     code = afs_CheckCode(code, &treq, 54);
520     ReleaseSharedLock(&vcp->lock);
521
522 out:
523     AFS_GUNLOCK();
524
525     crfree(credp);
526     return -code;
527 }
528
529 #if !defined(AFS_LINUX24_ENV)
530 /* Not allowed to directly read a directory. */
531 ssize_t
532 afs_linux_dir_read(struct file * fp, char *buf, size_t count, loff_t * ppos)
533 {
534     return -EISDIR;
535 }
536 #endif
537
538
539
540 struct file_operations afs_dir_fops = {
541 #if !defined(AFS_LINUX24_ENV)
542   .read =       afs_linux_dir_read,
543   .lock =       afs_linux_lock,
544   .fsync =      afs_linux_fsync,
545 #else
546   .read =       generic_read_dir,
547 #endif
548   .readdir =    afs_linux_readdir,
549 #ifdef HAVE_UNLOCKED_IOCTL
550   .unlocked_ioctl = afs_unlocked_xioctl,
551 #else
552   .ioctl =      afs_xioctl,
553 #endif
554 #ifdef HAVE_COMPAT_IOCTL
555   .compat_ioctl = afs_unlocked_xioctl,
556 #endif
557   .open =       afs_linux_open,
558   .release =    afs_linux_release,
559 };
560
561 struct file_operations afs_file_fops = {
562   .read =       afs_linux_read,
563   .write =      afs_linux_write,
564 #ifdef HAVE_UNLOCKED_IOCTL
565   .unlocked_ioctl = afs_unlocked_xioctl,
566 #else
567   .ioctl =      afs_xioctl,
568 #endif
569 #ifdef HAVE_COMPAT_IOCTL
570   .compat_ioctl = afs_unlocked_xioctl,
571 #endif
572   .mmap =       afs_linux_mmap,
573   .open =       afs_linux_open,
574   .flush =      afs_linux_flush,
575 #ifdef AFS_LINUX26_ENV
576   .sendfile =   generic_file_sendfile,
577 #endif
578   .release =    afs_linux_release,
579   .fsync =      afs_linux_fsync,
580   .lock =       afs_linux_lock,
581 };
582
583
584 /**********************************************************************
585  * AFS Linux dentry operations
586  **********************************************************************/
587
588 /* check_bad_parent() : Checks if this dentry's vcache is a root vcache
589  * that has its mvid (parent dir's fid) pointer set to the wrong directory
590  * due to being mounted in multiple points at once. If so, check_bad_parent()
591  * calls afs_lookup() to correct the vcache's mvid, as well as the volume's
592  * dotdotfid and mtpoint fid members.
593  * Parameters:
594  *   dp - dentry to be checked.
595  * Return Values:
596  *   None.
597  * Sideeffects:
598  *   This dentry's vcache's mvid will be set to the correct parent directory's
599  *   fid.
600  *   This root vnode's volume will have its dotdotfid and mtpoint fids set
601  *   to the correct parent and mountpoint fids.
602  */
603
604 static inline void
605 check_bad_parent(struct dentry *dp)
606 {
607     cred_t *credp;
608     struct vcache *vcp = VTOAFS(dp->d_inode), *avc = NULL;
609     struct vcache *pvc = VTOAFS(dp->d_parent->d_inode);
610
611     if (vcp->mvid->Fid.Volume != pvc->fid.Fid.Volume) { /* bad parent */
612         credp = crref();
613
614         /* force a lookup, so vcp->mvid is fixed up */
615         afs_lookup(pvc, dp->d_name.name, &avc, credp);
616         if (!avc || vcp != avc) {       /* bad, very bad.. */
617             afs_Trace4(afs_iclSetp, CM_TRACE_TMP_1S3L, ICL_TYPE_STRING,
618                        "check_bad_parent: bad pointer returned from afs_lookup origvc newvc dentry",
619                        ICL_TYPE_POINTER, vcp, ICL_TYPE_POINTER, avc,
620                        ICL_TYPE_POINTER, dp);
621         }
622         if (avc)
623             AFS_RELE(AFSTOV(avc));
624         crfree(credp);
625     }
626
627     return;
628 }
629
630 /* afs_linux_revalidate
631  * Ensure vcache is stat'd before use. Return 0 if entry is valid.
632  */
633 static int
634 afs_linux_revalidate(struct dentry *dp)
635 {
636     struct vattr vattr;
637     struct vcache *vcp = VTOAFS(dp->d_inode);
638     cred_t *credp;
639     int code;
640
641 #ifdef AFS_LINUX24_ENV
642     lock_kernel();
643 #endif
644     AFS_GLOCK();
645
646 #ifdef notyet
647     /* Make this a fast path (no crref), since it's called so often. */
648     if (vcp->states & CStatd) {
649
650         if (*dp->d_name.name != '/' && vcp->mvstat == 2)        /* root vnode */
651             check_bad_parent(dp);       /* check and correct mvid */
652
653         AFS_GUNLOCK();
654 #ifdef AFS_LINUX24_ENV
655         unlock_kernel();
656 #endif
657         return 0;
658     }
659 #endif
660
661     credp = crref();
662     code = afs_getattr(vcp, &vattr, credp);
663     if (!code)
664         vattr2inode(AFSTOV(vcp), &vattr);
665
666     AFS_GUNLOCK();
667 #ifdef AFS_LINUX24_ENV
668     unlock_kernel();
669 #endif
670     crfree(credp);
671
672     return -code;
673 }
674
675 #if defined(AFS_LINUX26_ENV)
676 static int
677 afs_linux_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
678 {
679         int err = afs_linux_revalidate(dentry);
680         if (!err) {
681                 generic_fillattr(dentry->d_inode, stat);
682 }
683         return err;
684 }
685 #endif
686
687 /* Validate a dentry. Return 1 if unchanged, 0 if VFS layer should re-evaluate.
688  * In kernels 2.2.10 and above, we are passed an additional flags var which
689  * may have either the LOOKUP_FOLLOW OR LOOKUP_DIRECTORY set in which case
690  * we are advised to follow the entry if it is a link or to make sure that 
691  * it is a directory. But since the kernel itself checks these possibilities
692  * later on, we shouldn't have to do it until later. Perhaps in the future..
693  */
694 static int
695 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
696 #ifdef DOP_REVALIDATE_TAKES_NAMEIDATA
697 afs_linux_dentry_revalidate(struct dentry *dp, struct nameidata *nd)
698 #else
699 afs_linux_dentry_revalidate(struct dentry *dp, int flags)
700 #endif
701 #else
702 afs_linux_dentry_revalidate(struct dentry *dp)
703 #endif
704 {
705     struct vattr vattr;
706     cred_t *credp = NULL;
707     struct vcache *vcp, *pvcp, *tvc = NULL;
708     int valid;
709
710 #ifdef AFS_LINUX24_ENV
711     lock_kernel();
712 #endif
713     AFS_GLOCK();
714
715     if (dp->d_inode) {
716
717         vcp = VTOAFS(dp->d_inode);
718         pvcp = VTOAFS(dp->d_parent->d_inode);           /* dget_parent()? */
719
720         if (vcp == afs_globalVp)
721             goto good_dentry;
722
723         if (*dp->d_name.name != '/' && vcp->mvstat == 2)        /* root vnode */
724             check_bad_parent(dp);       /* check and correct mvid */
725
726 #ifdef notdef
727         /* If the last looker changes, we should make sure the current
728          * looker still has permission to examine this file.  This would
729          * always require a crref() which would be "slow".
730          */
731         if (vcp->last_looker != treq.uid) {
732             if (!afs_AccessOK(vcp, (vType(vcp) == VREG) ? PRSFS_READ : PRSFS_LOOKUP, &treq, CHECK_MODE_BITS))
733                 goto bad_dentry;
734
735             vcp->last_looker = treq.uid;
736         }
737 #endif
738
739         /* If the parent's DataVersion has changed or the vnode
740          * is longer valid, we need to do a full lookup.  VerifyVCache
741          * isn't enough since the vnode may have been renamed.
742          */
743
744         if (hgetlo(pvcp->m.DataVersion) > dp->d_time || !(vcp->states & CStatd)) {
745
746             credp = crref();
747             afs_lookup(pvcp, dp->d_name.name, &tvc, credp);
748             if (!tvc || tvc != vcp)
749                 goto bad_dentry;
750
751             if (afs_getattr(vcp, &vattr, credp))
752                 goto bad_dentry;
753
754             vattr2inode(AFSTOV(vcp), &vattr);
755             dp->d_time = hgetlo(pvcp->m.DataVersion);
756         }
757
758         /* should we always update the attributes at this point? */
759         /* unlikely--the vcache entry hasn't changed */
760
761     } else {
762 #ifdef notyet
763         pvcp = VTOAFS(dp->d_parent->d_inode);           /* dget_parent()? */
764         if (hgetlo(pvcp->m.DataVersion) > dp->d_time)
765             goto bad_dentry;
766 #endif
767
768         /* No change in parent's DataVersion so this negative
769          * lookup is still valid.  BUT, if a server is down a
770          * negative lookup can result so there should be a
771          * liftime as well.  For now, always expire.
772          */
773
774         goto bad_dentry;
775     }
776
777   good_dentry:
778     valid = 1;
779
780   done:
781     /* Clean up */
782     if (tvc)
783         afs_PutVCache(tvc);
784     AFS_GUNLOCK();
785     if (credp)
786         crfree(credp);
787
788     if (!valid) {
789         shrink_dcache_parent(dp);
790         d_drop(dp);
791     }
792 #ifdef AFS_LINUX24_ENV
793     unlock_kernel();
794 #endif
795     return valid;
796
797   bad_dentry:
798     valid = 0;
799     goto done;
800 }
801
802 static void
803 afs_dentry_iput(struct dentry *dp, struct inode *ip)
804 {
805     struct vcache *vcp = VTOAFS(ip);
806
807     AFS_GLOCK();
808     if (vcp->states & CUnlinked)
809         (void) afs_InactiveVCache(vcp, NULL);
810     AFS_GUNLOCK();
811
812     iput(ip);
813 }
814
815 static int
816 afs_dentry_delete(struct dentry *dp)
817 {
818     if (dp->d_inode && (VTOAFS(dp->d_inode)->states & CUnlinked))
819         return 1;               /* bad inode? */
820
821     return 0;
822 }
823
824 struct dentry_operations afs_dentry_operations = {
825   .d_revalidate =       afs_linux_dentry_revalidate,
826   .d_delete =           afs_dentry_delete,
827   .d_iput =             afs_dentry_iput,
828 };
829
830 /**********************************************************************
831  * AFS Linux inode operations
832  **********************************************************************/
833
834 /* afs_linux_create
835  *
836  * Merely need to set enough of vattr to get us through the create. Note
837  * that the higher level code (open_namei) will take care of any tuncation
838  * explicitly. Exclusive open is also taken care of in open_namei.
839  *
840  * name is in kernel space at this point.
841  */
842 static int
843 #ifdef IOP_CREATE_TAKES_NAMEIDATA
844 afs_linux_create(struct inode *dip, struct dentry *dp, int mode,
845                  struct nameidata *nd)
846 #else
847 afs_linux_create(struct inode *dip, struct dentry *dp, int mode)
848 #endif
849 {
850     struct vattr vattr;
851     cred_t *credp = crref();
852     const char *name = dp->d_name.name;
853     struct vcache *vcp;
854     int code;
855
856     VATTR_NULL(&vattr);
857     vattr.va_mode = mode;
858     vattr.va_type = mode & S_IFMT;
859
860 #if defined(AFS_LINUX26_ENV)
861     lock_kernel();
862 #endif
863     AFS_GLOCK();
864     code = afs_create(VTOAFS(dip), (char *)name, &vattr, NONEXCL, mode,
865                       &vcp, credp);
866
867     if (!code) {
868         struct inode *ip = AFSTOV(vcp);
869
870         afs_getattr(vcp, &vattr, credp);
871         afs_fill_inode(ip, &vattr);
872         dp->d_op = &afs_dentry_operations;
873         dp->d_time = hgetlo(VTOAFS(dip)->m.DataVersion);
874         d_instantiate(dp, ip);
875     }
876     AFS_GUNLOCK();
877
878 #if defined(AFS_LINUX26_ENV)
879     unlock_kernel();
880 #endif
881     crfree(credp);
882     return -code;
883 }
884
885 /* afs_linux_lookup */
886 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
887 static struct dentry *
888 #ifdef IOP_LOOKUP_TAKES_NAMEIDATA
889 afs_linux_lookup(struct inode *dip, struct dentry *dp,
890                  struct nameidata *nd)
891 #else
892 afs_linux_lookup(struct inode *dip, struct dentry *dp)
893 #endif
894 #else
895 static int
896 afs_linux_lookup(struct inode *dip, struct dentry *dp)
897 #endif
898 {
899     cred_t *credp = crref();
900     struct vcache *vcp = NULL;
901     const char *comp = dp->d_name.name;
902     struct inode *ip = NULL;
903     int code;
904
905 #if defined(AFS_LINUX26_ENV)
906     lock_kernel();
907 #endif
908     AFS_GLOCK();
909     code = afs_lookup(VTOAFS(dip), comp, &vcp, credp);
910     
911     if (vcp) {
912         struct vattr vattr;
913
914         ip = AFSTOV(vcp);
915         afs_getattr(vcp, &vattr, credp);
916         afs_fill_inode(ip, &vattr);
917     }
918     dp->d_op = &afs_dentry_operations;
919     dp->d_time = hgetlo(VTOAFS(dip)->m.DataVersion);
920     AFS_GUNLOCK();
921
922 #if defined(AFS_LINUX24_ENV)
923     if (ip && S_ISDIR(ip->i_mode)) {
924         struct dentry *alias;
925
926         alias = d_find_alias(ip);
927         if (alias) {
928             if (d_invalidate(alias) == 0) {
929                 dput(alias);
930             } else {
931                 iput(ip);
932 #if defined(AFS_LINUX26_ENV)
933                 unlock_kernel();
934 #endif
935                 return alias;
936             }
937         }
938     }
939 #endif
940     d_add(dp, ip);
941
942 #if defined(AFS_LINUX26_ENV)
943     unlock_kernel();
944 #endif
945     crfree(credp);
946
947     /* It's ok for the file to not be found. That's noted by the caller by
948      * seeing that the dp->d_inode field is NULL.
949      */
950 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
951     if (code == ENOENT)
952         return ERR_PTR(0);
953     else
954         return ERR_PTR(-code);
955 #else
956     if (code == ENOENT)
957         code = 0;
958     return -code;
959 #endif
960 }
961
962 static int
963 afs_linux_link(struct dentry *olddp, struct inode *dip, struct dentry *newdp)
964 {
965     int code;
966     cred_t *credp = crref();
967     const char *name = newdp->d_name.name;
968     struct inode *oldip = olddp->d_inode;
969
970     /* If afs_link returned the vnode, we could instantiate the
971      * dentry. Since it's not, we drop this one and do a new lookup.
972      */
973     d_drop(newdp);
974
975     AFS_GLOCK();
976     code = afs_link(VTOAFS(oldip), VTOAFS(dip), name, credp);
977
978     AFS_GUNLOCK();
979     crfree(credp);
980     return -code;
981 }
982
983 static int
984 afs_linux_unlink(struct inode *dip, struct dentry *dp)
985 {
986     int code = EBUSY;
987     cred_t *credp = crref();
988     const char *name = dp->d_name.name;
989     struct vcache *tvc = VTOAFS(dp->d_inode);
990
991 #if defined(AFS_LINUX26_ENV)
992     lock_kernel();
993 #endif
994     if (VREFCOUNT(tvc) > 1 && tvc->opens > 0
995                                 && !(tvc->states & CUnlinked)) {
996         struct dentry *__dp;
997         char *__name;
998         extern char *afs_newname();
999
1000         __dp = NULL;
1001         __name = NULL;
1002         do {
1003             dput(__dp);
1004
1005             AFS_GLOCK();
1006             if (__name)
1007                 osi_FreeSmallSpace(__name);
1008             __name = afs_newname();
1009             AFS_GUNLOCK();
1010
1011             __dp = lookup_one_len(__name, dp->d_parent, strlen(__name));
1012                 
1013             if (IS_ERR(__dp))
1014                 goto out;
1015         } while (__dp->d_inode != NULL);
1016
1017         AFS_GLOCK();
1018         code = afs_rename(VTOAFS(dip), dp->d_name.name, VTOAFS(dip), __dp->d_name.name, credp);
1019         if (!code) {
1020             tvc->mvid = (void *) __name;
1021             crhold(credp);
1022             if (tvc->uncred) {
1023                 crfree(tvc->uncred);
1024             }
1025             tvc->uncred = credp;
1026             tvc->states |= CUnlinked;
1027         }
1028         AFS_GUNLOCK();
1029
1030         if (!code) {
1031             __dp->d_time = hgetlo(VTOAFS(dip)->m.DataVersion);
1032             d_move(dp, __dp);
1033         }
1034         dput(__dp);
1035
1036         goto out;
1037     }
1038
1039     AFS_GLOCK();
1040     code = afs_remove(VTOAFS(dip), name, credp);
1041     AFS_GUNLOCK();
1042     if (!code)
1043         d_drop(dp);
1044 out:
1045 #if defined(AFS_LINUX26_ENV)
1046     unlock_kernel();
1047 #endif
1048     crfree(credp);
1049     return -code;
1050 }
1051
1052
1053 static int
1054 afs_linux_symlink(struct inode *dip, struct dentry *dp, const char *target)
1055 {
1056     int code;
1057     cred_t *credp = crref();
1058     struct vattr vattr;
1059     const char *name = dp->d_name.name;
1060
1061     /* If afs_symlink returned the vnode, we could instantiate the
1062      * dentry. Since it's not, we drop this one and do a new lookup.
1063      */
1064     d_drop(dp);
1065
1066     VATTR_NULL(&vattr);
1067     AFS_GLOCK();
1068     code = afs_symlink(VTOAFS(dip), name, &vattr, target, credp);
1069     AFS_GUNLOCK();
1070     crfree(credp);
1071     return -code;
1072 }
1073
1074 static int
1075 afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode)
1076 {
1077     int code;
1078     cred_t *credp = crref();
1079     struct vcache *tvcp = NULL;
1080     struct vattr vattr;
1081     const char *name = dp->d_name.name;
1082
1083 #if defined(AFS_LINUX26_ENV)
1084     lock_kernel();
1085 #endif
1086     VATTR_NULL(&vattr);
1087     vattr.va_mask = ATTR_MODE;
1088     vattr.va_mode = mode;
1089     AFS_GLOCK();
1090     code = afs_mkdir(VTOAFS(dip), name, &vattr, &tvcp, credp);
1091
1092     if (tvcp) {
1093         struct inode *ip = AFSTOV(tvcp);
1094
1095         afs_getattr(tvcp, &vattr, credp);
1096         afs_fill_inode(ip, &vattr);
1097
1098         dp->d_op = &afs_dentry_operations;
1099         dp->d_time = hgetlo(VTOAFS(dip)->m.DataVersion);
1100         d_instantiate(dp, ip);
1101     }
1102     AFS_GUNLOCK();
1103
1104 #if defined(AFS_LINUX26_ENV)
1105     unlock_kernel();
1106 #endif
1107     crfree(credp);
1108     return -code;
1109 }
1110
1111 static int
1112 afs_linux_rmdir(struct inode *dip, struct dentry *dp)
1113 {
1114     int code;
1115     cred_t *credp = crref();
1116     const char *name = dp->d_name.name;
1117
1118     /* locking kernel conflicts with glock? */
1119
1120     AFS_GLOCK();
1121     code = afs_rmdir(VTOAFS(dip), name, credp);
1122     AFS_GUNLOCK();
1123
1124     /* Linux likes to see ENOTEMPTY returned from an rmdir() syscall
1125      * that failed because a directory is not empty. So, we map
1126      * EEXIST to ENOTEMPTY on linux.
1127      */
1128     if (code == EEXIST) {
1129         code = ENOTEMPTY;
1130     }
1131
1132     if (!code) {
1133         d_drop(dp);
1134     }
1135
1136     crfree(credp);
1137     return -code;
1138 }
1139
1140
1141 static int
1142 afs_linux_rename(struct inode *oldip, struct dentry *olddp,
1143                  struct inode *newip, struct dentry *newdp)
1144 {
1145     int code;
1146     cred_t *credp = crref();
1147     const char *oldname = olddp->d_name.name;
1148     const char *newname = newdp->d_name.name;
1149     struct dentry *rehash = NULL;
1150
1151 #if defined(AFS_LINUX26_ENV)
1152     /* Prevent any new references during rename operation. */
1153     lock_kernel();
1154 #endif
1155     /* Remove old and new entries from name hash. New one will change below.
1156      * While it's optimal to catch failures and re-insert newdp into hash,
1157      * it's also error prone and in that case we're already dealing with error
1158      * cases. Let another lookup put things right, if need be.
1159      */
1160 #if defined(AFS_LINUX26_ENV)
1161     if (!d_unhashed(newdp)) {
1162         d_drop(newdp);
1163         rehash = newdp;
1164     }
1165 #else
1166     if (!list_empty(&newdp->d_hash)) {
1167         d_drop(newdp);
1168         rehash = newdp;
1169     }
1170 #endif
1171
1172 #if defined(AFS_LINUX24_ENV)
1173     if (atomic_read(&olddp->d_count) > 1)
1174         shrink_dcache_parent(olddp);
1175 #endif
1176
1177     AFS_GLOCK();
1178     code = afs_rename(VTOAFS(oldip), oldname, VTOAFS(newip), newname, credp);
1179     AFS_GUNLOCK();
1180
1181     if (rehash)
1182         d_rehash(rehash);
1183
1184 #if defined(AFS_LINUX26_ENV)
1185     unlock_kernel();
1186 #endif
1187
1188     crfree(credp);
1189     return -code;
1190 }
1191
1192
1193 /* afs_linux_ireadlink 
1194  * Internal readlink which can return link contents to user or kernel space.
1195  * Note that the buffer is NOT supposed to be null-terminated.
1196  */
1197 static int
1198 afs_linux_ireadlink(struct inode *ip, char *target, int maxlen, uio_seg_t seg)
1199 {
1200     int code;
1201     cred_t *credp = crref();
1202     uio_t tuio;
1203     struct iovec iov;
1204
1205     setup_uio(&tuio, &iov, target, (afs_offs_t) 0, maxlen, UIO_READ, seg);
1206     code = afs_readlink(VTOAFS(ip), &tuio, credp);
1207     crfree(credp);
1208
1209     if (!code)
1210         return maxlen - tuio.uio_resid;
1211     else
1212         return -code;
1213 }
1214
1215 #if !defined(AFS_LINUX24_ENV)
1216 /* afs_linux_readlink 
1217  * Fill target (which is in user space) with contents of symlink.
1218  */
1219 static int
1220 afs_linux_readlink(struct dentry *dp, char *target, int maxlen)
1221 {
1222     int code;
1223     struct inode *ip = dp->d_inode;
1224
1225     AFS_GLOCK();
1226     code = afs_linux_ireadlink(ip, target, maxlen, AFS_UIOUSER);
1227     AFS_GUNLOCK();
1228     return code;
1229 }
1230
1231
1232 /* afs_linux_follow_link
1233  * a file system dependent link following routine.
1234  */
1235 static struct dentry *
1236 afs_linux_follow_link(struct dentry *dp, struct dentry *basep,
1237                       unsigned int follow)
1238 {
1239     int code = 0;
1240     char *name;
1241     struct dentry *res;
1242
1243
1244     AFS_GLOCK();
1245     name = osi_Alloc(PATH_MAX + 1);
1246     if (!name) {
1247         AFS_GUNLOCK();
1248         dput(basep);
1249         return ERR_PTR(-EIO);
1250     }
1251
1252     code = afs_linux_ireadlink(dp->d_inode, name, PATH_MAX, AFS_UIOSYS);
1253     AFS_GUNLOCK();
1254
1255     if (code < 0) {
1256         dput(basep);
1257         res = ERR_PTR(code);
1258     } else {
1259         name[code] = '\0';
1260         res = lookup_dentry(name, basep, follow);
1261     }
1262
1263     AFS_GLOCK();
1264     osi_Free(name, PATH_MAX + 1);
1265     AFS_GUNLOCK();
1266     return res;
1267 }
1268 #endif
1269
1270 /* afs_linux_readpage
1271  * all reads come through here. A strategy-like read call.
1272  */
1273 static int
1274 afs_linux_readpage(struct file *fp, struct page *pp)
1275 {
1276     int code;
1277     cred_t *credp = crref();
1278 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1279     char *address;
1280     afs_offs_t offset = ((loff_t) pp->index) << PAGE_CACHE_SHIFT;
1281 #else
1282     ulong address = afs_linux_page_address(pp);
1283     afs_offs_t offset = pageoff(pp);
1284 #endif
1285     uio_t tuio;
1286     struct iovec iovec;
1287     struct inode *ip = FILE_INODE(fp);
1288     int cnt = page_count(pp);
1289     struct vcache *avc = VTOAFS(ip);
1290
1291
1292 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1293     address = kmap(pp);
1294     ClearPageError(pp);
1295 #else
1296     atomic_add(1, &pp->count);
1297     set_bit(PG_locked, &pp->flags);     /* other bits? See mm.h */
1298     clear_bit(PG_error, &pp->flags);
1299 #endif
1300
1301     setup_uio(&tuio, &iovec, (char *)address, offset, PAGESIZE, UIO_READ,
1302               AFS_UIOSYS);
1303 #ifdef AFS_LINUX24_ENV
1304     lock_kernel();
1305 #endif
1306     AFS_GLOCK();
1307     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip, ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32, 99999); /* not a possible code value */
1308     code = afs_rdwr(avc, &tuio, UIO_READ, 0, credp);
1309     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip,
1310                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32,
1311                code);
1312     AFS_GUNLOCK();
1313 #ifdef AFS_LINUX24_ENV
1314     unlock_kernel();
1315 #endif
1316
1317     if (!code) {
1318         if (tuio.uio_resid)     /* zero remainder of page */
1319             memset((void *)(address + (PAGESIZE - tuio.uio_resid)), 0,
1320                    tuio.uio_resid);
1321 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1322         flush_dcache_page(pp);
1323         SetPageUptodate(pp);
1324 #else
1325         set_bit(PG_uptodate, &pp->flags);
1326 #endif
1327     }
1328
1329 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1330     kunmap(pp);
1331     UnlockPage(pp);
1332 #else
1333     clear_bit(PG_locked, &pp->flags);
1334     wake_up(&pp->wait);
1335     free_page(address);
1336 #endif
1337
1338     if (!code && AFS_CHUNKOFFSET(offset) == 0) {
1339         struct dcache *tdc;
1340         struct vrequest treq;
1341
1342         AFS_GLOCK();
1343         code = afs_InitReq(&treq, credp);
1344         if (!code && !NBObtainWriteLock(&avc->lock, 534)) {
1345             tdc = afs_FindDCache(avc, offset);
1346             if (tdc) {
1347                 if (!(tdc->mflags & DFNextStarted))
1348                     afs_PrefetchChunk(avc, tdc, credp, &treq);
1349                 afs_PutDCache(tdc);
1350             }
1351             ReleaseWriteLock(&avc->lock);
1352         }
1353         AFS_GUNLOCK();
1354     }
1355
1356     crfree(credp);
1357     return -code;
1358 }
1359
1360
1361 #if defined(AFS_LINUX24_ENV)
1362 static int
1363 afs_linux_writepage_sync(struct inode *ip, struct page *pp,
1364                          unsigned long offset, unsigned int count)
1365 {
1366     struct vcache *vcp = VTOAFS(ip);
1367     char *buffer;
1368     afs_offs_t base;
1369     int code = 0;
1370     cred_t *credp;
1371     uio_t tuio;
1372     struct iovec iovec;
1373     int f_flags = 0;
1374
1375     buffer = kmap(pp) + offset;
1376     base = (((loff_t) pp->index) << PAGE_CACHE_SHIFT)  + offset;
1377
1378     credp = crref();
1379     lock_kernel();
1380     AFS_GLOCK();
1381     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1382                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
1383                ICL_TYPE_INT32, 99999);
1384
1385     setup_uio(&tuio, &iovec, buffer, base, count, UIO_WRITE, AFS_UIOSYS);
1386
1387     code = afs_write(vcp, &tuio, f_flags, credp, 0);
1388
1389     ip->i_size = vcp->m.Length;
1390     ip->i_blocks = ((vcp->m.Length + 1023) >> 10) << 1;
1391
1392     if (!code) {
1393         struct vrequest treq;
1394
1395         ObtainWriteLock(&vcp->lock, 533);
1396         if (!afs_InitReq(&treq, credp))
1397             code = afs_DoPartialWrite(vcp, &treq);
1398         ReleaseWriteLock(&vcp->lock);
1399     }
1400     code = code ? -code : count - tuio.uio_resid;
1401
1402     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1403                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
1404                ICL_TYPE_INT32, code);
1405
1406     AFS_GUNLOCK();
1407     unlock_kernel();
1408     crfree(credp);
1409     kunmap(pp);
1410
1411     return code;
1412 }
1413
1414
1415 static int
1416 #ifdef AOP_WRITEPAGE_TAKES_WRITEBACK_CONTROL
1417 afs_linux_writepage(struct page *pp, struct writeback_control *wbc)
1418 #else
1419 afs_linux_writepage(struct page *pp)
1420 #endif
1421 {
1422     struct address_space *mapping = pp->mapping;
1423     struct inode *inode;
1424     unsigned long end_index;
1425     unsigned offset = PAGE_CACHE_SIZE;
1426     long status;
1427
1428 #if defined(AFS_LINUX26_ENV)
1429     if (PageReclaim(pp)) {
1430 # if defined(WRITEPAGE_ACTIVATE)
1431         return WRITEPAGE_ACTIVATE;
1432 # else 
1433         return AOP_WRITEPAGE_ACTIVATE;
1434 # endif
1435     }
1436 #else
1437     if (PageLaunder(pp)) {
1438         return(fail_writepage(pp));
1439     }
1440 #endif
1441
1442     inode = (struct inode *)mapping->host;
1443     end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1444
1445     /* easy case */
1446     if (pp->index < end_index)
1447         goto do_it;
1448     /* things got complicated... */
1449     offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
1450     /* OK, are we completely out? */
1451     if (pp->index >= end_index + 1 || !offset)
1452         return -EIO;
1453   do_it:
1454     status = afs_linux_writepage_sync(inode, pp, 0, offset);
1455     SetPageUptodate(pp);
1456     UnlockPage(pp);
1457     if (status == offset)
1458         return 0;
1459     else
1460         return status;
1461 }
1462 #else
1463 /* afs_linux_updatepage
1464  * What one would have thought was writepage - write dirty page to file.
1465  * Called from generic_file_write. buffer is still in user space. pagep
1466  * has been filled in with old data if we're updating less than a page.
1467  */
1468 static int
1469 afs_linux_updatepage(struct file *fp, struct page *pp, unsigned long offset,
1470                      unsigned int count, int sync)
1471 {
1472     struct vcache *vcp = VTOAFS(FILE_INODE(fp));
1473     u8 *page_addr = (u8 *) afs_linux_page_address(pp);
1474     int code = 0;
1475     cred_t *credp;
1476     uio_t tuio;
1477     struct iovec iovec;
1478
1479     set_bit(PG_locked, &pp->flags);
1480
1481     credp = crref();
1482     AFS_GLOCK();
1483     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1484                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
1485                ICL_TYPE_INT32, 99999);
1486     setup_uio(&tuio, &iovec, page_addr + offset,
1487               (afs_offs_t) (pageoff(pp) + offset), count, UIO_WRITE,
1488               AFS_UIOSYS);
1489
1490     code = afs_write(vcp, &tuio, fp->f_flags, credp, 0);
1491
1492     ip->i_size = vcp->m.Length;
1493     ip->i_blocks = ((vcp->m.Length + 1023) >> 10) << 1;
1494
1495     if (!code) {
1496         struct vrequest treq;
1497
1498         ObtainWriteLock(&vcp->lock, 533);
1499         vcp->m.Date = osi_Time();   /* set modification time */
1500         if (!afs_InitReq(&treq, credp))
1501             code = afs_DoPartialWrite(vcp, &treq);
1502         ReleaseWriteLock(&vcp->lock);
1503     }
1504
1505     code = code ? -code : count - tuio.uio_resid;
1506     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1507                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
1508                ICL_TYPE_INT32, code);
1509
1510     AFS_GUNLOCK();
1511     crfree(credp);
1512
1513     clear_bit(PG_locked, &pp->flags);
1514     return code;
1515 }
1516 #endif
1517
1518 /* afs_linux_permission
1519  * Check access rights - returns error if can't check or permission denied.
1520  */
1521 static int
1522 #ifdef IOP_PERMISSION_TAKES_NAMEIDATA
1523 afs_linux_permission(struct inode *ip, int mode, struct nameidata *nd)
1524 #else
1525 afs_linux_permission(struct inode *ip, int mode)
1526 #endif
1527 {
1528     int code;
1529     cred_t *credp = crref();
1530     int tmp = 0;
1531
1532     AFS_GLOCK();
1533     if (mode & MAY_EXEC)
1534         tmp |= VEXEC;
1535     if (mode & MAY_READ)
1536         tmp |= VREAD;
1537     if (mode & MAY_WRITE)
1538         tmp |= VWRITE;
1539     code = afs_access(VTOAFS(ip), tmp, credp);
1540
1541     AFS_GUNLOCK();
1542     crfree(credp);
1543     return -code;
1544 }
1545
1546 #if defined(AFS_LINUX24_ENV)
1547 static int
1548 afs_linux_commit_write(struct file *file, struct page *page, unsigned offset,
1549                        unsigned to)
1550 {
1551     int code;
1552
1553     code = afs_linux_writepage_sync(file->f_dentry->d_inode, page,
1554                                     offset, to - offset);
1555 #if !defined(AFS_LINUX26_ENV)
1556     kunmap(page);
1557 #endif
1558
1559     return code;
1560 }
1561
1562 static int
1563 afs_linux_prepare_write(struct file *file, struct page *page, unsigned from,
1564                         unsigned to)
1565 {
1566 /* sometime between 2.4.0 and 2.4.19, the callers of prepare_write began to
1567    call kmap directly instead of relying on us to do it */
1568 #if !defined(AFS_LINUX26_ENV)
1569     kmap(page);
1570 #endif
1571     return 0;
1572 }
1573
1574 extern int afs_notify_change(struct dentry *dp, struct iattr *iattrp);
1575 #endif
1576
1577 static struct inode_operations afs_file_iops = {
1578 #if defined(AFS_LINUX26_ENV)
1579   .permission =         afs_linux_permission,
1580   .getattr =            afs_linux_getattr,
1581   .setattr =            afs_notify_change,
1582 #elif defined(AFS_LINUX24_ENV)
1583   .permission =         afs_linux_permission,
1584   .revalidate =         afs_linux_revalidate,
1585   .setattr =            afs_notify_change,
1586 #else
1587   .default_file_ops =   &afs_file_fops,
1588   .readpage =           afs_linux_readpage,
1589   .revalidate =         afs_linux_revalidate,
1590   .updatepage =         afs_linux_updatepage,
1591 #endif
1592 };
1593
1594 #if defined(AFS_LINUX24_ENV)
1595 static struct address_space_operations afs_file_aops = {
1596   .readpage =           afs_linux_readpage,
1597   .writepage =          afs_linux_writepage,
1598   .commit_write =       afs_linux_commit_write,
1599   .prepare_write =      afs_linux_prepare_write,
1600 };
1601 #endif
1602
1603
1604 /* Separate ops vector for directories. Linux 2.2 tests type of inode
1605  * by what sort of operation is allowed.....
1606  */
1607
1608 static struct inode_operations afs_dir_iops = {
1609 #if !defined(AFS_LINUX24_ENV)
1610   .default_file_ops =   &afs_dir_fops,
1611 #else
1612   .setattr =            afs_notify_change,
1613 #endif
1614   .create =             afs_linux_create,
1615   .lookup =             afs_linux_lookup,
1616   .link =               afs_linux_link,
1617   .unlink =             afs_linux_unlink,
1618   .symlink =            afs_linux_symlink,
1619   .mkdir =              afs_linux_mkdir,
1620   .rmdir =              afs_linux_rmdir,
1621   .rename =             afs_linux_rename,
1622 #if defined(AFS_LINUX26_ENV)
1623   .getattr =            afs_linux_getattr,
1624 #else
1625   .revalidate =         afs_linux_revalidate,
1626 #endif
1627   .permission =         afs_linux_permission,
1628 };
1629
1630 /* We really need a separate symlink set of ops, since do_follow_link()
1631  * determines if it _is_ a link by checking if the follow_link op is set.
1632  */
1633 #if defined(AFS_LINUX24_ENV)
1634 static int
1635 afs_symlink_filler(struct file *file, struct page *page)
1636 {
1637     struct inode *ip = (struct inode *)page->mapping->host;
1638     char *p = (char *)kmap(page);
1639     int code;
1640
1641     lock_kernel();
1642     AFS_GLOCK();
1643     code = afs_linux_ireadlink(ip, p, PAGE_SIZE, AFS_UIOSYS);
1644     AFS_GUNLOCK();
1645
1646     if (code < 0)
1647         goto fail;
1648     p[code] = '\0';             /* null terminate? */
1649     unlock_kernel();
1650
1651     SetPageUptodate(page);
1652     kunmap(page);
1653     UnlockPage(page);
1654     return 0;
1655
1656   fail:
1657     unlock_kernel();
1658
1659     SetPageError(page);
1660     kunmap(page);
1661     UnlockPage(page);
1662     return code;
1663 }
1664
1665 static struct address_space_operations afs_symlink_aops = {
1666   .readpage =   afs_symlink_filler
1667 };
1668 #endif
1669
1670 static struct inode_operations afs_symlink_iops = {
1671 #if defined(AFS_LINUX24_ENV)
1672   .readlink =           page_readlink,
1673 #if defined(HAVE_KERNEL_PAGE_FOLLOW_LINK)
1674   .follow_link =        page_follow_link,
1675 #else
1676   .follow_link =        page_follow_link_light,
1677   .put_link =           page_put_link,
1678 #endif
1679   .setattr =            afs_notify_change,
1680 #else
1681   .readlink =           afs_linux_readlink,
1682   .follow_link =        afs_linux_follow_link,
1683   .permission =         afs_linux_permission,
1684   .revalidate =         afs_linux_revalidate,
1685 #endif
1686 };
1687
1688 void
1689 afs_fill_inode(struct inode *ip, struct vattr *vattr)
1690 {
1691         
1692     if (vattr)
1693         vattr2inode(ip, vattr);
1694
1695 /* Reset ops if symlink or directory. */
1696     if (S_ISREG(ip->i_mode)) {
1697         ip->i_op = &afs_file_iops;
1698 #if defined(AFS_LINUX24_ENV)
1699         ip->i_fop = &afs_file_fops;
1700         ip->i_data.a_ops = &afs_file_aops;
1701 #endif
1702
1703     } else if (S_ISDIR(ip->i_mode)) {
1704         ip->i_op = &afs_dir_iops;
1705 #if defined(AFS_LINUX24_ENV)
1706         ip->i_fop = &afs_dir_fops;
1707 #endif
1708
1709     } else if (S_ISLNK(ip->i_mode)) {
1710         ip->i_op = &afs_symlink_iops;
1711 #if defined(AFS_LINUX24_ENV)
1712         ip->i_data.a_ops = &afs_symlink_aops;
1713         ip->i_mapping = &ip->i_data;
1714 #endif
1715     }
1716
1717     /* insert_inode_hash(ip);   -- this would make iget() work (if we used it) */
1718 }