kopenafs-20060802
[openafs.git] / src / sys / afssyscalls.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 #include <signal.h>
17 #include <sys/errno.h>
18 #include <afs/afs_args.h>
19 #include <sys/file.h>
20 #include <sys/ioctl.h>
21 #if defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)
22 #include <unistd.h>
23 #else
24 #include <stdio.h>
25 #endif
26 #ifdef AFS_SUN5_ENV
27 #include <fcntl.h>
28 #endif
29 #ifdef AFS_SGI_XFS_IOPS_ENV
30 #include "xfsattrs.h"
31 #endif
32 #include <errno.h>
33 #include "afssyscalls.h"
34
35 #ifdef AFS_DEBUG_IOPS
36 FILE *inode_debug_log;          /* If set, write to this file. */
37 /* Indices used for database arrays. */
38 #define CREATE_I 0
39 #define OPEN_I   1
40 #define INC_I    2
41 #define DEC_I    3
42 #define MAX_I    3
43 static void check_iops(int index, char *fun, char *file, int line);
44 #endif /* AFS_DEBUG_IOPS */
45
46 #ifdef AFS_AIX32_ENV
47 /*
48  * in VRMIX, system calls look just like function calls, so we don't
49  * need to do anything!
50  */
51
52 #else
53 #if defined(AFS_SGI_ENV)
54 #ifdef AFS_SGI61_ENV
55 #include <sys/types.h>
56 #endif /* AFS_SGI61_ENV */
57
58 #pragma weak xicreate = icreate
59 #pragma weak xiinc = iinc
60 #pragma weak xidec = idec
61 #pragma weak xiopen = iopen
62 #ifdef notdef
63 #pragma weak xiread = iread
64 #pragma weak xiwrite = iwrite
65 #endif
66
67 int
68 icreate(int dev, int near_inode, int param1, int param2, int param3,
69         int param4)
70 {
71     return (syscall
72             (AFS_ICREATE, dev, near_inode, param1, param2, param3, param4));
73 }
74
75 int
76 iopen(int dev, int inode, int usrmod)
77 {
78     return (syscall(AFS_IOPEN, dev, inode, usrmod));
79 }
80
81 int
82 iinc(int dev, int inode, int inode_p1)
83 {
84     return (syscall(AFS_IINC, dev, inode, inode_p1));
85 }
86
87 int
88 idec(int dev, int inode, int inode_p1)
89 {
90     return (syscall(AFS_IDEC, dev, inode, inode_p1));
91 }
92
93
94 #ifdef AFS_SGI_XFS_IOPS_ENV
95 uint64_t
96 icreatename64(int dev, char *partname, int p0, int p1, int p2, int p3)
97 {
98     uint64_t ino;
99     int code;
100     afs_inode_params_t param;
101
102     /* Use an array so we don't widen the syscall interface. */
103     param[0] = p0;
104     param[1] = p1;
105     param[2] = p2;
106     param[3] = p3;
107     code =
108         afs_syscall(AFSCALL_ICREATENAME64, dev, partname,
109                     1 + strlen(partname), param, &ino);
110     if (code)
111         return (uint64_t) - 1;
112     return ino;
113 }
114
115 int
116 iopen64(int dev, uint64_t inode, int usrmod)
117 {
118     return (syscall
119             (AFS_IOPEN64, dev, (u_int) ((inode >> 32) & 0xffffffff),
120              (u_int) (inode & 0xffffffff), usrmod));
121 }
122
123 int
124 iinc64(int dev, uint64_t inode, int inode_p1)
125 {
126     return (afs_syscall
127             (AFSCALL_IINC64, dev, (u_int) ((inode >> 32) & 0xffffffff),
128              (u_int) (inode & 0xffffffff), inode_p1));
129 }
130
131 int
132 idec64(int dev, uint64_t inode, int inode_p1)
133 {
134     return (afs_syscall
135             (AFSCALL_IDEC64, dev, (u_int) ((inode >> 32) & 0xffffffff),
136              (u_int) (inode & 0xffffffff), inode_p1));
137 }
138
139 int
140 ilistinode64(int dev, uint64_t inode, void *data, int *datalen)
141 {
142     return (afs_syscall
143             (AFSCALL_ILISTINODE64, dev, (u_int) ((inode >> 32) & 0xffffffff),
144              (u_int) (inode & 0xffffffff), data, datalen));
145 }
146
147 #ifdef AFS_DEBUG_IOPS
148 uint64_t
149 debug_icreatename64(int dev, char *partname, int p0, int p1, int p2, int p3,
150                     char *file, int line)
151 {
152     check_iops(CREATE_I, "icreatename64", file, line);
153     return icreatename64(dev, partname, p0, p1, p2, p3);
154 }
155
156 int
157 debug_iopen64(int dev, uint64_t inode, int usrmod, char *file, int line)
158 {
159     check_iops(OPEN_I, "iopen64", file, line);
160     return iopen64(dev, inode, usrmod);
161 }
162
163 int
164 debug_iinc64(int dev, uint64_t inode, int inode_p1, char *file, int line)
165 {
166     check_iops(INC_I, "iinc64", file, line);
167     return iinc64(dev, inode, inode_p1);
168 }
169
170 int
171 debug_idec64(int dev, uint64_t inode, int inode_p1, char *file, int line)
172 {
173     check_iops(DEC_I, "idec64", file, line);
174     return idec64(dev, inode, inode_p1);
175 }
176
177 #endif /* AFS_DEBUG_IOPS */
178 #endif /* AFS_SGI_XFS_IOPS_ENV */
179
180 #ifdef AFS_SGI_VNODE_GLUE
181 /* flag: 1 = has NUMA, 0 = no NUMA, -1 = kernel decides. */
182 int
183 afs_init_kernel_config(int flag)
184 {
185     return afs_syscall(AFSCALL_INIT_KERNEL_CONFIG, flag);
186 }
187 #endif
188
189 #ifdef notdef
190 /* iread and iwrite are deprecated interfaces. Use inode_read and inode_write instead. */
191 int
192 iread(int dev, int inode, int inode_p1, unsigned int offset, char *cbuf,
193       unsigned int count)
194 {
195     return (syscall(AFS_IREAD, dev, inode, inode_p1, offset, cbuf, count));
196 }
197
198 int
199 iwrite(int dev, int inode, int inode_p1, unsigned int offset, char *cbuf,
200        unsigned int count)
201 {
202     return (syscall(AFS_IWRITE, dev, inode, inode_p1, offset, cbuf, count));
203 }
204 #endif /* notdef */
205
206 #else /* AFS_SGI_ENV */
207
208 #ifndef AFS_NAMEI_ENV
209 struct iparam {
210     long param1;
211     long param2;
212     long param3;
213     long param4;
214 };
215
216 /* This module contains the stubs for all AFS-related kernel calls that use a single common entry (i.e. AFS_SYSCALL  system call). Note we ignore SIGSYS signals that are sent when a "nosys" is reached so that kernels that don't support this new entry, will revert back to the original old afs entry; note that in some cases (where EINVAL is normally returned) we'll call the appropriate system call twice (sigh) */
217
218 /* Also since we're limited to 6 parameters/call, in some calls (icreate,
219    iread, iwrite) we combine some in a structure */
220
221 int
222 icreate(int dev, int near_inode, int param1, int param2, int param3,
223         int param4)
224 {
225     int errcode;
226     struct iparam iparams;
227
228     iparams.param1 = param1;
229     iparams.param2 = param2;
230     iparams.param3 = param3;
231     iparams.param4 = param4;
232
233     errcode =
234         syscall(AFS_SYSCALL, AFSCALL_ICREATE, dev, near_inode, &iparams);
235     return (errcode);
236 }
237
238
239 int
240 iopen(int dev, int inode, int usrmod)
241 {
242     int errcode;
243
244     errcode = syscall(AFS_SYSCALL, AFSCALL_IOPEN, dev, inode, usrmod);
245     return (errcode);
246 }
247
248
249 int
250 iinc(int dev, int inode, int inode_p1)
251 {
252     int errcode;
253
254     errcode = syscall(AFS_SYSCALL, AFSCALL_IINC, dev, inode, inode_p1);
255     return (errcode);
256 }
257
258
259 int
260 idec(int dev, int inode, int inode_p1)
261 {
262     int errcode;
263
264     errcode = syscall(AFS_SYSCALL, AFSCALL_IDEC, dev, inode, inode_p1);
265     return (errcode);
266 }
267
268
269 #ifdef notdef
270 int
271 iread(int dev, int inode, int inode_p1, unsigned int offset, char *cbuf,
272       unsigned int count)
273 {
274     int errcode;
275     struct iparam iparams;
276
277     iparams.param1 = inode_p1;
278     iparams.param2 = offset;
279     iparams.param3 = (long)cbuf;
280     iparams.param4 = count;
281     errcode = syscall(AFS_SYSCALL, AFSCALL_IREAD, dev, inode, &iparams);
282     return (errcode);
283 }
284
285
286 iwrite(int dev, int inode, int inode_p1, unsigned int offset, char *cbuf,
287        unsigned int count)
288 {
289     int errcode;
290     struct iparam iparams;
291
292     iparams.param1 = inode_p1;
293     iparams.param2 = offset;
294     iparams.param3 = (long)cbuf;
295     iparams.param4 = count;
296
297     errcode = syscall(AFS_SYSCALL, AFSCALL_IWRITE, dev, inode, &iparams);
298     return (errcode);
299 }
300 #endif
301
302 #endif /* AFS_NAMEI_ENV */
303
304 #endif /* !AFS_SGI_ENV */
305 #endif /* !AFS_AIX32_ENV */
306
307 #ifndef AFS_NAMEI_ENV
308
309 int
310 inode_read(afs_int32 dev, Inode inode, afs_int32 inode_p1,
311            unsigned int offset, char *cbuf, unsigned int count)
312 {
313     int fd;
314     int code = 0;
315
316
317     fd = IOPEN(dev, inode, O_RDONLY);
318     if (fd < 0)
319         return -1;
320
321     code = lseek(fd, offset, SEEK_SET);
322     if (code != offset) {
323         code = -1;
324     } else {
325         code = read(fd, cbuf, count);
326     }
327     close(fd);
328     return code;
329 }
330
331
332 int
333 inode_write(afs_int32 dev, Inode inode, afs_int32 inode_p1,
334             unsigned int offset, char *cbuf, unsigned int count)
335 {
336     int fd;
337     int code = 0;
338
339     fd = IOPEN(dev, inode, O_WRONLY);
340     if (fd < 0)
341         return -1;
342
343     code = lseek(fd, offset, SEEK_SET);
344     if (code != offset) {
345         code = -1;
346     } else {
347         code = write(fd, cbuf, count);
348     }
349     close(fd);
350     return code;
351 }
352
353
354 /* PrintInode
355  *
356  * returns a static string used to print either 32 or 64 bit inode numbers.
357  */
358 #ifdef AFS_64BIT_IOPS_ENV
359 char *
360 PrintInode(char *s, Inode ino)
361 #else
362 char *
363 PrintInode(afs_ino_str_t s, Inode ino)
364 #endif
365 {
366     static afs_ino_str_t result;
367
368     if (!s)
369         s = result;
370
371 #ifdef AFS_64BIT_IOPS_ENV
372     (void)sprintf((char *)s, "%llu", ino);
373 #else
374     (void)sprintf((char *)s, "%u", ino);
375 #endif
376     return (char *)s;
377 }
378 #endif /* AFS_NAMEI_ENV */
379
380
381 #ifdef AFS_DEBUG_IOPS
382 #define MAX_FILE_NAME_LENGTH 32
383 typedef struct {
384     int line;
385     char file[MAX_FILE_NAME_LENGTH];
386 } iops_debug_t;
387 int iops_debug_n_avail[MAX_I + 1];
388 int iops_debug_n_used[MAX_I + 1];
389 iops_debug_t *iops_debug[MAX_I + 1];
390 #define IOPS_DEBUG_MALLOC_STEP 64
391
392 /* check_iops
393  * Returns 1 if first time we've seen this file/line. 
394  * Puts file/line in array so we only print the first time we encounter
395  * this entry.
396  */
397 static void
398 check_iops(int index, char *fun, char *file, int line)
399 {
400     int i;
401     int *availp = &iops_debug_n_avail[index];
402     int *usedp = &iops_debug_n_used[index];
403     iops_debug_t *iops = iops_debug[index];
404     int used;
405
406     if (!inode_debug_log)
407         return;
408
409     used = *usedp;
410     if (used) {
411         for (i = 0; i < used; i++) {
412             if (line == iops[i].line) {
413                 if (!strncmp(file, iops[i].file, MAX_FILE_NAME_LENGTH)) {
414                     /* We've already entered this one. */
415                     return;
416                 }
417             }
418         }
419     }
420
421     /* Not found, enter into db. */
422     if (used >= *availp) {
423         int avail = *availp;
424         avail += IOPS_DEBUG_MALLOC_STEP;
425         if (avail == IOPS_DEBUG_MALLOC_STEP)
426             iops_debug[index] =
427                 (iops_debug_t *) malloc(avail * sizeof(iops_debug_t));
428         else
429             iops_debug[index] =
430                 (iops_debug_t *) realloc(*iops, avail * sizeof(iops_debug_t));
431         if (!iops_debug[index]) {
432             printf("check_iops: Can't %salloc %lu bytes for index %d\n",
433                    (avail == IOPS_DEBUG_MALLOC_STEP) ? "m" : "re",
434                    avail * sizeof(iops_debug_t), index);
435             exit(1);
436         }
437         *availp = avail;
438         iops = iops_debug[index];
439     }
440     iops[used].line = line;
441     (void)strncpy(iops[used].file, file, MAX_FILE_NAME_LENGTH);
442     *usedp = used + 1;
443
444     fprintf(inode_debug_log, "%s: file %s, line %d\n", fun, file, line);
445     fflush(inode_debug_log);
446 }
447 #endif /* AFS_DEBUG_IOPS */