8e965957cab967371b4b6fa85bbe6b15a6190ea2
[openafs.git] / src / afs / LINUX24 / osi_file.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 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #ifdef AFS_LINUX24_ENV
15 #include "h/module.h" /* early to avoid printf->printk mapping */
16 #endif
17 #include "afs/sysincludes.h"    /* Standard vendor system headers */
18 #include "afsincludes.h"        /* Afs-based standard headers */
19 #include "afs/afs_stats.h"      /* afs statistics */
20 #include "h/smp_lock.h"
21 #if defined(AFS_LINUX26_ENV)
22 #include "h/namei.h"
23 #endif
24 #if defined(LINUX_USE_FH)
25 #include "h/exportfs.h"
26 int cache_fh_type = -1;
27 int cache_fh_len = -1;
28 #endif
29
30 afs_lock_t afs_xosi;            /* lock is for tvattr */
31 extern struct osi_dev cacheDev;
32 #if defined(AFS_LINUX24_ENV)
33 extern struct vfsmount *afs_cacheMnt;
34 #endif
35 extern struct super_block *afs_cacheSBp;
36
37 #if defined(AFS_LINUX26_ENV) 
38 struct file *
39 afs_linux_raw_open(afs_dcache_id_t *ainode)
40 {
41     struct inode *tip = NULL;
42     struct dentry *dp = NULL;
43     struct file* filp;
44
45 #if !defined(LINUX_USE_FH)
46     tip = iget(afs_cacheSBp, ainode->ufs);
47     if (!tip)
48         osi_Panic("Can't get inode %d\n", (int) ainode->ufs);
49
50     dp = d_alloc_anon(tip);
51 #else
52     dp = afs_cacheSBp->s_export_op->fh_to_dentry(afs_cacheSBp, &ainode->ufs.fh,
53                                                  cache_fh_len, cache_fh_type);
54     if (!dp)
55            osi_Panic("Can't get dentry\n");
56     tip = dp->d_inode;
57 #endif
58
59 #if defined(S_NOATIME)
60     tip->i_flags |= S_NOATIME; /* Disable updating access times. */
61 #else
62     tip->i_flags |= MS_NOATIME; /* Disable updating access times. */
63 #endif
64
65 #if defined(STRUCT_TASK_HAS_CRED)
66     filp = dentry_open(dp, mntget(afs_cacheMnt), O_RDWR, current_cred());
67 #else
68     filp = dentry_open(dp, mntget(afs_cacheMnt), O_RDWR);
69 #endif
70     if (IS_ERR(filp))
71 #if defined(LINUX_USE_FH)
72         osi_Panic("Can't open file\n");
73 #else
74         osi_Panic("Can't open inode %d\n", (int) ainode->ufs);
75 #endif
76     return filp;
77 }
78
79 void *
80 osi_UFSOpen(afs_dcache_id_t *ainode)
81 {
82     struct osi_file *afile = NULL;
83     extern int cacheDiskType;
84     struct file *filp = NULL;
85     AFS_STATCNT(osi_UFSOpen);
86     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
87         osi_Panic("UFSOpen called for non-UFS cache\n");
88     }
89     if (!afs_osicred_initialized) {
90         /* valid for alpha_osf, SunOS, Ultrix */
91         memset(&afs_osi_cred, 0, sizeof(afs_ucred_t));
92         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
93         afs_osicred_initialized = 1;
94     }
95     afile = (struct osi_file *)osi_AllocLargeSpace(sizeof(struct osi_file));
96     AFS_GUNLOCK();
97     if (!afile) {
98         osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n",
99                   (int)sizeof(struct osi_file));
100     }
101     memset(afile, 0, sizeof(struct osi_file));
102
103     afile->filp = afs_linux_raw_open(ainode);
104     afile->size = i_size_read(FILE_INODE(afile->filp));
105     AFS_GLOCK();
106     afile->offset = 0;
107     afile->proc = (int (*)())0;
108     return (void *)afile;
109 }
110 #else
111 void *
112 osi_UFSOpen(afs_dcache_id_t *ainode)
113 {
114     register struct osi_file *afile = NULL;
115     extern int cacheDiskType;
116     afs_int32 code = 0;
117     struct inode *tip = NULL;
118     struct file *filp = NULL;
119     AFS_STATCNT(osi_UFSOpen);
120     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
121         osi_Panic("UFSOpen called for non-UFS cache\n");
122     }
123     if (!afs_osicred_initialized) {
124         /* valid for alpha_osf, SunOS, Ultrix */
125         memset(&afs_osi_cred, 0, sizeof(afs_ucred_t));
126         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
127         afs_osicred_initialized = 1;
128     }
129     afile = (struct osi_file *)osi_AllocLargeSpace(sizeof(struct osi_file));
130     AFS_GUNLOCK();
131     if (!afile) {
132         osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n",
133                   sizeof(struct osi_file));
134     }
135     memset(afile, 0, sizeof(struct osi_file));
136     filp = &afile->file;
137     filp->f_dentry = &afile->dentry;
138     tip = iget(afs_cacheSBp, ainode->ufs);
139     if (!tip)
140         osi_Panic("Can't get inode %d\n", ainode->ufs);
141     FILE_INODE(filp) = tip;
142     tip->i_flags |= MS_NOATIME; /* Disable updating access times. */
143     filp->f_flags = O_RDWR;
144 #if defined(AFS_LINUX24_ENV)
145     filp->f_mode = FMODE_READ|FMODE_WRITE;
146     filp->f_op = fops_get(tip->i_fop);
147 #else
148     filp->f_op = tip->i_op->default_file_ops;
149 #endif
150     if (filp->f_op && filp->f_op->open)
151         code = filp->f_op->open(tip, filp);
152     if (code)
153         osi_Panic("Can't open inode %d\n", ainode->ufs);
154     afile->size = i_size_read(tip);
155     AFS_GLOCK();
156     afile->offset = 0;
157     afile->proc = (int (*)())0;
158     return (void *)afile;
159 }
160 #endif
161
162 #if defined(LINUX_USE_FH)
163 /*
164  * Given a dentry, return the file handle as encoded by the filesystem.
165  * We can't assume anything about the length (words, not bytes).
166  * The cache has to live on a single filesystem with uniform file 
167  * handles, otherwise we panic.
168  */
169 void osi_get_fh(struct dentry *dp, afs_ufs_dcache_id_t *ainode) {
170     int max_len;
171     int type;
172
173     if (cache_fh_len > 0)
174         max_len = cache_fh_len;
175     else
176         max_len = MAX_FH_LEN;
177     if (dp->d_sb->s_export_op->encode_fh) {
178         type = dp->d_sb->s_export_op->encode_fh(dp, &ainode->raw[0], &max_len, 0);
179         if (type == 255) {
180            osi_Panic("File handle encoding failed\n");
181         }
182         if (cache_fh_type < 0)
183             cache_fh_type = type;
184         if (cache_fh_len < 0) {
185             cache_fh_len = max_len;
186         }
187         if (type != cache_fh_type || max_len != cache_fh_len) {
188            osi_Panic("Inconsistent file handles within cache\n");
189         }
190     } else {
191          /* If fs doesn't provide an encode_fh method, assume the default INO32 type */
192         if (cache_fh_type < 0)
193             cache_fh_type = FILEID_INO32_GEN;
194         if (cache_fh_len < 0)
195             cache_fh_len = sizeof(struct fid)/4;
196         ainode->fh.i32.ino = dp->d_inode->i_ino;
197         ainode->fh.i32.gen = dp->d_inode->i_generation;
198     }
199 }
200 #else
201 void osi_get_fh(struct dentry *dp, afs_ufs_dcache_id_t *ainode) {
202     *ainode = dp->d_inode->i_ino;
203 }
204 #endif
205
206 int
207 afs_osi_Stat(register struct osi_file *afile, register struct osi_stat *astat)
208 {
209     register afs_int32 code;
210     AFS_STATCNT(osi_Stat);
211     ObtainWriteLock(&afs_xosi, 320);
212     astat->size = i_size_read(OSIFILE_INODE(afile));
213 #if defined(AFS_LINUX26_ENV)
214     astat->mtime = OSIFILE_INODE(afile)->i_mtime.tv_sec;
215     astat->atime = OSIFILE_INODE(afile)->i_atime.tv_sec;
216 #else
217     astat->mtime = OSIFILE_INODE(afile)->i_mtime;
218     astat->atime = OSIFILE_INODE(afile)->i_atime;
219 #endif
220     code = 0;
221     ReleaseWriteLock(&afs_xosi);
222     return code;
223 }
224
225 #ifdef AFS_LINUX26_ENV
226 int
227 osi_UFSClose(register struct osi_file *afile)
228 {
229     AFS_STATCNT(osi_Close);
230     if (afile) {
231         if (OSIFILE_INODE(afile)) {
232             filp_close(afile->filp, NULL);
233         }
234     }
235
236     osi_FreeLargeSpace(afile);
237     return 0;
238 }
239 #else
240 int
241 osi_UFSClose(register struct osi_file *afile)
242 {
243     AFS_STATCNT(osi_Close);
244     if (afile) {
245         if (FILE_INODE(&afile->file)) {
246             struct file *filp = &afile->file;
247             if (filp->f_op && filp->f_op->release)
248                 filp->f_op->release(FILE_INODE(filp), filp);
249             iput(FILE_INODE(filp));
250         }
251     }
252
253     osi_FreeLargeSpace(afile);
254     return 0;
255 }
256 #endif
257
258 int
259 osi_UFSTruncate(register struct osi_file *afile, afs_int32 asize)
260 {
261     register afs_int32 code;
262     struct osi_stat tstat;
263     struct iattr newattrs;
264     struct inode *inode = OSIFILE_INODE(afile);
265     AFS_STATCNT(osi_Truncate);
266
267     /* This routine only shrinks files, and most systems
268      * have very slow truncates, even when the file is already
269      * small enough.  Check now and save some time.
270      */
271     code = afs_osi_Stat(afile, &tstat);
272     if (code || tstat.size <= asize)
273         return code;
274     ObtainWriteLock(&afs_xosi, 321);
275     AFS_GUNLOCK();
276 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
277     down_write(&inode->i_alloc_sem);
278 #endif
279 #ifdef STRUCT_INODE_HAS_I_MUTEX
280     mutex_lock(&inode->i_mutex);
281 #else
282     down(&inode->i_sem);
283 #endif
284     newattrs.ia_size = asize;
285     newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
286 #if defined(AFS_LINUX24_ENV)
287     newattrs.ia_ctime = CURRENT_TIME;
288
289     /* avoid notify_change() since it wants to update dentry->d_parent */
290     lock_kernel();
291     code = inode_change_ok(inode, &newattrs);
292     if (!code) {
293 #ifdef INODE_SETATTR_NOT_VOID
294 #if defined(AFS_LINUX26_ENV)
295         if (inode->i_op && inode->i_op->setattr)
296             code = inode->i_op->setattr(afile->filp->f_dentry, &newattrs);
297         else
298 #endif
299             code = inode_setattr(inode, &newattrs);
300 #else
301         inode_setattr(inode, &newattrs);
302 #endif
303     }
304     unlock_kernel();
305     if (!code)
306         truncate_inode_pages(&inode->i_data, asize);
307 #else
308     i_size_write(inode, asize);
309     if (inode->i_sb->s_op && inode->i_sb->s_op->notify_change) {
310         code = inode->i_sb->s_op->notify_change(&afile->dentry, &newattrs);
311     }
312     if (!code) {
313         truncate_inode_pages(inode, asize);
314         if (inode->i_op && inode->i_op->truncate)
315             inode->i_op->truncate(inode);
316     }
317 #endif
318     code = -code;
319 #ifdef STRUCT_INODE_HAS_I_MUTEX
320     mutex_unlock(&inode->i_mutex);
321 #else
322     up(&inode->i_sem);
323 #endif
324 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
325     up_write(&inode->i_alloc_sem);
326 #endif
327     AFS_GLOCK();
328     ReleaseWriteLock(&afs_xosi);
329     return code;
330 }
331
332
333 /* Generic read interface */
334 int
335 afs_osi_Read(register struct osi_file *afile, int offset, void *aptr,
336              afs_int32 asize)
337 {
338     struct uio auio;
339     struct iovec iov;
340     afs_int32 code;
341
342     AFS_STATCNT(osi_Read);
343
344     /*
345      * If the osi_file passed in is NULL, panic only if AFS is not shutting
346      * down. No point in crashing when we are already shutting down
347      */
348     if (!afile) {
349         if (!afs_shuttingdown)
350             osi_Panic("osi_Read called with null param");
351         else
352             return EIO;
353     }
354
355     if (offset != -1)
356         afile->offset = offset;
357     setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_READ, AFS_UIOSYS);
358     AFS_GUNLOCK();
359     code = osi_rdwr(afile, &auio, UIO_READ);
360     AFS_GLOCK();
361     if (code == 0) {
362         code = asize - auio.uio_resid;
363         afile->offset += code;
364     } else {
365         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, auio.uio_resid,
366                    ICL_TYPE_INT32, code);
367         code = -1;
368     }
369     return code;
370 }
371
372 /* Generic write interface */
373 int
374 afs_osi_Write(register struct osi_file *afile, afs_int32 offset, void *aptr,
375               afs_int32 asize)
376 {
377     struct uio auio;
378     struct iovec iov;
379     afs_int32 code;
380
381     AFS_STATCNT(osi_Write);
382
383     if (!afile) {
384         if (!afs_shuttingdown)
385             osi_Panic("afs_osi_Write called with null param");
386         else
387             return EIO;
388     }
389
390     if (offset != -1)
391         afile->offset = offset;
392     setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_WRITE, AFS_UIOSYS);
393     AFS_GUNLOCK();
394     code = osi_rdwr(afile, &auio, UIO_WRITE);
395     AFS_GLOCK();
396     if (code == 0) {
397         code = asize - auio.uio_resid;
398         afile->offset += code;
399     } else {
400         if (code == ENOSPC)
401             afs_warnuser
402                 ("\n\n\n*** Cache partition is FULL - Decrease cachesize!!! ***\n\n");
403         code = -1;
404     }
405
406     if (afile->proc)
407         (*afile->proc)(afile, code);
408
409     return code;
410 }
411
412
413 /*  This work should be handled by physstrat in ca/machdep.c.
414     This routine written from the RT NFS port strategy routine.
415     It has been generalized a bit, but should still be pretty clear. */
416 int
417 afs_osi_MapStrategy(int (*aproc) (struct buf * bp), register struct buf *bp)
418 {
419     afs_int32 returnCode;
420
421     AFS_STATCNT(osi_MapStrategy);
422     returnCode = (*aproc) (bp);
423
424     return returnCode;
425 }
426
427 void
428 shutdown_osifile(void)
429 {
430     AFS_STATCNT(shutdown_osifile);
431     if (afs_cold_shutdown) {
432         afs_osicred_initialized = 0;
433     }
434 }
435
436 /* Intialize cache device info and fragment size for disk cache partition. */
437 int
438 osi_InitCacheInfo(char *aname)
439 {
440     int code;
441     extern afs_dcache_id_t cacheInode;
442     struct dentry *dp;
443     extern struct osi_dev cacheDev;
444     extern afs_int32 afs_fsfragsize;
445     extern struct super_block *afs_cacheSBp;
446     extern struct vfsmount *afs_cacheMnt;
447     code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp);
448     if (code)
449         return ENOENT;
450
451     osi_get_fh(dp, &cacheInode.ufs);
452     cacheDev.dev = dp->d_inode->i_sb->s_dev;
453     afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
454     afs_cacheSBp = dp->d_inode->i_sb;
455
456     dput(dp);
457
458     return 0;
459 }
460
461
462 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
463 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
464
465 /* osi_rdwr
466  * seek, then read or write to an open inode. addrp points to data in
467  * kernel space.
468  */
469 int
470 osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
471 {
472 #ifdef AFS_LINUX26_ENV
473     struct file *filp = osifile->filp;
474 #else
475     struct file *filp = &osifile->file;
476 #endif
477     KERNEL_SPACE_DECL;
478     int code = 0;
479     struct iovec *iov;
480     afs_size_t count;
481     unsigned long savelim;
482
483     savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
484     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
485
486     if (uiop->uio_seg == AFS_UIOSYS)
487         TO_USER_SPACE();
488
489     /* seek to the desired position. Return -1 on error. */
490     if (filp->f_op->llseek) {
491         if (filp->f_op->llseek(filp, (loff_t) uiop->uio_offset, 0) != uiop->uio_offset)
492             return -1;
493     } else
494         filp->f_pos = uiop->uio_offset;
495
496     while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
497         iov = uiop->uio_iov;
498         count = iov->iov_len;
499         if (count == 0) {
500             uiop->uio_iov++;
501             uiop->uio_iovcnt--;
502             continue;
503         }
504
505         if (rw == UIO_READ)
506             code = FOP_READ(filp, iov->iov_base, count);
507         else
508             code = FOP_WRITE(filp, iov->iov_base, count);
509
510         if (code < 0) {
511             code = -code;
512             break;
513         } else if (code == 0) {
514             /*
515              * This is bad -- we can't read any more data from the
516              * file, but we have no good way of signaling a partial
517              * read either.
518              */
519             code = EIO;
520             break;
521         }
522
523         iov->iov_base += code;
524         iov->iov_len -= code;
525         uiop->uio_resid -= code;
526         uiop->uio_offset += code;
527         code = 0;
528     }
529
530     if (uiop->uio_seg == AFS_UIOSYS)
531         TO_KERNEL_SPACE();
532
533     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
534
535     return code;
536 }
537
538 /* setup_uio 
539  * Setup a uio struct.
540  */
541 void
542 setup_uio(uio_t * uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos,
543           int count, uio_flag_t flag, uio_seg_t seg)
544 {
545     iovecp->iov_base = (char *)buf;
546     iovecp->iov_len = count;
547     uiop->uio_iov = iovecp;
548     uiop->uio_iovcnt = 1;
549     uiop->uio_offset = pos;
550     uiop->uio_seg = seg;
551     uiop->uio_resid = count;
552     uiop->uio_flag = flag;
553 }
554
555
556 /* uiomove
557  * UIO_READ : dp -> uio
558  * UIO_WRITE : uio -> dp
559  */
560 int
561 uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
562 {
563     int count;
564     struct iovec *iov;
565     int code;
566
567     while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
568         iov = uiop->uio_iov;
569         count = iov->iov_len;
570
571         if (!count) {
572             uiop->uio_iov++;
573             uiop->uio_iovcnt--;
574             continue;
575         }
576
577         if (count > length)
578             count = length;
579
580         switch (uiop->uio_seg) {
581         case AFS_UIOSYS:
582             switch (rw) {
583             case UIO_READ:
584                 memcpy(iov->iov_base, dp, count);
585                 break;
586             case UIO_WRITE:
587                 memcpy(dp, iov->iov_base, count);
588                 break;
589             default:
590                 printf("uiomove: Bad rw = %d\n", rw);
591                 return -EINVAL;
592             }
593             break;
594         case AFS_UIOUSER:
595             switch (rw) {
596             case UIO_READ:
597                 AFS_COPYOUT(dp, iov->iov_base, count, code);
598                 break;
599             case UIO_WRITE:
600                 AFS_COPYIN(iov->iov_base, dp, count, code);
601                 break;
602             default:
603                 printf("uiomove: Bad rw = %d\n", rw);
604                 return -EINVAL;
605             }
606             break;
607         default:
608             printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
609             return -EINVAL;
610         }
611
612         dp += count;
613         length -= count;
614         iov->iov_base += count;
615         iov->iov_len -= count;
616         uiop->uio_offset += count;
617         uiop->uio_resid -= count;
618     }
619     return 0;
620 }
621