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