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