Commit | Line | Data |
---|---|---|
805e021f CE |
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 | #include <linux/module.h> /* early to avoid printf->printk mapping */ | |
15 | #include "afs/sysincludes.h" /* Standard vendor system headers */ | |
16 | #include "afsincludes.h" /* Afs-based standard headers */ | |
17 | #include "afs/afs_stats.h" /* afs statistics */ | |
18 | #include <linux/namei.h> | |
19 | ||
20 | #if defined(HAVE_LINUX_EXPORTFS_H) | |
21 | #include <linux/exportfs.h> | |
22 | #endif | |
23 | #include "osi_compat.h" | |
24 | ||
25 | #ifndef CURRENT_TIME | |
26 | # if defined(HAVE_LINUX_KTIME_GET_COARSE_REAL_TS64) | |
27 | # define AFS_CURRENT_TIME(x) (ktime_get_coarse_real_ts64((x))) | |
28 | # else | |
29 | # ifdef IATTR_TAKES_64BIT_TIME | |
30 | # define AFS_CURRENT_TIME(x) do {*(x) = current_kernel_time64();} while (0) | |
31 | # else | |
32 | # define AFS_CURRENT_TIME(x) do {*(x) = current_kernel_time();} while (0) | |
33 | # endif | |
34 | # endif | |
35 | #else | |
36 | # define AFS_CURRENT_TIME(x) do {*(x) = CURRENT_TIME;} while(0) | |
37 | #endif | |
38 | ||
39 | int cache_fh_type = -1; | |
40 | int cache_fh_len = -1; | |
41 | ||
42 | extern struct osi_dev cacheDev; | |
43 | extern struct vfsmount *afs_cacheMnt; | |
44 | extern struct super_block *afs_cacheSBp; | |
45 | #if defined(STRUCT_TASK_STRUCT_HAS_CRED) | |
46 | extern struct cred *cache_creds; | |
47 | #endif | |
48 | ||
49 | /* Old export ops: decode_fh will call back here. Accept any dentry it suggests */ | |
50 | int | |
51 | afs_fh_acceptable(void *context, struct dentry *dp) | |
52 | { | |
53 | return 1; | |
54 | } | |
55 | ||
56 | struct file * | |
57 | afs_linux_raw_open(afs_dcache_id_t *ainode) | |
58 | { | |
59 | struct inode *tip = NULL; | |
60 | struct dentry *dp = NULL; | |
61 | struct file* filp; | |
62 | ||
63 | dp = afs_get_dentry_from_fh(afs_cacheSBp, ainode, cache_fh_len, cache_fh_type, | |
64 | afs_fh_acceptable); | |
65 | if ((!dp) || IS_ERR(dp)) | |
66 | osi_Panic("Can't get dentry\n"); | |
67 | tip = dp->d_inode; | |
68 | tip->i_flags |= S_NOATIME; /* Disable updating access times. */ | |
69 | ||
70 | #if defined(STRUCT_TASK_STRUCT_HAS_CRED) | |
71 | /* Use stashed credentials - prevent selinux/apparmor problems */ | |
72 | filp = afs_dentry_open(dp, afs_cacheMnt, O_RDWR, cache_creds); | |
73 | if (IS_ERR(filp)) | |
74 | filp = afs_dentry_open(dp, afs_cacheMnt, O_RDWR, current_cred()); | |
75 | #else | |
76 | filp = dentry_open(dget(dp), mntget(afs_cacheMnt), O_RDWR); | |
77 | #endif | |
78 | if (IS_ERR(filp)) { | |
79 | afs_warn("afs: Cannot open cache file (code %d). Trying to continue, " | |
80 | "but AFS accesses may return errors or panic the system\n", | |
81 | (int) PTR_ERR(filp)); | |
82 | filp = NULL; | |
83 | } | |
84 | ||
85 | dput(dp); | |
86 | ||
87 | return filp; | |
88 | } | |
89 | ||
90 | void * | |
91 | osi_UFSOpen(afs_dcache_id_t *ainode) | |
92 | { | |
93 | struct osi_file *afile = NULL; | |
94 | extern int cacheDiskType; | |
95 | ||
96 | AFS_STATCNT(osi_UFSOpen); | |
97 | if (cacheDiskType != AFS_FCACHE_TYPE_UFS) { | |
98 | osi_Panic("UFSOpen called for non-UFS cache\n"); | |
99 | } | |
100 | if (!afs_osicred_initialized) { | |
101 | /* valid for alpha_osf, SunOS, Ultrix */ | |
102 | memset(&afs_osi_cred, 0, sizeof(afs_ucred_t)); | |
103 | crhold(&afs_osi_cred); /* don't let it evaporate, since it is static */ | |
104 | afs_osicred_initialized = 1; | |
105 | } | |
106 | AFS_GUNLOCK(); | |
107 | afile = kmalloc(sizeof(struct osi_file), GFP_NOFS); | |
108 | if (!afile) { | |
109 | osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n", | |
110 | (int)sizeof(struct osi_file)); | |
111 | } | |
112 | memset(afile, 0, sizeof(struct osi_file)); | |
113 | ||
114 | afile->filp = afs_linux_raw_open(ainode); | |
115 | if (afile->filp) { | |
116 | afile->size = i_size_read(FILE_INODE(afile->filp)); | |
117 | } | |
118 | AFS_GLOCK(); | |
119 | ||
120 | if (!afile->filp) { | |
121 | osi_FreeLargeSpace(afile); | |
122 | return NULL; | |
123 | } | |
124 | ||
125 | afile->offset = 0; | |
126 | afile->proc = (int (*)())0; | |
127 | return (void *)afile; | |
128 | } | |
129 | ||
130 | /* | |
131 | * Given a dentry, return the file handle as encoded by the filesystem. | |
132 | * We can't assume anything about the length (words, not bytes). | |
133 | * The cache has to live on a single filesystem with uniform file | |
134 | * handles, otherwise we panic. | |
135 | */ | |
136 | void osi_get_fh(struct dentry *dp, afs_ufs_dcache_id_t *ainode) { | |
137 | int max_len; | |
138 | int type; | |
139 | ||
140 | if (cache_fh_len > 0) | |
141 | max_len = cache_fh_len; | |
142 | else | |
143 | max_len = MAX_FH_LEN; | |
144 | type = afs_get_fh_from_dentry(dp, ainode, &max_len); | |
145 | if (type == 255) { | |
146 | osi_Panic("File handle encoding failed\n"); | |
147 | } | |
148 | if (cache_fh_type < 0) | |
149 | cache_fh_type = type; | |
150 | if (cache_fh_len < 0) { | |
151 | cache_fh_len = max_len; | |
152 | } | |
153 | if (type != cache_fh_type || max_len != cache_fh_len) { | |
154 | osi_Panic("Inconsistent file handles within cache\n"); | |
155 | } | |
156 | } | |
157 | ||
158 | int | |
159 | afs_osi_Stat(struct osi_file *afile, struct osi_stat *astat) | |
160 | { | |
161 | AFS_STATCNT(osi_Stat); | |
162 | astat->size = i_size_read(OSIFILE_INODE(afile)); | |
163 | astat->mtime = OSIFILE_INODE(afile)->i_mtime.tv_sec; | |
164 | astat->atime = OSIFILE_INODE(afile)->i_atime.tv_sec; | |
165 | ||
166 | return 0; | |
167 | } | |
168 | ||
169 | int | |
170 | osi_UFSClose(struct osi_file *afile) | |
171 | { | |
172 | AFS_STATCNT(osi_Close); | |
173 | if (afile) { | |
174 | if (OSIFILE_INODE(afile)) { | |
175 | filp_close(afile->filp, NULL); | |
176 | } | |
177 | } | |
178 | kfree(afile); | |
179 | return 0; | |
180 | } | |
181 | ||
182 | int | |
183 | osi_UFSTruncate(struct osi_file *afile, afs_int32 asize) | |
184 | { | |
185 | afs_int32 code; | |
186 | struct osi_stat tstat; | |
187 | struct iattr newattrs; | |
188 | struct inode *inode = OSIFILE_INODE(afile); | |
189 | AFS_STATCNT(osi_Truncate); | |
190 | ||
191 | /* This routine only shrinks files, and most systems | |
192 | * have very slow truncates, even when the file is already | |
193 | * small enough. Check now and save some time. | |
194 | */ | |
195 | code = afs_osi_Stat(afile, &tstat); | |
196 | if (code || tstat.size <= asize) | |
197 | return code; | |
198 | AFS_GUNLOCK(); | |
199 | afs_linux_lock_inode(inode); | |
200 | #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM | |
201 | down_write(&inode->i_alloc_sem); | |
202 | #endif | |
203 | newattrs.ia_size = asize; | |
204 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | |
205 | AFS_CURRENT_TIME(&newattrs.ia_ctime); | |
206 | ||
207 | /* avoid notify_change() since it wants to update dentry->d_parent */ | |
208 | #ifdef HAVE_LINUX_SETATTR_PREPARE | |
209 | code = setattr_prepare(file_dentry(afile->filp), &newattrs); | |
210 | #else | |
211 | code = inode_change_ok(inode, &newattrs); | |
212 | #endif | |
213 | if (!code) | |
214 | code = afs_inode_setattr(afile, &newattrs); | |
215 | if (!code) | |
216 | truncate_inode_pages(&inode->i_data, asize); | |
217 | code = -code; | |
218 | #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM | |
219 | up_write(&inode->i_alloc_sem); | |
220 | #endif | |
221 | afs_linux_unlock_inode(inode); | |
222 | AFS_GLOCK(); | |
223 | return code; | |
224 | } | |
225 | ||
226 | ||
227 | /* Generic read interface */ | |
228 | int | |
229 | afs_osi_Read(struct osi_file *afile, int offset, void *aptr, | |
230 | afs_int32 asize) | |
231 | { | |
232 | struct uio auio; | |
233 | struct iovec iov; | |
234 | afs_int32 code; | |
235 | ||
236 | memset(&auio, 0, sizeof(auio)); | |
237 | memset(&iov, 0, sizeof(iov)); | |
238 | ||
239 | AFS_STATCNT(osi_Read); | |
240 | ||
241 | /* | |
242 | * If the osi_file passed in is NULL, panic only if AFS is not shutting | |
243 | * down. No point in crashing when we are already shutting down | |
244 | */ | |
245 | if (!afile) { | |
246 | if (afs_shuttingdown == AFS_RUNNING) | |
247 | osi_Panic("osi_Read called with null param"); | |
248 | else | |
249 | return -EIO; | |
250 | } | |
251 | ||
252 | if (offset != -1) | |
253 | afile->offset = offset; | |
254 | setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_READ, AFS_UIOSYS); | |
255 | AFS_GUNLOCK(); | |
256 | code = osi_rdwr(afile, &auio, UIO_READ); | |
257 | AFS_GLOCK(); | |
258 | if (code == 0) { | |
259 | code = asize - auio.uio_resid; | |
260 | afile->offset += code; | |
261 | } else { | |
262 | afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, auio.uio_resid, | |
263 | ICL_TYPE_INT32, code); | |
264 | if (code > 0) { | |
265 | code = -code; | |
266 | } | |
267 | } | |
268 | return code; | |
269 | } | |
270 | ||
271 | /* Generic write interface */ | |
272 | int | |
273 | afs_osi_Write(struct osi_file *afile, afs_int32 offset, void *aptr, | |
274 | afs_int32 asize) | |
275 | { | |
276 | struct uio auio; | |
277 | struct iovec iov; | |
278 | afs_int32 code; | |
279 | ||
280 | memset(&auio, 0, sizeof(auio)); | |
281 | memset(&iov, 0, sizeof(iov)); | |
282 | ||
283 | AFS_STATCNT(osi_Write); | |
284 | ||
285 | if (!afile) { | |
286 | if (afs_shuttingdown == AFS_RUNNING) | |
287 | osi_Panic("afs_osi_Write called with null param"); | |
288 | else | |
289 | return -EIO; | |
290 | } | |
291 | ||
292 | if (offset != -1) | |
293 | afile->offset = offset; | |
294 | setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_WRITE, AFS_UIOSYS); | |
295 | AFS_GUNLOCK(); | |
296 | code = osi_rdwr(afile, &auio, UIO_WRITE); | |
297 | AFS_GLOCK(); | |
298 | if (code == 0) { | |
299 | code = asize - auio.uio_resid; | |
300 | afile->offset += code; | |
301 | } else { | |
302 | if (code == ENOSPC) | |
303 | afs_WarnENOSPC(); | |
304 | if (code > 0) { | |
305 | code = -code; | |
306 | } | |
307 | } | |
308 | ||
309 | if (afile->proc) | |
310 | (*afile->proc)(afile, code); | |
311 | ||
312 | return code; | |
313 | } | |
314 | ||
315 | ||
316 | /* This work should be handled by physstrat in ca/machdep.c. | |
317 | This routine written from the RT NFS port strategy routine. | |
318 | It has been generalized a bit, but should still be pretty clear. */ | |
319 | int | |
320 | afs_osi_MapStrategy(int (*aproc) (struct buf * bp), struct buf *bp) | |
321 | { | |
322 | afs_int32 returnCode; | |
323 | ||
324 | AFS_STATCNT(osi_MapStrategy); | |
325 | returnCode = (*aproc) (bp); | |
326 | ||
327 | return returnCode; | |
328 | } | |
329 | ||
330 | void | |
331 | shutdown_osifile(void) | |
332 | { | |
333 | AFS_STATCNT(shutdown_osifile); | |
334 | if (afs_cold_shutdown) { | |
335 | afs_osicred_initialized = 0; | |
336 | } | |
337 | } | |
338 | ||
339 | /* Intialize cache device info and fragment size for disk cache partition. */ | |
340 | int | |
341 | osi_InitCacheInfo(char *aname) | |
342 | { | |
343 | int code; | |
344 | extern afs_dcache_id_t cacheInode; | |
345 | struct dentry *dp; | |
346 | extern struct osi_dev cacheDev; | |
347 | extern afs_int32 afs_fsfragsize; | |
348 | extern struct super_block *afs_cacheSBp; | |
349 | extern struct vfsmount *afs_cacheMnt; | |
350 | code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp); | |
351 | if (code) | |
352 | return ENOENT; | |
353 | ||
354 | osi_get_fh(dp, &cacheInode.ufs); | |
355 | cacheDev.dev = dp->d_inode->i_sb->s_dev; | |
356 | afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1; | |
357 | afs_cacheSBp = dp->d_inode->i_sb; | |
358 | ||
359 | dput(dp); | |
360 | ||
361 | afs_init_sb_export_ops(afs_cacheSBp); | |
362 | ||
363 | return 0; | |
364 | } | |
365 | ||
366 | ||
367 | /* osi_rdwr | |
368 | * seek, then read or write to an open inode. addrp points to data in | |
369 | * kernel space. | |
370 | */ | |
371 | int | |
372 | osi_rdwr(struct osi_file *osifile, struct uio *uiop, int rw) | |
373 | { | |
374 | struct file *filp = osifile->filp; | |
375 | #ifdef AFS_FILE_NEEDS_SET_FS | |
376 | mm_segment_t old_fs = {0}; | |
377 | #endif /* AFS_FILE_NEEDS_SET_FS */ | |
378 | int code = 0; | |
379 | struct iovec *iov; | |
380 | size_t count; | |
381 | unsigned long savelim; | |
382 | loff_t pos; | |
383 | ||
384 | savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur; | |
385 | current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; | |
386 | ||
387 | #ifdef AFS_FILE_NEEDS_SET_FS | |
388 | if (uiop->uio_seg == AFS_UIOSYS) { | |
389 | /* Switch into user space */ | |
390 | old_fs = get_fs(); | |
391 | set_fs(get_ds()); | |
392 | } | |
393 | #endif /* AFS_FILE_NEEDS_SET_FS */ | |
394 | ||
395 | while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) { | |
396 | iov = uiop->uio_iov; | |
397 | count = iov->iov_len; | |
398 | if (count == 0) { | |
399 | uiop->uio_iov++; | |
400 | uiop->uio_iovcnt--; | |
401 | continue; | |
402 | } | |
403 | ||
404 | pos = uiop->uio_offset; | |
405 | if (rw == UIO_READ) | |
406 | code = afs_file_read(filp, iov->iov_base, count, &pos); | |
407 | else | |
408 | code = afs_file_write(filp, iov->iov_base, count, &pos); | |
409 | ||
410 | if (code < 0) { | |
411 | code = -code; | |
412 | break; | |
413 | } else if (code == 0) { | |
414 | /* | |
415 | * This is bad -- we can't read any more data from the | |
416 | * file, but we have no good way of signaling a partial | |
417 | * read either. | |
418 | */ | |
419 | code = EIO; | |
420 | break; | |
421 | } | |
422 | ||
423 | iov->iov_base += code; | |
424 | iov->iov_len -= code; | |
425 | uiop->uio_resid -= code; | |
426 | uiop->uio_offset += code; | |
427 | code = 0; | |
428 | } | |
429 | ||
430 | #ifdef AFS_FILE_NEEDS_SET_FS | |
431 | if (uiop->uio_seg == AFS_UIOSYS) { | |
432 | /* Switch back into kernel space */ | |
433 | set_fs(old_fs); | |
434 | } | |
435 | #endif /* AFS_FILE_NEEDS_SET_FS */ | |
436 | ||
437 | current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim; | |
438 | ||
439 | return code; | |
440 | } | |
441 | ||
442 | /* setup_uio | |
443 | * Setup a uio struct. | |
444 | */ | |
445 | void | |
446 | setup_uio(struct uio *uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos, | |
447 | int count, uio_flag_t flag, uio_seg_t seg) | |
448 | { | |
449 | iovecp->iov_base = (char *)buf; | |
450 | iovecp->iov_len = count; | |
451 | uiop->uio_iov = iovecp; | |
452 | uiop->uio_iovcnt = 1; | |
453 | uiop->uio_offset = pos; | |
454 | uiop->uio_seg = seg; | |
455 | uiop->uio_resid = count; | |
456 | uiop->uio_flag = flag; | |
457 | } | |
458 | ||
459 | ||
460 | /* uiomove | |
461 | * UIO_READ : dp -> uio | |
462 | * UIO_WRITE : uio -> dp | |
463 | */ | |
464 | int | |
465 | uiomove(char *dp, int length, uio_flag_t rw, struct uio *uiop) | |
466 | { | |
467 | int count; | |
468 | struct iovec *iov; | |
469 | int code; | |
470 | ||
471 | while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) { | |
472 | iov = uiop->uio_iov; | |
473 | count = iov->iov_len; | |
474 | ||
475 | if (!count) { | |
476 | uiop->uio_iov++; | |
477 | uiop->uio_iovcnt--; | |
478 | continue; | |
479 | } | |
480 | ||
481 | if (count > length) | |
482 | count = length; | |
483 | ||
484 | switch (uiop->uio_seg) { | |
485 | case AFS_UIOSYS: | |
486 | switch (rw) { | |
487 | case UIO_READ: | |
488 | memcpy(iov->iov_base, dp, count); | |
489 | break; | |
490 | case UIO_WRITE: | |
491 | memcpy(dp, iov->iov_base, count); | |
492 | break; | |
493 | default: | |
494 | printf("uiomove: Bad rw = %d\n", rw); | |
495 | return -EINVAL; | |
496 | } | |
497 | break; | |
498 | case AFS_UIOUSER: | |
499 | switch (rw) { | |
500 | case UIO_READ: | |
501 | AFS_COPYOUT(dp, iov->iov_base, count, code); | |
502 | break; | |
503 | case UIO_WRITE: | |
504 | AFS_COPYIN(iov->iov_base, dp, count, code); | |
505 | break; | |
506 | default: | |
507 | printf("uiomove: Bad rw = %d\n", rw); | |
508 | return -EINVAL; | |
509 | } | |
510 | break; | |
511 | default: | |
512 | printf("uiomove: Bad seg = %d\n", uiop->uio_seg); | |
513 | return -EINVAL; | |
514 | } | |
515 | ||
516 | dp += count; | |
517 | length -= count; | |
518 | iov->iov_base += count; | |
519 | iov->iov_len -= count; | |
520 | uiop->uio_offset += count; | |
521 | uiop->uio_resid -= count; | |
522 | } | |
523 | return 0; | |
524 | } | |
525 |