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