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