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