300308c25ba18855780720a9c920c41eae149ba0
[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("$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, NULL, &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, NULL,
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, NULL,
454                                       &dvp);
455             }
456             if (code) {
457                 AFS_UNLOCK_VOL_CREATE();
458                 return code;
459             }
460         }
461         else
462             createdDir = 1;
463         memset((char*)&dattr, 0, 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     memset((char*)&attrs, 0, 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         memcpy((char*)attrs.at_param, (char*)params, sizeof(afs_inode_params_t));
514         attrs.at_attr_version = AFS_XFS_ATTR_VERS;
515         attrs.at_name_version = name_version;
516         AFS_VOP_ATTR_SET(vp, AFS_XFS_ATTR, (char*)&attrs,
517                          SIZEOF_XFS_ATTR_T,
518                          ATTR_ROOT|ATTR_CREATE, OSI_GET_CURRENT_CRED(),
519                          code);
520         if (!code) {
521             vattr.va_mode = 1;
522             vattr.va_uid = AFS_XFS_VNO_CLIP(params[0]);
523             vattr.va_gid = XFS_VICEMAGIC;
524             vattr.va_mask = AT_MODE | AT_UID | AT_GID;
525             AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
526         }
527         if (!code) {
528             vattr.va_mask = AT_NODEID;
529             AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
530         }
531         if (!code)
532             *inop = vattr.va_nodeid;
533         VN_RELE(vp);
534     }
535
536     if (code) {
537         /* remove partially created file. */
538         (void) vn_remove(name, UIO_SYSSPACE, RMFILE);
539         
540         /* and directory if volume special file. */
541         if (createdDir) {
542             AFS_LOCK_VOL_CREATE();
543             (void) vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
544             AFS_UNLOCK_VOL_CREATE();
545         }
546     }
547     return code;
548 }
549
550 /* afs_syscall_icreatename64
551  * This is the icreatename64 entry point used by the combined EFS/XFS
552  * fileserver suite. The datap and datalen do not need to be set for EFS.
553  */
554 int
555 afs_syscall_icreatename64(int dev, int datap, int datalen, int paramp,
556                           int inop)
557 {
558     struct vfs *vfsp;
559     afs_inode_params_t param;
560     int code;
561     rval_t rval;
562     ino_t ino;
563
564
565     if (!afs_suser())
566         return EPERM;
567
568 #ifdef AFS_SGI65_ENV
569     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
570 #else
571     vfsp = vfs_devsearch(dev);
572 #endif
573     if (vfsp == NULL) {
574         return ENXIO;
575     }
576
577     AFS_COPYIN((char*)paramp, (char*)param, sizeof(afs_inode_params_t), code);
578     if (vfsp->vfs_fstype == xfs_fstype) {
579         code =  xfs_icreatename64(vfsp, datap, datalen, param, &ino);
580         if (code)
581             return code;
582         else {
583             AFS_COPYOUT((char*)&ino, (char*)inop, sizeof(ino_t), code);
584             return code;
585         }
586     }
587     else if (vfsp->vfs_fstype == efs_fstype) {
588         code = afs_syscall_icreate(dev, 0, param[0], param[1], param[2],
589                                    param[3], &rval);
590         if (code)
591             return code;
592         else {
593             ino = (ino_t)rval.r_val1;
594             AFS_COPYOUT((char*)&ino, (char*)inop, sizeof(ino_t), code);
595             return code;
596         }
597     }
598     return ENXIO;
599 }
600 #endif /* AFS_SGI_XFS_IOPS_ENV */
601
602 /*
603  * iopen system calls -- open an inode for reading/writing
604  * Restricted to super user.
605  * Any IFREG files.
606  * The original EFS only system calls are still present in the kernel for
607  * in case a kernel upgrade is done for a fix, but the EFS fileserver is
608  * still in use.
609  */
610 struct iopenargs {
611         sysarg_t        dev;
612         sysarg_t        inode;
613         sysarg_t        usrmod;
614 };
615
616 #ifdef AFS_SGI_XFS_IOPS_ENV
617 struct iopenargs64 {
618         sysarg_t        dev;
619         sysarg_t        inode_hi;
620         sysarg_t        inode_lo;
621         sysarg_t        usrmod;
622 };
623
624 #ifdef AFS_SGI65_ENV
625 int
626 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t *rvp)
627 {
628         struct file *fp;
629         int fd;
630         int error;
631         struct vfs* vfsp;
632         struct vnode *vp;
633
634         AFS_STATCNT(afs_syscall_iopen);
635         if (!afs_suser())
636                 return EPERM;
637         vfsp = vfs_devsearch(dev, xfs_fstype);
638         if (!vfsp)
639             vfsp = vfs_devsearch(dev, efs_fstype);
640         if (!vfsp)
641             return ENXIO;
642
643 #ifdef AFS_SGI_EFS_IOPS_ENV
644         if (vfsp->vfs_fstype == efs_fstype) {
645             struct inode *ip;
646             if (error = igetinode(vfsp, (dev_t)dev, inode, &ip))
647                 return error;
648             vp = EFS_ITOV(ip);
649             if (error = vfile_alloc((usrmod+1) & (FMASK), &fp, &fd)) {
650                 iput(ip);
651                 return error;
652             }
653             iunlock(ip);
654         }
655         else 
656 #endif /* AFS_SGI_EFS_IOPS_ENV */
657           if (vfsp->vfs_fstype == xfs_fstype) {
658               struct xfs_inode *xip;
659               if (error = xfs_igetinode(vfsp, (dev_t)dev, inode, &xip))
660                   return error;
661               vp = XFS_ITOV(xip);
662               if (error = vfile_alloc((usrmod+1) & (FMASK), &fp, &fd)) {
663                   VN_RELE(vp);
664                   return error;
665               }
666           }
667           else {
668               osi_Panic("afs_syscall_iopen: bad fstype = %d\n",
669                         vfsp->vfs_fstype);
670           }
671         vfile_ready(fp, vp);
672         rvp->r_val1 = fd;
673         return 0;
674 }
675 #else
676 /* afs_syscall_iopen
677  * EFS/XFS version vectors to correct code based vfs_fstype. Expects a
678  * 64 bit inode number.
679  */
680 int
681 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t *rvp)
682 {
683         struct file *fp;
684         int fd;
685         int error;
686         struct vfs* vfsp;
687
688         AFS_STATCNT(afs_syscall_iopen);
689         if (!afs_suser())
690                 return EPERM;
691         vfsp = vfs_devsearch(dev);
692         if (!vfsp) {
693             return ENXIO;
694         }
695
696         if (vfsp->vfs_fstype == xfs_fstype) {
697             struct xfs_inode *xip;
698             struct vnode *vp;
699             if (error = xfs_igetinode(vfsp, (dev_t)dev, inode, &xip))
700                 return error;
701             vp = XFS_ITOV(xip);
702             if (error = falloc(vp, (usrmod+1) & (FMASK), &fp, &fd)) {
703                 VN_RELE(vp);
704                 return error;
705             }
706         }
707         else if (vfsp->vfs_fstype == efs_fstype) {
708             struct inode *ip;
709             if (error = igetinode(vfsp, (dev_t)dev, inode, &ip))
710                 return error;
711             if (error = falloc(EFS_ITOV(ip), (usrmod+1) & (FMASK), &fp, &fd)) {
712                 iput(ip);
713                 return error;
714             }
715             iunlock(ip);
716         }
717         else {
718             osi_Panic("afs_syscall_iopen: bad fstype = %d\n",
719                       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(uap->dev, (ino_t)uap->inode, uap->usrmod,
732                                rvp));
733 }
734
735 int
736 iopen64(struct iopenargs64 *uap, rval_t *rvp)
737 {
738      AFS_STATCNT(iopen);
739      return (afs_syscall_iopen(uap->dev,
740                                (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())
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 efs_iincdec(vfsp, inode, inode_p1, amount)
797 struct vfs *vfsp;
798 int inode, inode_p1, amount;
799 {
800     struct inode *ip;
801     int error;
802
803     if (error = igetinode(vfsp, NULL, inode, &ip))
804         return error;
805     
806     if (!IS_VICEMAGIC(ip))
807         error = EPERM;
808     else if (((struct afsparms *)ip->i_afs)->vicep1 != inode_p1)
809         error = ENXIO;
810     else {
811         ip->i_nlink += amount;
812         osi_Assert(ip->i_nlink >= 0);
813         if (ip->i_nlink == 0) {
814             CLEAR_VICEMAGIC(ip);
815             afsidestroy(ip);
816         }
817         ip->i_flags |= ICHG;
818     }
819     /* XXX sync write?? */
820     iput(ip);
821     return error;
822 }
823 #endif /* AFS_SGI_EFS_IOPS_ENV */
824
825 /* xfs_iincdec
826  *
827  * XFS/EFS iinc/idec code for EFS. Uses 64 bit inode numbers. 
828  */
829 static int xfs_iincdec64(struct vfs *vfsp, ino_t inode, int inode_p1,
830                          int amount)
831 {
832     vnode_t *vp;
833     xfs_inode_t *ip;
834     int code = 0;
835     afs_xfs_attr_t attrs;
836     int length = SIZEOF_XFS_ATTR_T;
837     afs_xfs_dattr_t dattr;
838     struct vattr vattr;
839     int nlink;
840     int vol;
841     
842     code = xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
843                     (void*)0, (xfs_ino_t)inode, XFS_ILOCK_SHARED, &ip, 
844                     (daddr_t)0);
845     if (code)
846         return code;
847
848     vp = XFS_ITOV(ip);
849     xfs_iunlock(ip, XFS_ILOCK_SHARED);
850     
851     vattr.va_mask = AT_GID | AT_UID | AT_MODE;
852     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
853     if (code) 
854         code = EPERM;
855
856     if (!code && (vattr.va_gid != XFS_VICEMAGIC))
857         code = EPERM;
858         
859     if (!code && (AFS_XFS_VNO_CLIP(inode_p1) != vattr.va_uid))
860         code = ENXIO;
861
862     if (code) {
863         VN_RELE(vp);
864         return code;
865     }
866
867     nlink = vattr.va_mode & AFS_XFS_MODE_LINK_MASK;
868     nlink += amount;
869     if (nlink > 07) {
870         code = EOVERFLOW;
871     }
872     if (nlink > 0) {
873         vattr.va_mode &= ~AFS_XFS_MODE_LINK_MASK;
874         vattr.va_mode |= nlink;
875         vattr.va_mask = AT_MODE;
876         AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
877         VN_RELE(vp);
878         return code;
879     }
880     else {
881         char path[64];
882         b64_string_t stmp1, stmp2;
883         vnode_t *dvp;
884         xfs_inode_t *ip;
885             
886         length = SIZEOF_XFS_ATTR_T;
887         AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char*)&attrs, &length,
888                                 ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
889         VN_RELE(vp);
890         if (!code) {
891             if (length != SIZEOF_XFS_ATTR_T
892                 || attrs.at_attr_version != AFS_XFS_ATTR_VERS)
893                 return EINVAL;
894         }
895         /* Get the vnode for the directory this file is in. */
896         if (!attrs.at_pino)
897             return ENOENT;
898
899         code = xfs_getinode(vp->v_vfsp, NULL, attrs.at_pino, &ip);
900         if (code)
901             return code;
902
903         dvp = XFS_ITOV(ip);
904         xfs_iunlock(ip, XFS_ILOCK_SHARED);
905
906         /* Verify directory attributes. */
907         length = SIZEOF_XFS_DATTR_T;
908         AFS_VOP_ATTR_GET(dvp, AFS_XFS_DATTR , (char*)&dattr, &length,
909                          ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
910         if (!code) {
911             if (length != SIZEOF_XFS_DATTR_T
912                 || dattr.atd_version != AFS_XFS_ATD_VERS)
913                 code = ENXIO;
914         }
915         if (code) {
916             VN_RELE(dvp);
917             return code;
918         }
919
920         strcpy(path, ".");
921         strcat(path, int_to_base64(stmp1, attrs.at_param[2]));
922         strcat(path, ".");
923         strcat(path, int_to_base64(stmp1, attrs.at_tag));
924             
925         AFS_VOP_REMOVE(dvp, path, OSI_GET_CURRENT_CRED(), code);
926                 
927         if (!code) {
928             int code2;
929             vattr.va_mask = AT_NLINK;
930             AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(),
931                             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,
939                                    (struct pathname *)NULL,
940                                    0, OSI_GET_CURRENT_RDIR(),
941                                    OSI_GET_CURRENT_CRED(), code2);
942                     if (!code2) {
943                         VN_RELE(dvp);
944                         dvp = (vnode_t*)0;
945                         strcpy(path, ".");
946                         if (attrs.at_name_version == AFS_XFS_NAME_VERS2)
947                             strcpy(path, AFS_INODE_DIR_NAME);
948                         else 
949                             strcpy(path, ".");
950                         int_to_base64(stmp1,
951                                       (attrs.at_param[1] == INODESPECIAL) ?
952                                       attrs.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())
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 iinc(struct iincargs *uap, rval_t *rvp) {
1023     AFS_STATCNT(iinc);
1024     return ENOTSUP;
1025 }
1026 int idec(struct iincargs *uap, rval_t *rvp) {
1027     AFS_STATCNT(idec);
1028     return ENOTSUP;
1029 }
1030 #else
1031 /* iincdec
1032  *
1033  * XFS/EFS iinc/idec entry points for EFS only fileservers.
1034  *
1035  */
1036 int
1037 iincdec(dev, inode, inode_p1, amount)
1038 int dev, inode, inode_p1, amount;
1039 {
1040     struct vfs *vfsp;
1041     
1042     if (!afs_suser())
1043         return EPERM;
1044     vfsp = vfs_devsearch(dev);
1045     if (!vfsp) {
1046         return ENXIO;
1047     }
1048     if (vfsp->vfs_fstype != efs_fstype)
1049         return ENOSYS;
1050
1051     return efs_iincdec(vfsp, inode, inode_p1, amount);
1052 }
1053 int
1054 iinc(struct iincargs *uap, rval_t *rvp) {
1055     AFS_STATCNT(iinc);
1056     return (iincdec(uap->dev, uap->inode, uap->inode_p1, 1));
1057 }
1058
1059 int
1060 idec(struct iincargs *uap, rval_t *rvp) {
1061     AFS_STATCNT(idec);
1062     return (iincdec(uap->dev, uap->inode, uap->inode_p1, -1));
1063 }
1064 #endif /* AFS_SGI65_ENV */
1065
1066 #else /* AFS_SGI_XFS_IOPS_ENV */
1067 /* afs_syscall_iincdec iinc idec
1068  *
1069  * These are the original EFS only entry points.
1070  */
1071 int
1072 afs_syscall_iincdec(dev, inode, inode_p1, amount)
1073 int dev, inode, inode_p1, amount;
1074 {
1075         struct inode *ip;
1076         int error = 0;
1077
1078         if (!afs_suser())
1079                 return EPERM;
1080         if (error = igetinode(0, (dev_t)dev, inode, &ip))
1081                 return error;
1082
1083         if (!IS_VICEMAGIC(ip))
1084             error = EPERM;
1085         else if (((struct afsparms *)ip->i_afs)->vicep1 != inode_p1)
1086             error = ENXIO;
1087         else {
1088                 ip->i_nlink += amount;
1089                 osi_Assert(ip->i_nlink >= 0);
1090                 if (ip->i_nlink == 0) {
1091                     CLEAR_VICEMAGIC(ip);
1092                     afsidestroy(ip);
1093                 }
1094                 ip->i_flags |= ICHG;
1095         }
1096         /* XXX sync write?? */
1097         iput(ip);
1098         return error;
1099 }
1100
1101 struct iincargs {
1102         sysarg_t        dev;
1103         sysarg_t        inode;
1104         sysarg_t        inode_p1;
1105 };
1106
1107 int
1108 iinc(struct iincargs *uap, rval_t *rvp) {
1109     AFS_STATCNT(iinc);
1110     return (afs_syscall_iincdec(uap->dev, uap->inode, uap->inode_p1, 1));
1111 }
1112
1113 int
1114 idec(struct iincargs *uap, rval_t *rvp) {
1115     AFS_STATCNT(idec);
1116     return (afs_syscall_iincdec(uap->dev, uap->inode, uap->inode_p1, -1));
1117 }
1118 #endif /* AFS_SGI_XFS_IOPS_ENV */
1119
1120 #ifdef AFS_SGI_XFS_IOPS_ENV
1121 /* afs_syscall_ilistinode64
1122  * Gathers up all required info for ListViceInodes in one system call.
1123  */
1124 int
1125 afs_syscall_ilistinode64(int dev, int inode_hi, int inode_lo,
1126                          int datap, int datalenp)
1127 {
1128     int code = 0;
1129     ino_t inode;
1130     xfs_inode_t *ip;
1131     vfs_t *vfsp;
1132     vnode_t *vp;
1133     struct vattr vattr;
1134     afs_xfs_attr_t attrs;
1135     int length;
1136     i_list_inode_t data;
1137     int idatalen;
1138
1139     if (!afs_suser())
1140         return EPERM;
1141 #ifdef AFS_SGI65_ENV
1142     vfsp = vfs_devsearch(dev, xfs_fstype);
1143 #else
1144     vfsp = vfs_devsearch(dev);
1145 #endif
1146     if (!vfsp) {
1147         return ENXIO;
1148     }
1149 #ifndef AFS_SGI65_ENV
1150     if (vfsp->vfs_fstype != xfs_fstype)
1151         return ENOSYS;
1152 #endif
1153
1154     AFS_COPYIN((char*)datalenp, &idatalen, sizeof(int), code);
1155     if (idatalen < sizeof(i_list_inode_t)) {
1156         idatalen = sizeof(i_list_inode_t);
1157         AFS_COPYOUT((char*)datalenp, (char*)&idatalen, sizeof(int), code);
1158         return E2BIG;
1159     }
1160     idatalen = sizeof(i_list_inode_t);
1161     AFS_COPYOUT((char*)datalenp, (char*)&idatalen, sizeof(int), code);
1162
1163     AFS_COPYIN((char*)datap, (char*)&data, sizeof(i_list_inode_t), code);
1164     if (data.ili_version != AFS_XFS_ILI_VERSION) {
1165         data.ili_version = AFS_XFS_ILI_VERSION;
1166         AFS_COPYOUT((char*)&data, (char*)datap, sizeof(i_list_inode_t), code);
1167         return EINVAL;
1168     }
1169     
1170     
1171     inode = inode_hi;
1172     inode <<= 32;
1173     inode |= inode_lo;
1174     code = xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)), 
1175                     (void*)0, (xfs_ino_t)inode,
1176                     XFS_ILOCK_SHARED, &ip, (daddr_t)0);
1177     if (code)
1178         return code;
1179     
1180     vp = XFS_ITOV(ip);
1181     xfs_iunlock(ip, XFS_ILOCK_SHARED);
1182     
1183     length = SIZEOF_XFS_ATTR_T;
1184
1185     AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char*)&attrs, &length,
1186                             ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
1187     if (code) { 
1188         code = EPERM;
1189     }
1190
1191     if (!code) {
1192         if (attrs.at_attr_version != AFS_XFS_ATTR_VERS)
1193             code = EINVAL;
1194     }
1195     
1196     if (!code) {
1197         vattr.va_mask = AT_STAT;
1198         AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
1199     }
1200     
1201     if (!code) {
1202         memset((char*)&data, 0, sizeof(data));
1203         data.ili_info.inodeNumber = inode;
1204         data.ili_info.byteCount = vattr.va_size;
1205         data.ili_info.linkCount = (vattr.va_mode & AFS_XFS_MODE_LINK_MASK);
1206         memcpy((char*)data.ili_info.param, (char*)attrs.at_param, sizeof(data.ili_info.param));
1207         data.ili_attr_version = attrs.at_attr_version;
1208         data.ili_name_version = attrs.at_name_version;
1209         data.ili_tag = attrs.at_tag;
1210         data.ili_pino = attrs.at_pino;
1211         data.ili_vno = vattr.va_uid;
1212         data.ili_magic = vattr.va_gid;
1213         AFS_COPYOUT((char*)&data, (char*)datap, sizeof(data), code);
1214     }
1215     VN_RELE(vp);
1216     return code;
1217 }
1218 #endif /* AFS_SGI_XFS_IOPS_ENV */