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