62f9825ed2c336caef60f718fc201825b56ec93a
[openafs.git] / src / afs / IRIX / 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  * IRIX inode operations
12  *
13  * Implements:
14  * afsdptoip
15  * afsiptodp
16  * afsidestroy
17  * getinode
18  * igetinode
19  * xfs_getinode
20  * xfs_igetinode
21  * icreate
22  * afs_syscall_icreate
23  * xfs_icreatename64
24  * afs_syscall_icreatename64
25  * iopenargs64
26  * afs_syscall_iopen
27  * iopen
28  * iopen64
29  * efs_iincdec
30  * xfs_iincdec64
31  * iincdec64
32  * afs_syscall_idec64
33  * afs_syscall_iinc64
34  * iincdec
35  * iinc
36  * idec
37  * afs_syscall_iincdec
38  * afs_syscall_ilistinode64
39  *
40  */
41
42 #include <afsconfig.h>
43 #include "afs/param.h"
44
45 RCSID
46     ("$Header$");
47
48 #include "afs/sysincludes.h"    /* Standard vendor system headers */
49 #include "afsincludes.h"        /* Afs-based standard headers */
50 #include "afs/osi_inode.h"
51 #include "afs/afs_stats.h"      /* statistics stuff */
52
53 #define BAD_IGET        -1000
54
55 /*
56  * SGI dependent system calls
57  */
58 #ifndef INODESPECIAL
59 /*
60  * `INODESPECIAL' type inodes are ones that describe volumes.
61  */
62 #define INODESPECIAL    0xffffffff      /* ... from ../vol/viceinode.h  */
63 #endif
64 /*
65  * copy disk inode to incore inode and vice-versa
66  */
67 void
68 afsdptoip(struct efs_dinode *dp, struct inode *ip)
69 {
70     struct afsparms *ap;
71
72     ip->i_afs = kmem_alloc(sizeof(struct afsparms), KM_SLEEP);
73     osi_Assert(ip->i_version == EFS_IVER_AFSSPEC
74                || ip->i_version == EFS_IVER_AFSINO);
75     ap = (struct afsparms *)ip->i_afs;
76     /* vicep1 is VOLid */
77     ap->vicep1 =
78         dmag(dp, 0) << 24 | dmag(dp, 1) << 16 | dmag(dp, 2) << 8 | dmag(dp,
79                                                                         3) <<
80         0;
81
82     if (ip->i_version == EFS_IVER_AFSSPEC) {
83         ap->vicep3 = dmag(dp, 8);       /* Type */
84         ap->vicep4 =
85             dmag(dp, 4) << 24 | dmag(dp, 5) << 16 | dmag(dp,
86                                                          6) << 8 | dmag(dp,
87                                                                         7) <<
88             0;
89
90     } else {
91         /* vnode number */
92         ap->vicep2 = dmag(dp, 4) << 16 | dmag(dp, 5) << 8 | dmag(dp, 6) << 0;
93         /* disk uniqifier */
94         ap->vicep3 = dmag(dp, 7) << 16 | dmag(dp, 8) << 8 | dmag(dp, 9) << 0;
95         /* data version */
96         ap->vicep4 = dmag(dp, 10) << 16 | dmag(dp, 11) << 8 | (dp)->di_spare;
97     }
98 }
99
100 void
101 afsiptodp(struct inode *ip, struct efs_dinode *dp)
102 {
103     struct afsparms *ap;
104
105     if (ip->i_afs == NULL)
106         return;
107
108     osi_Assert(ip->i_version == EFS_IVER_AFSSPEC
109                || ip->i_version == EFS_IVER_AFSINO);
110     ap = (struct afsparms *)ip->i_afs;
111     /* vicep1 is VOLid */
112     dmag(dp, 0) = ap->vicep1 >> 24;
113     dmag(dp, 1) = ap->vicep1 >> 16;
114     dmag(dp, 2) = ap->vicep1 >> 8;
115     dmag(dp, 3) = ap->vicep1 >> 0;
116
117     if (ip->i_version == EFS_IVER_AFSSPEC) {
118         /* Type */
119         dmag(dp, 8) = ap->vicep3;
120         /* ParentId */
121         dmag(dp, 4) = ap->vicep4 >> 24;
122         dmag(dp, 5) = ap->vicep4 >> 16;
123         dmag(dp, 6) = ap->vicep4 >> 8;
124         dmag(dp, 7) = ap->vicep4 >> 0;
125     } else {
126         /* vnode number */
127         dmag(dp, 4) = ap->vicep2 >> 16;
128         dmag(dp, 5) = ap->vicep2 >> 8;
129         dmag(dp, 6) = ap->vicep2 >> 0;
130         /* disk uniqifier */
131         dmag(dp, 7) = ap->vicep3 >> 16;
132         dmag(dp, 8) = ap->vicep3 >> 8;
133         dmag(dp, 9) = ap->vicep3 >> 0;
134         /* data version */
135         dmag(dp, 10) = ap->vicep4 >> 16;
136         dmag(dp, 11) = ap->vicep4 >> 8;
137         dp->di_spare = ap->vicep4 >> 0;
138     }
139 }
140
141 void
142 afsidestroy(struct inode *ip)
143 {
144     if (ip->i_afs) {
145         kmem_free(ip->i_afs, sizeof(struct afsparms));
146         ip->i_afs = NULL;
147     }
148 }
149
150 extern int efs_fstype;
151 #ifdef AFS_SGI_XFS_IOPS_ENV
152 extern int xfs_fstype;
153 #endif
154
155 int
156 getinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct inode **ipp)
157 {
158     struct inode *ip;
159     int error;
160
161     if (!vfsp) {
162 #ifdef AFS_SGI65_ENV
163         vfsp = vfs_devsearch(dev, efs_fstype);
164 #else
165         vfsp = vfs_devsearch(dev);
166 #endif
167         if (!vfsp) {
168             return ENXIO;
169         }
170     }
171 #ifndef AFS_SGI65_ENV
172     if (vfsp->vfs_fstype != efs_fstype)
173         return ENOSYS;
174 #endif
175
176     if (error =
177         iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
178              (unsigned int)(inode & 0xffffffff), &ip)) {
179         return error;
180     }
181     *ipp = ip;
182     return 0;
183 }
184
185 int
186 igetinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct inode **ipp)
187 {
188     struct inode *ip;
189     int error;
190
191     AFS_STATCNT(igetinode);
192     if (error = getinode(vfsp, dev, inode, &ip))
193         return error;
194     *ipp = ip;
195     return 0;
196 }
197
198 int XFS_IGET_EPOS;
199 ino_t XFS_IGET_INO;
200 dev_t XFS_IGET_DEV;
201 #define SET_XFS_ERROR(POS, DEV, INO) \
202         XFS_IGET_EPOS = (POS), XFS_IGET_DEV = (DEV), XFS_IGET_INO = (INO)
203
204 int
205 xfs_getinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct xfs_inode **ipp)
206 {
207     struct xfs_inode *ip;
208     int error;
209
210     if (!vfsp) {
211 #ifdef AFS_SGI65_ENV
212         vfsp = vfs_devsearch(dev, xfs_fstype);
213 #else
214         vfsp = vfs_devsearch(dev);
215 #endif
216         if (!vfsp) {
217             SET_XFS_ERROR(1, dev, inode);
218             return ENXIO;
219         }
220     }
221 #ifndef AFS_SGI65_ENV
222     if (vfsp->vfs_fstype != xfs_fstype) {
223         SET_XFS_ERROR(2, vfsp->vfs_dev, inode);
224         return ENOSYS;
225     }
226 #endif
227
228     if (error = xfs_iget((((struct mount *)
229                            ((vfsp)->vfs_bh.bh_first)->bd_pdata)), (void *)0,
230                          (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
231                          (daddr_t) 0)) {
232         SET_XFS_ERROR(3, vfsp->vfs_dev, inode);
233         return error;
234     }
235
236     *ipp = ip;
237     return 0;
238 }
239
240 /* xfs_igetinode now returns an unlocked inode. This is fine, since we
241  * have a refcount on the holding vnode.
242  */
243 int
244 xfs_igetinode(struct vfs *vfsp, dev_t dev, ino_t inode,
245               struct xfs_inode **ipp)
246 {
247     struct xfs_inode *ip;
248     vnode_t *vp;
249     vattr_t vattr;
250     int error;
251
252     AFS_STATCNT(igetinode);
253
254     *ipp = NULL;
255     if (error = xfs_getinode(vfsp, dev, inode, &ip)) {
256         return error;
257     }
258
259     xfs_iunlock(ip, XFS_ILOCK_SHARED);
260     vp = XFS_ITOV(ip);
261     vattr.va_mask = AT_STAT;
262     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), error);
263     if (error) {
264         SET_XFS_ERROR(4, vp->v_vfsp->vfs_dev, inode);
265         VN_RELE(vp);
266         return error;
267     }
268     if (vattr.va_nlink == 0 || vattr.va_type != VREG) {
269         SET_XFS_ERROR(5, vp->v_vfsp->vfs_dev, inode);
270         VN_RELE(vp);
271         return ENOENT;
272     }
273
274     *ipp = ip;
275     return 0;
276 }
277
278 /**************************************************************************
279  * inode creation routines.
280  *
281  ***************************************************************************/
282 struct icreateargs {
283     sysarg_t dev;
284     sysarg_t near_inode;
285     sysarg_t param1;
286     sysarg_t param2;
287     sysarg_t param3;
288     sysarg_t param4;
289 };
290
291 /* EFS only fs suite uses this entry point - icreate in afssyscalls.c. */
292 int
293 icreate(struct icreateargs *uap, rval_t * rvp)
294 {
295 #ifdef AFS_SGI_EFS_IOPS_ENV
296     AFS_STATCNT(icreate);
297     return (afs_syscall_icreate
298             (uap->dev, uap->near_inode, uap->param1, uap->param2, uap->param3,
299              uap->param4, rvp));
300 #else
301     return ENOSYS;
302 #endif
303 }
304
305 #ifdef AFS_SGI_EFS_IOPS_ENV
306 int
307 afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp)
308      afs_uint32 dev, near_inode, param1, param2, param3, param4;
309      rval_t *rvp;
310 {
311     struct inode *ip, *newip;
312     struct afsparms *ap;
313     struct cred cr;
314     int error;
315
316     AFS_STATCNT(afs_syscall_icreate);
317     if (!afs_suser(NULL))
318         return EPERM;
319
320     if (error = getinode(0, (dev_t) dev, 2, &ip))
321         return error;
322
323     cr.cr_uid = 0;
324     cr.cr_gid = -2;
325     if (error = efs_ialloc(ip, IFREG, 1, NODEV, &newip, &cr)) {
326         iput(ip);
327         return error;
328     }
329     iput(ip);
330     osi_Assert(newip);
331     newip->i_flags |= IACC | IUPD | ICHG;
332
333     osi_Assert(newip->i_afs == NULL);
334     newip->i_afs = kmem_alloc(sizeof(struct afsparms), KM_SLEEP);
335     if (param2 == INODESPECIAL)
336         newip->i_version = EFS_IVER_AFSSPEC;
337     else
338         newip->i_version = EFS_IVER_AFSINO;
339     ap = (struct afsparms *)newip->i_afs;
340     ap->vicep1 = param1;        /* VOLid */
341     ap->vicep2 = param2;        /* Vnode # */
342     ap->vicep3 = param3;        /* SPEC:type INO:vnode uniq */
343     ap->vicep4 = param4;        /* SPEC:parentId INO:data version */
344     rvp->r_val1 = newip->i_number;
345     iput(newip);
346     return 0;
347 }
348 #else /* !AFS_SGI_EFS_IOPS_ENV */
349 int
350 afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp)
351      afs_uint32 dev, near_inode, param1, param2, param3, param4;
352      rval_t *rvp;
353 {
354     return ENOSYS;
355 }
356 #endif /* AFS_SGI_EFS_IOPS_ENV */
357
358 #ifdef AFS_SGI_XFS_IOPS_ENV
359 /* inode creation routines for icreatename64 entry point. Use for EFS/XFS
360  * fileserver suite.  For XFS, create a name in the namespace as well as the
361  * inode. For EFS, just call the original routine.
362  */
363
364 #include <afs/xfsattrs.h>
365 #include <sys/attributes.h>
366
367 extern char *int_to_base64(char *, int);
368
369 /* Lock against races creating/removing directory - vos zap RO, vos create RW*/
370 kmutex_t afs_vol_create_lock;
371 int afs_vol_create_lock_inited = 0;
372 #define AFS_LOCK_VOL_CREATE() { \
373         if (!afs_vol_create_lock_inited) { \
374             mutex_init(&afs_vol_create_lock, MUTEX_DEFAULT, \
375                        "afs_vol_create_lock"); \
376             afs_vol_create_lock_inited = 1; \
377         } \
378         mutex_enter(&afs_vol_create_lock); \
379                                  }
380 #define AFS_UNLOCK_VOL_CREATE() mutex_exit(&afs_vol_create_lock)
381
382
383 /* xfs_icreatename64
384  * Create an AFS inode in the XFS name space. If required create the proper
385  * containing directory. See sys/xfsattrs.h for the details on the naming
386  * conventions and the usage of file and directory attributes.
387  *
388  * The inode parameters are stored in an XFS attribute called "AFS". In
389  * addition gid is set to XFS_VICEMAGIC and uid is set to the low 31 bits
390  * of the RW volume id. This is so inode verification in iinc and idec
391  * don't need to get the attribute. Note that only the low 31 bits are set.
392  * This is because chmod only accepts up to MAX_UID and chmod is used
393  * to correct these values in xfs_ListViceInodes.
394  */
395 int
396 xfs_icreatename64(struct vfs *vfsp, int datap, int datalen,
397                   afs_inode_params_t params, ino_t * inop)
398 {
399 #define AFS_PNAME_SIZE 16
400     char path[64];
401     char name[64];
402     b64_string_t stmp1, stmp2;
403     afs_xfs_attr_t attrs;
404     struct vattr vattr;
405     int name_version = AFS_XFS_NAME_VERS;
406     int code = 0, unused;
407     struct vnode *vp;
408     struct vnode *dvp;
409     int rw_vno;                 /* volume ID of parent volume */
410     int i;
411     int createdDir = 0;
412     size_t junk;
413     char *s;
414
415
416     /* Get vnode for directory which will contain new inode. */
417     if (datalen >= AFS_PNAME_SIZE)
418         return E2BIG;
419
420     AFS_COPYINSTR((char *)datap, path, AFS_PNAME_SIZE - 1, &junk, unused);
421     if (*path != '/') {
422         return EINVAL;
423     }
424
425     rw_vno = (params[1] == INODESPECIAL) ? params[3] : params[0];
426
427     /* directory name */
428     strcat(path, "/");
429     strcat(path, AFS_INODE_DIR_NAME);
430     strcat(path, int_to_base64(stmp1, rw_vno));
431
432     if (params[1] == INODESPECIAL)
433         AFS_LOCK_VOL_CREATE();
434
435     code = gop_lookupname(path, AFS_UIOSYS, FOLLOW, &dvp);
436     if (code == ENOENT) {
437         /* Maybe it's an old directory name format. */
438         AFS_COPYINSTR((char *)datap, name, AFS_PNAME_SIZE - 1, &junk, unused);
439         strcat(name, "/.");
440         strcat(name, int_to_base64(stmp1, rw_vno));
441         code = gop_lookupname(name, AFS_UIOSYS, FOLLOW, &dvp);
442         if (!code) {
443             /* Use old name format. */
444             strcpy(path, name);
445             name_version = AFS_XFS_NAME_VERS1;
446         }
447     }
448
449     if (code == ENOENT) {
450         afs_xfs_dattr_t dattr;
451         /* make directory. */
452
453         code =
454             AFS_VN_OPEN(path, UIO_SYSSPACE, FCREAT | FEXCL, 0700, &dvp,
455                         CRMKDIR);
456         if (code) {
457             if (code == EEXIST) {
458                 /* someone beat us to it? */
459                 code = gop_lookupname(path, AFS_UIOSYS, NO_FOLLOW, &dvp);
460             }
461             if (code) {
462                 AFS_UNLOCK_VOL_CREATE();
463                 return code;
464             }
465         } else
466             createdDir = 1;
467         memset((char *)&dattr, 0, sizeof(dattr));
468         dattr.atd_version = AFS_XFS_ATD_VERS;
469         dattr.atd_volume = rw_vno;
470         AFS_VOP_ATTR_SET(dvp, AFS_XFS_DATTR, (char *)&dattr,
471                          SIZEOF_XFS_DATTR_T, ATTR_ROOT | ATTR_CREATE,
472                          OSI_GET_CURRENT_CRED(), code);
473         if (code) {
474             VN_RELE(dvp);
475             if (createdDir)
476                 (void)vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
477             AFS_UNLOCK_VOL_CREATE();
478             return code;
479         }
480     }
481
482     vattr.va_mask = AT_FSID | AT_NODEID;        /* gets a guick return using FSID */
483     AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
484     if (code) {
485         VN_RELE(dvp);
486         return code;
487     }
488
489     memset((char *)&attrs, 0, sizeof(attrs));
490     attrs.at_pino = vattr.va_nodeid;
491     VN_RELE(dvp);
492
493     /* Create the desired file. Use up to ten tries to create a unique name. */
494     (void)strcpy(name, path);
495     (void)strcat(name, "/.");
496     (void)strcat(name, int_to_base64(stmp2, params[2]));
497     s = &name[strlen(name)];
498
499     attrs.at_tag = 0;           /* Initial guess at a unique tag. */
500     for (i = 0; i < 10; i++) {
501         *s = '\0';
502         strcat(s, ".");
503         strcat(s, int_to_base64(stmp1, attrs.at_tag));
504         code =
505             AFS_VN_OPEN(name, UIO_SYSSPACE, FCREAT | FEXCL, 0600, &vp,
506                         CRCREAT);
507         if (!code || code != EEXIST)
508             break;
509
510         attrs.at_tag++;
511     }
512     /* Unlock the creation process since the directory now has a file in it. */
513     if (params[1] == INODESPECIAL)
514         AFS_UNLOCK_VOL_CREATE();
515
516     if (!code) {
517         /* Set attributes. */
518         memcpy((char *)attrs.at_param, (char *)params,
519                sizeof(afs_inode_params_t));
520         attrs.at_attr_version = AFS_XFS_ATTR_VERS;
521         attrs.at_name_version = name_version;
522         AFS_VOP_ATTR_SET(vp, AFS_XFS_ATTR, (char *)&attrs, SIZEOF_XFS_ATTR_T,
523                          ATTR_ROOT | ATTR_CREATE, OSI_GET_CURRENT_CRED(),
524                          code);
525         if (!code) {
526             vattr.va_mode = 1;
527             vattr.va_uid = AFS_XFS_VNO_CLIP(params[0]);
528             vattr.va_gid = XFS_VICEMAGIC;
529             vattr.va_mask = AT_MODE | AT_UID | AT_GID;
530             AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
531         }
532         if (!code) {
533             vattr.va_mask = AT_NODEID;
534             AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
535         }
536         if (!code)
537             *inop = vattr.va_nodeid;
538         VN_RELE(vp);
539     }
540
541     if (code) {
542         /* remove partially created file. */
543         (void)vn_remove(name, UIO_SYSSPACE, RMFILE);
544
545         /* and directory if volume special file. */
546         if (createdDir) {
547             AFS_LOCK_VOL_CREATE();
548             (void)vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
549             AFS_UNLOCK_VOL_CREATE();
550         }
551     }
552     return code;
553 }
554
555 /* afs_syscall_icreatename64
556  * This is the icreatename64 entry point used by the combined EFS/XFS
557  * fileserver suite. The datap and datalen do not need to be set for EFS.
558  */
559 int
560 afs_syscall_icreatename64(int dev, int datap, int datalen, int paramp,
561                           int inop)
562 {
563     struct vfs *vfsp;
564     afs_inode_params_t param;
565     int code;
566     rval_t rval;
567     ino_t ino;
568
569
570     if (!afs_suser(NULL))
571         return EPERM;
572
573 #ifdef AFS_SGI65_ENV
574     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
575 #else
576     vfsp = vfs_devsearch(dev);
577 #endif
578     if (vfsp == NULL) {
579         return ENXIO;
580     }
581
582     AFS_COPYIN((char *)paramp, (char *)param, sizeof(afs_inode_params_t),
583                code);
584     if (vfsp->vfs_fstype == xfs_fstype) {
585         code = xfs_icreatename64(vfsp, datap, datalen, param, &ino);
586         if (code)
587             return code;
588         else {
589             AFS_COPYOUT((char *)&ino, (char *)inop, sizeof(ino_t), code);
590             return code;
591         }
592     } else if (vfsp->vfs_fstype == efs_fstype) {
593         code =
594             afs_syscall_icreate(dev, 0, param[0], param[1], param[2],
595                                 param[3], &rval);
596         if (code)
597             return code;
598         else {
599             ino = (ino_t) rval.r_val1;
600             AFS_COPYOUT((char *)&ino, (char *)inop, sizeof(ino_t), code);
601             return code;
602         }
603     }
604     return ENXIO;
605 }
606 #endif /* AFS_SGI_XFS_IOPS_ENV */
607
608 /*
609  * iopen system calls -- open an inode for reading/writing
610  * Restricted to super user.
611  * Any IFREG files.
612  * The original EFS only system calls are still present in the kernel for
613  * in case a kernel upgrade is done for a fix, but the EFS fileserver is
614  * still in use.
615  */
616 struct iopenargs {
617     sysarg_t dev;
618     sysarg_t inode;
619     sysarg_t usrmod;
620 };
621
622 #ifdef AFS_SGI_XFS_IOPS_ENV
623 struct iopenargs64 {
624     sysarg_t dev;
625     sysarg_t inode_hi;
626     sysarg_t inode_lo;
627     sysarg_t usrmod;
628 };
629
630 #ifdef AFS_SGI65_ENV
631 int
632 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t * rvp)
633 {
634     struct file *fp;
635     int fd;
636     int error;
637     struct vfs *vfsp;
638     struct vnode *vp;
639
640     AFS_STATCNT(afs_syscall_iopen);
641     if (!afs_suser(NULL))
642         return EPERM;
643     vfsp = vfs_devsearch(dev, xfs_fstype);
644     if (!vfsp)
645         vfsp = vfs_devsearch(dev, efs_fstype);
646     if (!vfsp)
647         return ENXIO;
648
649 #ifdef AFS_SGI_EFS_IOPS_ENV
650     if (vfsp->vfs_fstype == efs_fstype) {
651         struct inode *ip;
652         if (error = igetinode(vfsp, (dev_t) dev, inode, &ip))
653             return error;
654         vp = EFS_ITOV(ip);
655         if (error = vfile_alloc((usrmod + 1) & (FMASK), &fp, &fd)) {
656             iput(ip);
657             return error;
658         }
659         iunlock(ip);
660     } else
661 #endif /* AFS_SGI_EFS_IOPS_ENV */
662     if (vfsp->vfs_fstype == xfs_fstype) {
663         struct xfs_inode *xip;
664         if (error = xfs_igetinode(vfsp, (dev_t) dev, inode, &xip))
665             return error;
666         vp = XFS_ITOV(xip);
667         if (error = vfile_alloc((usrmod + 1) & (FMASK), &fp, &fd)) {
668             VN_RELE(vp);
669             return error;
670         }
671     } else {
672         osi_Panic("afs_syscall_iopen: bad fstype = %d\n", vfsp->vfs_fstype);
673     }
674     vfile_ready(fp, vp);
675     rvp->r_val1 = fd;
676     return 0;
677 }
678 #else
679 /* afs_syscall_iopen
680  * EFS/XFS version vectors to correct code based vfs_fstype. Expects a
681  * 64 bit inode number.
682  */
683 int
684 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t * rvp)
685 {
686     struct file *fp;
687     int fd;
688     int error;
689     struct vfs *vfsp;
690
691     AFS_STATCNT(afs_syscall_iopen);
692     if (!afs_suser(NULL))
693         return EPERM;
694     vfsp = vfs_devsearch(dev);
695     if (!vfsp) {
696         return ENXIO;
697     }
698
699     if (vfsp->vfs_fstype == xfs_fstype) {
700         struct xfs_inode *xip;
701         struct vnode *vp;
702         if (error = xfs_igetinode(vfsp, (dev_t) dev, inode, &xip))
703             return error;
704         vp = XFS_ITOV(xip);
705         if (error = falloc(vp, (usrmod + 1) & (FMASK), &fp, &fd)) {
706             VN_RELE(vp);
707             return error;
708         }
709     } else if (vfsp->vfs_fstype == efs_fstype) {
710         struct inode *ip;
711         if (error = igetinode(vfsp, (dev_t) dev, inode, &ip))
712             return error;
713         if (error = falloc(EFS_ITOV(ip), (usrmod + 1) & (FMASK), &fp, &fd)) {
714             iput(ip);
715             return error;
716         }
717         iunlock(ip);
718     } else {
719         osi_Panic("afs_syscall_iopen: bad fstype = %d\n", vfsp->vfs_fstype);
720     }
721     fready(fp);
722     rvp->r_val1 = fd;
723     return 0;
724 }
725 #endif /* AFS_SGI65_ENV */
726
727 int
728 iopen(struct iopenargs *uap, rval_t * rvp)
729 {
730     AFS_STATCNT(iopen);
731     return (afs_syscall_iopen
732             (uap->dev, (ino_t) uap->inode, uap->usrmod, rvp));
733 }
734
735 int
736 iopen64(struct iopenargs64 *uap, rval_t * rvp)
737 {
738     AFS_STATCNT(iopen);
739     return (afs_syscall_iopen
740             (uap->dev, (ino_t) ((uap->inode_hi << 32) | uap->inode_lo),
741              uap->usrmod, rvp));
742 }
743
744 #else /* AFS_SGI_XFS_IOPS_ENV */
745 /* iopen/afs_syscall_iopen
746  *
747  * Original EFS only 32 bit iopen call.
748  */
749 int
750 iopen(struct iopenargs *uap, rval_t * rvp)
751 {
752     AFS_STATCNT(iopen);
753     return (afs_syscall_iopen(uap->dev, uap->inode, uap->usrmod, rvp));
754 }
755
756 int
757 afs_syscall_iopen(dev, inode, usrmod, rvp)
758      int dev, inode, usrmod;
759      rval_t *rvp;
760 {
761     struct file *fp;
762     struct inode *ip;
763     int fd;
764     int error;
765
766     AFS_STATCNT(afs_syscall_iopen);
767     if (!afs_suser(NULL))
768         return EPERM;
769     if (error = igetinode(0, (dev_t) dev, inode, &ip))
770         return error;
771     if (error = falloc(EFS_ITOV(ip), (usrmod + 1) & (FMASK), &fp, &fd)) {
772         iput(ip);
773         return error;
774     }
775     iunlock(ip);
776     rvp->r_val1 = fd;
777 #ifdef  AFS_SGI53_ENV
778     fready(fp);
779 #endif
780     return 0;
781 }
782 #endif /* AFS_SGI_XFS_IOPS_ENV */
783
784 /*
785  * Support for iinc() and idec() system calls--increment or decrement
786  * count on inode.
787  * Restricted to super user.
788  * Only VICEMAGIC type inodes.
789  */
790 #ifdef AFS_SGI_XFS_IOPS_ENV
791 #ifdef AFS_SGI_EFS_IOPS_ENV
792 /* efs_iincdec
793  *
794  * XFS/EFS iinc/idec code for EFS. Uses 32 bit inode numbers. 
795  */
796 static int
797 efs_iincdec(vfsp, inode, inode_p1, amount)
798      struct vfs *vfsp;
799      int inode, inode_p1, amount;
800 {
801     struct inode *ip;
802     int error;
803
804     if (error = igetinode(vfsp, NULL, inode, &ip))
805         return error;
806
807     if (!IS_VICEMAGIC(ip))
808         error = EPERM;
809     else if (((struct afsparms *)ip->i_afs)->vicep1 != inode_p1)
810         error = ENXIO;
811     else {
812         ip->i_nlink += amount;
813         osi_Assert(ip->i_nlink >= 0);
814         if (ip->i_nlink == 0) {
815             CLEAR_VICEMAGIC(ip);
816             afsidestroy(ip);
817         }
818         ip->i_flags |= ICHG;
819     }
820     /* XXX sync write?? */
821     iput(ip);
822     return error;
823 }
824 #endif /* AFS_SGI_EFS_IOPS_ENV */
825
826 /* xfs_iincdec
827  *
828  * XFS/EFS iinc/idec code for EFS. Uses 64 bit inode numbers. 
829  */
830 static int
831 xfs_iincdec64(struct vfs *vfsp, ino_t inode, int inode_p1, int amount)
832 {
833     vnode_t *vp;
834     xfs_inode_t *ip;
835     int code = 0;
836     afs_xfs_attr_t attrs;
837     int length = SIZEOF_XFS_ATTR_T;
838     afs_xfs_dattr_t dattr;
839     struct vattr vattr;
840     int nlink;
841     int vol;
842
843     code =
844         xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
845                  (void *)0, (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
846                  (daddr_t) 0);
847     if (code)
848         return code;
849
850     vp = XFS_ITOV(ip);
851     xfs_iunlock(ip, XFS_ILOCK_SHARED);
852
853     vattr.va_mask = AT_GID | AT_UID | AT_MODE;
854     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
855     if (code)
856         code = EPERM;
857
858     if (!code && (vattr.va_gid != XFS_VICEMAGIC))
859         code = EPERM;
860
861     if (!code && (AFS_XFS_VNO_CLIP(inode_p1) != vattr.va_uid))
862         code = ENXIO;
863
864     if (code) {
865         VN_RELE(vp);
866         return code;
867     }
868
869     nlink = vattr.va_mode & AFS_XFS_MODE_LINK_MASK;
870     nlink += amount;
871     if (nlink > 07) {
872         code = EOVERFLOW;
873     }
874     if (nlink > 0) {
875         vattr.va_mode &= ~AFS_XFS_MODE_LINK_MASK;
876         vattr.va_mode |= nlink;
877         vattr.va_mask = AT_MODE;
878         AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
879         VN_RELE(vp);
880         return code;
881     } else {
882         char path[64];
883         b64_string_t stmp1, stmp2;
884         vnode_t *dvp;
885         xfs_inode_t *ip;
886
887         length = SIZEOF_XFS_ATTR_T;
888         AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT,
889                          OSI_GET_CURRENT_CRED(), code);
890         VN_RELE(vp);
891         if (!code) {
892             if (length != SIZEOF_XFS_ATTR_T
893                 || attrs.at_attr_version != AFS_XFS_ATTR_VERS)
894                 return EINVAL;
895         }
896         /* Get the vnode for the directory this file is in. */
897         if (!attrs.at_pino)
898             return ENOENT;
899
900         code = xfs_getinode(vp->v_vfsp, NULL, attrs.at_pino, &ip);
901         if (code)
902             return code;
903
904         dvp = XFS_ITOV(ip);
905         xfs_iunlock(ip, XFS_ILOCK_SHARED);
906
907         /* Verify directory attributes. */
908         length = SIZEOF_XFS_DATTR_T;
909         AFS_VOP_ATTR_GET(dvp, AFS_XFS_DATTR, (char *)&dattr, &length,
910                          ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
911         if (!code) {
912             if (length != SIZEOF_XFS_DATTR_T
913                 || dattr.atd_version != AFS_XFS_ATD_VERS)
914                 code = ENXIO;
915         }
916         if (code) {
917             VN_RELE(dvp);
918             return code;
919         }
920
921         strcpy(path, ".");
922         strcat(path, int_to_base64(stmp1, attrs.at_param[2]));
923         strcat(path, ".");
924         strcat(path, int_to_base64(stmp1, attrs.at_tag));
925
926         AFS_VOP_REMOVE(dvp, path, OSI_GET_CURRENT_CRED(), code);
927
928         if (!code) {
929             int code2;
930             vattr.va_mask = AT_NLINK;
931             AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(), code2);
932             if (!code2) {
933                 if (vattr.va_nlink == 2) {
934                     vnode_t *ddvp;      /* parent of volume directory. */
935                     /* Try to remove the directory if this is a volume
936                      * special file. It's ok to fail.
937                      */
938                     AFS_VOP_LOOKUP(dvp, "..", &ddvp, (struct pathname *)NULL,
939                                    0, OSI_GET_CURRENT_RDIR(),
940                                    OSI_GET_CURRENT_CRED(), code2);
941                     if (!code2) {
942                         VN_RELE(dvp);
943                         dvp = (vnode_t *) 0;
944                         strcpy(path, ".");
945                         if (attrs.at_name_version == AFS_XFS_NAME_VERS2)
946                             strcpy(path, AFS_INODE_DIR_NAME);
947                         else
948                             strcpy(path, ".");
949                         int_to_base64(stmp1,
950                                       (attrs.at_param[1] ==
951                                        INODESPECIAL) ? attrs.
952                                       at_param[3] : attrs.at_param[0]);
953                         strcat(path, stmp1);
954                         AFS_LOCK_VOL_CREATE();
955                         AFS_VOP_RMDIR(ddvp, path, OSI_GET_CURRENT_CDIR(),
956                                       OSI_GET_CURRENT_CRED(), code2);
957                         AFS_UNLOCK_VOL_CREATE();
958                         VN_RELE(ddvp);
959                     }
960                 }
961             }
962         }
963         if (dvp)
964             VN_RELE(dvp);
965     }
966     return code;
967 }
968
969 int
970 iincdec64(int dev, int inode_hi, int inode_lo, int inode_p1, int amount)
971 {
972     struct vfs *vfsp;
973
974     if (!afs_suser(NULL))
975         return EPERM;
976 #ifdef AFS_SGI65_ENV
977     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
978 #else
979     vfsp = vfs_devsearch(dev);
980 #endif
981     if (!vfsp) {
982         return ENXIO;
983     }
984
985     if (vfsp->vfs_fstype == xfs_fstype) {
986         ino_t inode;
987         inode = inode_hi;
988         inode <<= 32;
989         inode |= inode_lo;
990         return xfs_iincdec64(vfsp, inode, inode_p1, amount);
991     }
992 #ifdef AFS_SGI_EFS_IOPS_ENV
993     else if (vfsp->vfs_fstype == efs_fstype) {
994         return efs_iincdec(vfsp, inode_lo, inode_p1, amount);
995     }
996 #endif /* AFS_SGI_EFS_IOPS_ENV */
997     return ENXIO;
998 }
999
1000 int
1001 afs_syscall_idec64(int dev, int inode_hi, int inode_lo, int inode_p1)
1002 {
1003     return iincdec64(dev, inode_hi, inode_lo, inode_p1, -1);
1004 }
1005
1006 int
1007 afs_syscall_iinc64(int dev, int inode_hi, int inode_lo, int inode_p1)
1008 {
1009     return iincdec64(dev, inode_hi, inode_lo, inode_p1, 1);
1010 }
1011
1012
1013
1014
1015 struct iincargs {
1016     sysarg_t dev;
1017     sysarg_t inode;
1018     sysarg_t inode_p1;
1019 };
1020
1021 #ifdef AFS_SGI65_ENV
1022 int
1023 iinc(struct iincargs *uap, rval_t * rvp)
1024 {
1025     AFS_STATCNT(iinc);
1026     return ENOTSUP;
1027 }
1028
1029 int
1030 idec(struct iincargs *uap, rval_t * rvp)
1031 {
1032     AFS_STATCNT(idec);
1033     return ENOTSUP;
1034 }
1035 #else
1036 /* iincdec
1037  *
1038  * XFS/EFS iinc/idec entry points for EFS only fileservers.
1039  *
1040  */
1041 int
1042 iincdec(dev, inode, inode_p1, amount)
1043      int dev, inode, inode_p1, amount;
1044 {
1045     struct vfs *vfsp;
1046
1047     if (!afs_suser(NULL))
1048         return EPERM;
1049     vfsp = vfs_devsearch(dev);
1050     if (!vfsp) {
1051         return ENXIO;
1052     }
1053     if (vfsp->vfs_fstype != efs_fstype)
1054         return ENOSYS;
1055
1056     return efs_iincdec(vfsp, inode, inode_p1, amount);
1057 }
1058
1059 int
1060 iinc(struct iincargs *uap, rval_t * rvp)
1061 {
1062     AFS_STATCNT(iinc);
1063     return (iincdec(uap->dev, uap->inode, uap->inode_p1, 1));
1064 }
1065
1066 int
1067 idec(struct iincargs *uap, rval_t * rvp)
1068 {
1069     AFS_STATCNT(idec);
1070     return (iincdec(uap->dev, uap->inode, uap->inode_p1, -1));
1071 }
1072 #endif /* AFS_SGI65_ENV */
1073
1074 #else /* AFS_SGI_XFS_IOPS_ENV */
1075 /* afs_syscall_iincdec iinc idec
1076  *
1077  * These are the original EFS only entry points.
1078  */
1079 int
1080 afs_syscall_iincdec(dev, inode, inode_p1, amount)
1081      int dev, inode, inode_p1, amount;
1082 {
1083     struct inode *ip;
1084     int error = 0;
1085
1086     if (!afs_suser(NULL))
1087         return EPERM;
1088     if (error = igetinode(0, (dev_t) dev, inode, &ip))
1089         return error;
1090
1091     if (!IS_VICEMAGIC(ip))
1092         error = EPERM;
1093     else if (((struct afsparms *)ip->i_afs)->vicep1 != inode_p1)
1094         error = ENXIO;
1095     else {
1096         ip->i_nlink += amount;
1097         osi_Assert(ip->i_nlink >= 0);
1098         if (ip->i_nlink == 0) {
1099             CLEAR_VICEMAGIC(ip);
1100             afsidestroy(ip);
1101         }
1102         ip->i_flags |= ICHG;
1103     }
1104     /* XXX sync write?? */
1105     iput(ip);
1106     return error;
1107 }
1108
1109 struct iincargs {
1110     sysarg_t dev;
1111     sysarg_t inode;
1112     sysarg_t inode_p1;
1113 };
1114
1115 int
1116 iinc(struct iincargs *uap, rval_t * rvp)
1117 {
1118     AFS_STATCNT(iinc);
1119     return (afs_syscall_iincdec(uap->dev, uap->inode, uap->inode_p1, 1));
1120 }
1121
1122 int
1123 idec(struct iincargs *uap, rval_t * rvp)
1124 {
1125     AFS_STATCNT(idec);
1126     return (afs_syscall_iincdec(uap->dev, uap->inode, uap->inode_p1, -1));
1127 }
1128 #endif /* AFS_SGI_XFS_IOPS_ENV */
1129
1130 #ifdef AFS_SGI_XFS_IOPS_ENV
1131 /* afs_syscall_ilistinode64
1132  * Gathers up all required info for ListViceInodes in one system call.
1133  */
1134 int
1135 afs_syscall_ilistinode64(int dev, int inode_hi, int inode_lo, int datap,
1136                          int datalenp)
1137 {
1138     int code = 0;
1139     ino_t inode;
1140     xfs_inode_t *ip;
1141     vfs_t *vfsp;
1142     vnode_t *vp;
1143     struct vattr vattr;
1144     afs_xfs_attr_t attrs;
1145     int length;
1146     i_list_inode_t data;
1147     int idatalen;
1148
1149     if (!afs_suser(NULL))
1150         return EPERM;
1151 #ifdef AFS_SGI65_ENV
1152     vfsp = vfs_devsearch(dev, xfs_fstype);
1153 #else
1154     vfsp = vfs_devsearch(dev);
1155 #endif
1156     if (!vfsp) {
1157         return ENXIO;
1158     }
1159 #ifndef AFS_SGI65_ENV
1160     if (vfsp->vfs_fstype != xfs_fstype)
1161         return ENOSYS;
1162 #endif
1163
1164     AFS_COPYIN((char *)datalenp, &idatalen, sizeof(int), code);
1165     if (idatalen < sizeof(i_list_inode_t)) {
1166         idatalen = sizeof(i_list_inode_t);
1167         AFS_COPYOUT((char *)datalenp, (char *)&idatalen, sizeof(int), code);
1168         return E2BIG;
1169     }
1170     idatalen = sizeof(i_list_inode_t);
1171     AFS_COPYOUT((char *)datalenp, (char *)&idatalen, sizeof(int), code);
1172
1173     AFS_COPYIN((char *)datap, (char *)&data, sizeof(i_list_inode_t), code);
1174     if (data.ili_version != AFS_XFS_ILI_VERSION) {
1175         data.ili_version = AFS_XFS_ILI_VERSION;
1176         AFS_COPYOUT((char *)&data, (char *)datap, sizeof(i_list_inode_t),
1177                     code);
1178         return EINVAL;
1179     }
1180
1181
1182     inode = inode_hi;
1183     inode <<= 32;
1184     inode |= inode_lo;
1185     code =
1186         xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
1187                  (void *)0, (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
1188                  (daddr_t) 0);
1189     if (code)
1190         return code;
1191
1192     vp = XFS_ITOV(ip);
1193     xfs_iunlock(ip, XFS_ILOCK_SHARED);
1194
1195     length = SIZEOF_XFS_ATTR_T;
1196
1197     AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT,
1198                      OSI_GET_CURRENT_CRED(), code);
1199     if (code) {
1200         code = EPERM;
1201     }
1202
1203     if (!code) {
1204         if (attrs.at_attr_version != AFS_XFS_ATTR_VERS)
1205             code = EINVAL;
1206     }
1207
1208     if (!code) {
1209         vattr.va_mask = AT_STAT;
1210         AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
1211     }
1212
1213     if (!code) {
1214         memset((char *)&data, 0, sizeof(data));
1215         data.ili_info.inodeNumber = inode;
1216         data.ili_info.byteCount = vattr.va_size;
1217         data.ili_info.linkCount = (vattr.va_mode & AFS_XFS_MODE_LINK_MASK);
1218         memcpy((char *)data.ili_info.param, (char *)attrs.at_param,
1219                sizeof(data.ili_info.param));
1220         data.ili_attr_version = attrs.at_attr_version;
1221         data.ili_name_version = attrs.at_name_version;
1222         data.ili_tag = attrs.at_tag;
1223         data.ili_pino = attrs.at_pino;
1224         data.ili_vno = vattr.va_uid;
1225         data.ili_magic = vattr.va_gid;
1226         AFS_COPYOUT((char *)&data, (char *)datap, sizeof(data), code);
1227     }
1228     VN_RELE(vp);
1229     return code;
1230 }
1231 #endif /* AFS_SGI_XFS_IOPS_ENV */