Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / AIX / osi_inode.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 /*
11 * AIX inode operations
12 *
13 * Implements:
14 *
15 */
16 #include <afsconfig.h>
17 #include "afs/param.h"
18
19
20 #include "afs/sysincludes.h" /* Standard vendor system headers */
21 #include "afsincludes.h" /* Afs-based standard headers */
22 #include "afs/osi_inode.h"
23 #include "afs/afs_stats.h" /* statistics stuff */
24 #include "sys/syspest.h"
25
26 #if !defined(offsetof)
27 #include <stddef.h> /* for definition of offsetof() */
28 #endif
29
30 extern Simple_lock jfs_icache_lock;
31 #define ICACHE_LOCK() simple_lock(&jfs_icache_lock)
32 #define ICACHE_UNLOCK() simple_unlock(&jfs_icache_lock)
33
34 /*
35 * In AIX 4.2.0, the inode member to lock is i_rdwrlock. The inode
36 * structure conditionally contains a member called i_nodelock which we
37 * do NOT want to use.
38 *
39 * In AIX 4.2.1 and later, the inode member to lock is i_nodelock, which
40 * was relocated to coincide with the AIX 4.2.0 position of i_rdwrlock.
41 * The AIX 4.2.1 and later inode structure does not contain a field
42 * named i_rdwrlock.
43 *
44 * We use an accident of the system header files to distinguish between
45 * AIX 4.2.0 and AIX 4.2.1 and later. This allows this part of the code
46 * to compile on AIX 4.2.1 and later without introducing a new system
47 * type.
48 *
49 * The macro IACTIVITY is 0x0020 on AIX 4.2.0, and 0x0010 on AIX 4.2.1
50 * and later (at least through AIX 4.3.3). If IACTIVITY is undefined,
51 * or has an unknown value, then the system header files are different
52 * than what we've seen and we'll need to take a look at them anyway to
53 * get AFS to work.
54 *
55 * The osi_Assert() statement in igetinode() checks that the lock field
56 * is at an expected offset.
57 */
58
59 #if IACTIVITY == 0x0020 /* in <jfs/inode.h> on AIX 4.2.0 */
60 #define afs_inode_lock i_rdwrlock
61 #endif
62
63 #if IACTIVITY == 0x0010 /* in <jfs/inode.h> on AIX 4.2.1 and later */
64 #define afs_inode_lock i_nodelock
65 #endif
66
67 #define IREAD_LOCK(ip) simple_lock(&((ip)->afs_inode_lock))
68 #define IREAD_UNLOCK(ip) simple_unlock(&((ip)->afs_inode_lock))
69 #define IWRITE_LOCK(ip) simple_lock(&((ip)->afs_inode_lock))
70 #define IWRITE_UNLOCK(ip) simple_unlock(&((ip)->afs_inode_lock))
71
72 #define SYSENT(name, arglist, decls) \
73 name decls \
74 { \
75 lock_t lockt; \
76 int rval1 = 0; \
77 label_t jmpbuf; \
78 int rc; \
79 \
80 \
81 setuerror(0); \
82 \
83 if ((rc = setjmpx(&jmpbuf)) == 0) { \
84 rval1 = afs_syscall_ ## name arglist; \
85 clrjmpx(&jmpbuf); \
86 } else { \
87 if (rc != EINTR) { \
88 longjmpx(rc); \
89 } \
90 setuerror(rc); \
91 } \
92 \
93 \
94 return(getuerror() ? -1 : rval1); \
95 } \
96 afs_syscall_ ## name decls \
97
98
99 /*
100 * This structure is used to pass information between devtovfs() and
101 * devtovfs_func() via vfs_search().
102 */
103
104 struct devtovfs_args {
105 dev_t dev;
106 struct vfs *ans;
107 };
108
109 /*
110 * If the given vfs matches rock->dev, set rock->ans to vfsp and return
111 * nonzero. Otherwise return zero.
112 *
113 * (Returning nonzero causes vfs_search() to terminate the search.)
114 */
115
116 static int
117 devtovfs_func(struct vfs *vfsp, struct devtovfs_args *rock)
118 {
119 if (vfsp->vfs_mntd != NULL && vfsp->vfs_type == MNT_JFS
120 && (vfsp->vfs_flag & VFS_DEVMOUNT)) {
121 struct inode *ip = VTOIP(vfsp->vfs_mntd);
122 if (brdev(ip->i_dev) == brdev(rock->dev)) {
123 rock->ans = vfsp;
124 return 1;
125 }
126 }
127
128 return 0;
129 }
130
131 /*
132 * Return the vfs entry for the given device.
133 */
134
135 static struct vfs *
136 devtovfs(dev_t dev)
137 {
138 struct devtovfs_args a;
139
140 AFS_STATCNT(devtovfs);
141
142 a.dev = dev;
143 a.ans = NULL;
144 vfs_search(devtovfs_func, (caddr_t) &a);
145 return a.ans;
146 }
147
148 /* Keep error values around in case iget fails. UFSOpen panics when
149 * igetinode fails.
150 */
151 int IGI_error;
152 ino_t IGI_inode;
153 int IGI_nlink;
154 int IGI_mode;
155 /* get an existing inode. Common code for iopen, iread/write, iinc/dec. */
156 /* Also used by rmt_remote to support passing of inode number from venus */
157 extern int iget();
158 extern struct vnode *filevp;
159 struct inode *
160 igetinode(dev, vfsp, inode, vpp, perror)
161 struct vfs *vfsp;
162 struct vnode **vpp; /* vnode associated with the inode */
163 dev_t dev;
164 ino_t inode;
165 int *perror;
166 {
167 struct inode *ip;
168 int was_locked;
169 struct vfs *nvfsp = NULL;
170 int code;
171 *perror = 0;
172 *vpp = NULL;
173 AFS_STATCNT(igetinode);
174
175 /*
176 * Double check that the inode lock is at a known offset.
177 *
178 * If it isn't, then we need to reexamine our code to make
179 * sure that it is still okay.
180 */
181 #ifdef __64BIT__
182 /* osi_Assert(offsetof(struct inode, afs_inode_lock) == 208); */
183 #else
184 osi_Assert(offsetof(struct inode, afs_inode_lock) == 128);
185 #endif
186
187 if (!vfsp && !(vfsp = devtovfs((dev_t) dev))) {
188 afs_warn("Dev=%d not mounted!!; quitting\n", dev);
189 setuerror(ENODEV);
190 ip = 0;
191 goto out;
192 }
193 if (vfsp->vfs_flag & VFS_DEVMOUNT)
194 nvfsp = vfsp;
195
196 /* Check if inode 0. This is the mount inode for the device
197 * and will panic the aix system if removed: defect 11434.
198 * No file should ever point to this inode.
199 */
200 if (inode == 0) {
201 afs_warn("Dev=%d zero inode.\n", dev);
202 setuerror(ENOENT);
203 ip = 0;
204 goto out;
205 }
206
207 ICACHE_LOCK();
208 #ifdef __64BIT__
209 if ((code = iget(dev, inode, &ip, (afs_size_t) 1, nvfsp))) {
210 #else
211 if ((code = iget(dev, inode, &ip, 1, nvfsp))) {
212 #endif
213 IGI_error = code;
214 IGI_inode = inode;
215 *perror = BAD_IGET;
216 ICACHE_UNLOCK();
217 setuerror(ENOENT); /* Well... */
218 ip = 0;
219 goto out;
220 }
221 ICACHE_UNLOCK();
222 IREAD_LOCK(ip);
223 if (ip->i_nlink == 0 || (ip->i_mode & IFMT) != IFREG) {
224 IGI_error = 0;
225 IGI_inode = inode;
226 IGI_nlink = ip->i_nlink;
227 IGI_mode = ip->i_mode;
228 IREAD_UNLOCK(ip);
229 ICACHE_LOCK();
230 iput(ip, NULL);
231 ICACHE_UNLOCK();
232 setuerror(ENOENT);
233 ip = 0;
234 goto out;
235 }
236 if (vpp) {
237 if (nvfsp)
238 *vpp = ip->i_gnode.gn_vnode;
239 else
240 setuerror(iptovp(vfsp, ip, vpp));
241 }
242 IREAD_UNLOCK(ip);
243 out:
244 return ip;
245 }
246
247
248 #ifndef INODESPECIAL
249 /*
250 * `INODESPECIAL' type inodes are ones that describe volumes. These are
251 * marked as journalled. We would also like to journal inodes corresponding
252 * to directory information...
253 */
254 #define INODESPECIAL 0xffffffff /* ... from ../vol/viceonode.h */
255 #endif
256
257 SYSENT(icreate, (dev, near_inode, param1, param2, param3, param4), (long dev, long near_inode, long param1, long param2, long param3, long param4))
258 {
259 struct inode *ip, *newip, *pip;
260 int err, rval1, rc = 0;
261 struct vnode *vp = NULL;
262 struct vfs *vfsp;
263 struct vfs *nvfsp = NULL;
264 char error;
265 ino_t ino = near_inode;
266
267 AFS_STATCNT(afs_syscall_icreate);
268 if (!suser(&error)) {
269 setuerror(error);
270 return -1;
271 }
272
273 if ((vfsp = devtovfs((dev_t) dev)) == 0) {
274 afs_warn("Dev=%d not mounted!!; quitting\n", dev);
275 setuerror(ENODEV);
276 return -1;
277 }
278 if (vfsp->vfs_flag & VFS_DEVMOUNT)
279 nvfsp = vfsp;
280 ICACHE_LOCK();
281 rc = iget(dev, 0, &pip, 1, nvfsp);
282 if (!rc) {
283 /*
284 * this is the mount inode, and thus we should be
285 * safe putting it back.
286 */
287 iput(pip, nvfsp);
288 }
289 ICACHE_UNLOCK();
290
291 if (rc) {
292 setuerror(EINVAL);
293 return -1;
294 }
295
296 if (setuerror(dev_ialloc(pip, ino, IFREG, nvfsp, &newip)))
297 return -1;
298 newip->i_flag |= IACC | IUPD | ICHG;
299 newip->i_gid = -2; /* Put special gid flag */
300 newip->i_vicemagic = VICEMAGIC;
301 newip->i_vicep1 = param1;
302 newip->i_vicep2 = param2;
303 newip->i_vicep3 = param3;
304 newip->i_vicep4 = param4;
305 IWRITE_UNLOCK(newip);
306 if (nvfsp) {
307 vp = newip->i_gnode.gn_vnode;
308 } else {
309 rc = iptovp(vfsp, newip, &vp);
310 }
311 setuerror(rc);
312
313 rval1 = newip->i_number;
314 if (vp) {
315 VNOP_RELE(vp);
316 }
317 return getuerror()? -1 : rval1;
318 }
319
320 SYSENT(iopen, (dev, inode, usrmod),(int dev, int inode, int usrmod))
321 {
322 struct file *fp;
323 struct inode *ip;
324 struct vnode *vp = NULL;
325 extern struct fileops vnodefops;
326 struct vfs *vfsp;
327 int fd;
328 char error;
329 struct ucred *credp;
330 int dummy;
331
332 AFS_STATCNT(afs_syscall_iopen);
333 if (!suser(&error)) {
334 setuerror(error);
335 return -1;
336 }
337
338 if ((vfsp = devtovfs((dev_t) dev)) == 0) {
339 afs_warn("Dev=%d not mounted!!; quitting\n", dev);
340 setuerror(ENODEV);
341 return -1;
342 }
343 ip = igetinode((dev_t) dev, vfsp, (ino_t) inode, &vp, &dummy);
344 if (getuerror())
345 return -1;
346
347 credp = crref();
348 if (setuerror
349 (ufdcreate
350 ((usrmod - FOPEN) & FMASK, &vnodefops, vp, DTYPE_VNODE, &fd,
351 credp))) {
352 crfree(credp);
353 VNOP_RELE(vp);
354 return -1;
355 }
356
357 if (setuerror(VNOP_OPEN(vp, (usrmod - FOPEN) & FMASK, 0, 0, credp))) {
358 close(fd);
359 crfree(credp);
360 return -1;
361 }
362 crfree(credp);
363 return fd;
364 }
365
366
367 /*
368 * Support for iinc() and idec() system calls--increment or decrement
369 * count on inode.
370 * Restricted to super user.
371 * Only VICEMAGIC type inodes.
372 */
373 iinc(dev, inode, inode_p1)
374 {
375
376 AFS_STATCNT(iinc);
377 return iincdec(dev, inode, inode_p1, 1);
378 }
379
380 idec(dev, inode, inode_p1)
381 {
382
383 AFS_STATCNT(idec);
384 return iincdec(dev, inode, inode_p1, -1);
385 }
386
387
388 SYSENT(iincdec, (dev, inode, inode_p1, amount),(int dev, int inode, int inode_p1, int amount))
389 {
390 struct inode *ip;
391 char error;
392 struct vnode *vp = NULL;
393 int dummy;
394
395 AFS_STATCNT(afs_syscall_iincdec);
396 if (!suser(&error)) {
397 setuerror(error);
398 return -1;
399 }
400
401 ip = igetinode((dev_t) dev, 0, (ino_t) inode, &vp, &dummy);
402 if (getuerror()) {
403 return -1;
404 }
405 IWRITE_LOCK(ip);
406 if (ip->i_vicemagic != VICEMAGIC)
407 setuerror(EPERM);
408 else if (ip->i_vicep1 != inode_p1)
409 setuerror(ENXIO);
410 else {
411 ip->i_nlink += amount;
412 if (ip->i_nlink == 0) {
413 ip->i_vicemagic = 0;
414 ip->i_cflag &= ~CMNEW;
415 }
416 ip->i_flag |= ICHG;
417 commit(1, ip); /* always commit */
418 }
419 IWRITE_UNLOCK(ip);
420 VNOP_RELE(vp);
421 /*
422 ICACHE_LOCK();
423 iput(ip, 0);
424 ICACHE_UNLOCK();
425 */
426 return getuerror()? -1 : 0;
427 }