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