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