diff options
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 215 | ||||
-rw-r--r-- | sys/ufs/ufs/inode.h | 8 |
2 files changed, 192 insertions, 31 deletions
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index b3fef68..9247515 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -48,6 +48,7 @@ #include <sys/systm.h> #include <sys/buf.h> #include <sys/conf.h> +#include <sys/extattr.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/mount.h> @@ -82,7 +83,9 @@ static int ffs_read(struct vop_read_args *); static int ffs_write(struct vop_write_args *); static int ffs_extread(struct vnode *vp, struct uio *uio, int ioflag); static int ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred); +static int ffs_closeextattr(struct vop_closeextattr_args *); static int ffs_getextattr(struct vop_getextattr_args *); +static int ffs_openextattr(struct vop_openextattr_args *); static int ffs_setextattr(struct vop_setextattr_args *); @@ -95,7 +98,9 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_read_desc, (vop_t *) ffs_read }, { &vop_reallocblks_desc, (vop_t *) ffs_reallocblks }, { &vop_write_desc, (vop_t *) ffs_write }, + { &vop_closeextattr_desc, (vop_t *) ffs_closeextattr }, { &vop_getextattr_desc, (vop_t *) ffs_getextattr }, + { &vop_openextattr_desc, (vop_t *) ffs_openextattr }, { &vop_setextattr_desc, (vop_t *) ffs_setextattr }, { NULL, NULL } }; @@ -106,7 +111,9 @@ vop_t **ffs_specop_p; static struct vnodeopv_entry_desc ffs_specop_entries[] = { { &vop_default_desc, (vop_t *) ufs_vnoperatespec }, { &vop_fsync_desc, (vop_t *) ffs_fsync }, + { &vop_closeextattr_desc, (vop_t *) ffs_closeextattr }, { &vop_getextattr_desc, (vop_t *) ffs_getextattr }, + { &vop_openextattr_desc, (vop_t *) ffs_openextattr }, { &vop_setextattr_desc, (vop_t *) ffs_setextattr }, { NULL, NULL } }; @@ -117,7 +124,9 @@ vop_t **ffs_fifoop_p; static struct vnodeopv_entry_desc ffs_fifoop_entries[] = { { &vop_default_desc, (vop_t *) ufs_vnoperatefifo }, { &vop_fsync_desc, (vop_t *) ffs_fsync }, + { &vop_closeextattr_desc, (vop_t *) ffs_closeextattr }, { &vop_getextattr_desc, (vop_t *) ffs_getextattr }, + { &vop_openextattr_desc, (vop_t *) ffs_openextattr }, { &vop_setextattr_desc, (vop_t *) ffs_setextattr }, { NULL, NULL } }; @@ -999,7 +1008,7 @@ ffs_getpages(ap) } /* - * Extended attribute reading. + * Extended attribute area reading. */ static int ffs_extread(struct vnode *vp, struct uio *uio, int ioflag) @@ -1166,7 +1175,7 @@ ffs_extread(struct vnode *vp, struct uio *uio, int ioflag) } /* - * Extended attribute writing. + * Extended attribute area writing. */ static int ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *ucred) @@ -1379,8 +1388,123 @@ ffs_rdextattr(u_char **p, struct vnode *vp, struct thread *td, int extra) return (0); } +static int +ffs_open_ea(struct vnode *vp, struct ucred *cred, struct thread *td) +{ + struct inode *ip; + struct fs *fs; + struct ufs2_dinode *dp; + int error; + + ip = VTOI(vp); + fs = ip->i_fs; + + if (ip->i_ea_area != NULL) + return (EBUSY); + dp = ip->i_din2; + error = ffs_rdextattr(&ip->i_ea_area, vp, td, 0); + if (error) + return (error); + ip->i_ea_len = dp->di_extsize; + ip->i_ea_error = 0; + return (0); +} + /* - * Vnode operating to retrieve a named extended attribute. + * Vnode extattr transaction commit/abort + */ +static int +ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td) +{ + struct inode *ip; + struct fs *fs; + struct uio luio; + struct iovec liovec; + int error; + struct ufs2_dinode *dp; + + ip = VTOI(vp); + fs = ip->i_fs; + if (ip->i_ea_area == NULL) + return (EINVAL); + dp = ip->i_din2; + error = ip->i_ea_error; + if (commit && error == 0) { + liovec.iov_base = ip->i_ea_area; + liovec.iov_len = ip->i_ea_len; + luio.uio_iov = &liovec; + luio.uio_iovcnt = 1; + luio.uio_offset = 0; + luio.uio_resid = ip->i_ea_len; + luio.uio_segflg = UIO_SYSSPACE; + luio.uio_rw = UIO_WRITE; + luio.uio_td = td; + /* XXX: I'm not happy about truncating to zero size */ + if (ip->i_ea_len < dp->di_extsize) + error = ffs_truncate(vp, 0, IO_EXT, cred, td); + error = ffs_extwrite(vp, &luio, IO_EXT | IO_SYNC, cred); + } + free(ip->i_ea_area, M_TEMP); + ip->i_ea_area = NULL; + ip->i_ea_len = 0; + ip->i_ea_error = 0; + return (error); +} + +/* + * Vnode extattr transaction commit/abort + */ +int +ffs_openextattr(struct vop_openextattr_args *ap) +/* +struct vop_openextattr_args { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct inode *ip; + struct fs *fs; + + ip = VTOI(ap->a_vp); + fs = ip->i_fs; + if (fs->fs_magic == FS_UFS1_MAGIC) + return (ufs_vnoperate((struct vop_generic_args *)ap)); + return (ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td)); +} + + +/* + * Vnode extattr transaction commit/abort + */ +int +ffs_closeextattr(struct vop_closeextattr_args *ap) +/* +struct vop_closeextattr_args { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + int a_commit; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct inode *ip; + struct fs *fs; + + ip = VTOI(ap->a_vp); + fs = ip->i_fs; + if (fs->fs_magic == FS_UFS1_MAGIC) + return (ufs_vnoperate((struct vop_generic_args *)ap)); + return (ffs_close_ea(ap->a_vp, ap->a_commit, ap->a_cred, ap->a_td)); +} + + + +/* + * Vnode operation to retrieve a named extended attribute. */ int ffs_getextattr(struct vop_getextattr_args *ap) @@ -1402,7 +1526,7 @@ vop_getextattr { struct ufs2_dinode *dp; unsigned easize; uint32_t ul; - int error, ealen; + int error, ealen, stand_alone; ip = VTOI(ap->a_vp); fs = ip->i_fs; @@ -1410,11 +1534,22 @@ vop_getextattr { if (fs->fs_magic == FS_UFS1_MAGIC) return (ufs_vnoperate((struct vop_generic_args *)ap)); - dp = ip->i_din2; - error = ffs_rdextattr(&eae, ap->a_vp, ap->a_td, 0); + error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, + ap->a_cred, ap->a_td, IREAD); if (error) return (error); - easize = dp->di_extsize; + + if (ip->i_ea_area == NULL) { + error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); + if (error) + return (error); + stand_alone = 1; + } else { + stand_alone = 0; + } + dp = ip->i_din2; + eae = ip->i_ea_area; + easize = ip->i_ea_len; if (strlen(ap->a_name) > 0) { ealen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name, NULL, &p); @@ -1449,7 +1584,8 @@ vop_getextattr { } } } - free(eae, M_TEMP); + if (stand_alone) + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); return(error); } @@ -1474,10 +1610,9 @@ vop_setextattr { uint32_t ealength, ul; int ealen, olen, eacont, eapad1, eapad2, error, i, easize; u_char *eae, *p; - struct uio luio; - struct iovec liovec; struct ufs2_dinode *dp; struct ucred *cred; + int stand_alone; ip = VTOI(ap->a_vp); fs = ip->i_fs; @@ -1485,12 +1620,30 @@ vop_setextattr { if (fs->fs_magic == FS_UFS1_MAGIC) return (ufs_vnoperate((struct vop_generic_args *)ap)); + error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, + ap->a_cred, ap->a_td, IWRITE); + if (error) { + if (ip->i_ea_area != NULL && ip->i_ea_error == 0) + ip->i_ea_error = error; + return (error); + } + if (ap->a_cred != NOCRED) cred = ap->a_cred; else cred = ap->a_vp->v_mount->mnt_cred; + dp = ip->i_din2; + if (ip->i_ea_area == NULL) { + error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); + if (error) + return (error); + stand_alone = 1; + } else { + stand_alone = 0; + } + /* Calculate the length of the EA entry */ if (ap->a_uio == NULL) { /* delete */ @@ -1508,18 +1661,20 @@ vop_setextattr { ealength += eapad1 + ealen + eapad2; } - error = ffs_rdextattr(&eae, ap->a_vp, ap->a_td, ealength); - if (error) - return (error); + eae = malloc(ip->i_ea_len + ealength, M_TEMP, M_WAITOK); + bcopy(ip->i_ea_area, eae, ip->i_ea_len); + easize = ip->i_ea_len; - easize = dp->di_extsize; olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name, &p, NULL); if (olen == -1 && ealength == 0) { /* delete but nonexistent */ free(eae, M_TEMP); + if (stand_alone) + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); return(ENOATTR); - } else if (olen == -1) { + } + if (olen == -1) { /* new, append at end */ p = eae + easize; easize += ealength; @@ -1533,6 +1688,10 @@ vop_setextattr { } if (easize > NXADDR * fs->fs_bsize) { free(eae, M_TEMP); + if (stand_alone) + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); + else if (ip->i_ea_error == 0) + ip->i_ea_error = ENOSPC; return(ENOSPC); } if (ealength != 0) { @@ -1548,26 +1707,20 @@ vop_setextattr { error = uiomove(p, ealen, ap->a_uio); if (error) { free(eae, M_TEMP); + if (stand_alone) + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); + else if (ip->i_ea_error == 0) + ip->i_ea_error = error; return(error); } p += ealen; bzero(p, eapad2); } - liovec.iov_base = eae; - liovec.iov_len = easize; - luio.uio_iov = &liovec; - luio.uio_iovcnt = 1; - luio.uio_offset = 0; - luio.uio_resid = easize; - luio.uio_segflg = UIO_SYSSPACE; - luio.uio_rw = UIO_WRITE; - luio.uio_td = ap->a_td; - /* XXX: I'm not happy about truncating to zero size */ - if (easize < dp->di_extsize) - error = ffs_truncate(ap->a_vp, 0, IO_EXT, cred, ap->a_td); - error = ffs_extwrite(ap->a_vp, &luio, IO_EXT | IO_SYNC, cred); - free(eae, M_TEMP); - if (error) - return(error); + p = ip->i_ea_area; + ip->i_ea_area = eae; + ip->i_ea_len = easize; + free(p, M_TEMP); + if (stand_alone) + error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td); return(error); } diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h index 02fa951..94ec179 100644 --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -86,6 +86,14 @@ struct inode { u_int32_t i_reclen; /* Size of found directory entry. */ struct dirhash *i_dirhash; /* Hashing for large directories */ + + /* + * Data for extended attribute modification. + */ + u_char *i_ea_area; /* Pointer to malloced copy of EA area */ + unsigned i_ea_len; /* Length of i_ea_area */ + int i_ea_error; /* First errno in transaction */ + /* * Copies from the on-disk dinode itself. */ |