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