Changeset View
Changeset View
Standalone View
Standalone View
head/sys/ufs/ffs/ffs_vnops.c
Show First 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | |||||
#include <ufs/ufs/ufs_extern.h> | #include <ufs/ufs/ufs_extern.h> | ||||
#include <ufs/ufs/ufsmount.h> | #include <ufs/ufs/ufsmount.h> | ||||
#include <ufs/ffs/fs.h> | #include <ufs/ffs/fs.h> | ||||
#include <ufs/ffs/ffs_extern.h> | #include <ufs/ffs/ffs_extern.h> | ||||
#include "opt_directio.h" | #include "opt_directio.h" | ||||
#include "opt_ffs.h" | #include "opt_ffs.h" | ||||
#define ALIGNED_TO(ptr, s) \ | |||||
(((uintptr_t)(ptr) & (_Alignof(s) - 1)) == 0) | |||||
#ifdef DIRECTIO | #ifdef DIRECTIO | ||||
extern int ffs_rawread(struct vnode *vp, struct uio *uio, int *workdone); | extern int ffs_rawread(struct vnode *vp, struct uio *uio, int *workdone); | ||||
#endif | #endif | ||||
static vop_fdatasync_t ffs_fdatasync; | static vop_fdatasync_t ffs_fdatasync; | ||||
static vop_fsync_t ffs_fsync; | static vop_fsync_t ffs_fsync; | ||||
static vop_getpages_t ffs_getpages; | static vop_getpages_t ffs_getpages; | ||||
static vop_lock1_t ffs_lock; | static vop_lock1_t ffs_lock; | ||||
static vop_read_t ffs_read; | static vop_read_t ffs_read; | ||||
▲ Show 20 Lines • Show All 984 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Vnode operating to retrieve a named extended attribute. | * Vnode operating to retrieve a named extended attribute. | ||||
* | * | ||||
* Locate a particular EA (nspace:name) in the area (ptr:length), and return | * Locate a particular EA (nspace:name) in the area (ptr:length), and return | ||||
* the length of the EA, and possibly the pointer to the entry and to the data. | * the length of the EA, and possibly the pointer to the entry and to the data. | ||||
*/ | */ | ||||
static int | static int | ||||
ffs_findextattr(u_char *ptr, u_int length, int nspace, const char *name, u_char **eap, u_char **eac) | ffs_findextattr(u_char *ptr, u_int length, int nspace, const char *name, | ||||
struct extattr **eapp, u_char **eac) | |||||
{ | { | ||||
u_char *p, *pe, *pn, *p0; | struct extattr *eap, *eaend; | ||||
int eapad1, eapad2, ealength, ealen, nlen; | size_t nlen; | ||||
uint32_t ul; | |||||
pe = ptr + length; | |||||
nlen = strlen(name); | nlen = strlen(name); | ||||
KASSERT(ALIGNED_TO(ptr, struct extattr), ("unaligned")); | |||||
for (p = ptr; p < pe; p = pn) { | eap = (struct extattr *)ptr; | ||||
p0 = p; | eaend = (struct extattr *)(ptr + length); | ||||
bcopy(p, &ul, sizeof(ul)); | for (; eap < eaend; eap = EXTATTR_NEXT(eap)) { | ||||
pn = p + ul; | |||||
/* make sure this entry is complete */ | /* make sure this entry is complete */ | ||||
if (pn > pe) | if (EXTATTR_NEXT(eap) > eaend) | ||||
break; | break; | ||||
p += sizeof(uint32_t); | if (eap->ea_namespace != nspace || eap->ea_namelength != nlen | ||||
if (*p != nspace) | || memcmp(eap->ea_name, name, nlen) != 0) | ||||
continue; | continue; | ||||
p++; | if (eapp != NULL) | ||||
eapad2 = *p++; | *eapp = eap; | ||||
if (*p != nlen) | |||||
continue; | |||||
p++; | |||||
if (bcmp(p, name, nlen)) | |||||
continue; | |||||
ealength = sizeof(uint32_t) + 3 + nlen; | |||||
eapad1 = 8 - (ealength % 8); | |||||
if (eapad1 == 8) | |||||
eapad1 = 0; | |||||
ealength += eapad1; | |||||
ealen = ul - ealength - eapad2; | |||||
p += nlen + eapad1; | |||||
if (eap != NULL) | |||||
*eap = p0; | |||||
if (eac != NULL) | if (eac != NULL) | ||||
*eac = p; | *eac = EXTATTR_CONTENT(eap); | ||||
return (ealen); | return (EXTATTR_CONTENT_SIZE(eap)); | ||||
} | } | ||||
return(-1); | return (-1); | ||||
} | } | ||||
static int | static int | ||||
ffs_rdextattr(u_char **p, struct vnode *vp, struct thread *td, int extra) | ffs_rdextattr(u_char **p, struct vnode *vp, struct thread *td, int extra) | ||||
{ | { | ||||
struct inode *ip; | struct inode *ip; | ||||
struct ufs2_dinode *dp; | struct ufs2_dinode *dp; | ||||
struct fs *fs; | struct fs *fs; | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | vop_deleteextattr { | ||||
IN const char *a_name; | IN const char *a_name; | ||||
IN struct ucred *a_cred; | IN struct ucred *a_cred; | ||||
IN struct thread *a_td; | IN struct thread *a_td; | ||||
}; | }; | ||||
*/ | */ | ||||
{ | { | ||||
struct inode *ip; | struct inode *ip; | ||||
struct fs *fs; | struct fs *fs; | ||||
uint32_t ealength, ul; | struct extattr *eap; | ||||
int ealen, olen, eapad1, eapad2, error, i, easize; | uint32_t ul; | ||||
u_char *eae, *p; | int olen, error, i, easize; | ||||
u_char *eae; | |||||
void *tmp; | |||||
ip = VTOI(ap->a_vp); | ip = VTOI(ap->a_vp); | ||||
fs = ITOFS(ip); | fs = ITOFS(ip); | ||||
if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) | if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
if (strlen(ap->a_name) == 0) | if (strlen(ap->a_name) == 0) | ||||
Show All 14 Lines | if (ip->i_ea_area != NULL && ip->i_ea_error == 0) | ||||
ip->i_ea_error = error; | ip->i_ea_error = error; | ||||
return (error); | return (error); | ||||
} | } | ||||
error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); | error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
ealength = eapad1 = ealen = eapad2 = 0; | /* CEM: delete could be done in-place instead */ | ||||
eae = malloc(ip->i_ea_len, M_TEMP, M_WAITOK); | eae = malloc(ip->i_ea_len, M_TEMP, M_WAITOK); | ||||
bcopy(ip->i_ea_area, eae, ip->i_ea_len); | bcopy(ip->i_ea_area, eae, ip->i_ea_len); | ||||
easize = ip->i_ea_len; | easize = ip->i_ea_len; | ||||
olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name, | olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name, | ||||
&p, NULL); | &eap, NULL); | ||||
if (olen == -1) { | if (olen == -1) { | ||||
/* delete but nonexistent */ | /* delete but nonexistent */ | ||||
free(eae, M_TEMP); | free(eae, M_TEMP); | ||||
ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ||||
return(ENOATTR); | return (ENOATTR); | ||||
} | } | ||||
bcopy(p, &ul, sizeof ul); | ul = eap->ea_length; | ||||
i = p - eae + ul; | i = (u_char *)EXTATTR_NEXT(eap) - eae; | ||||
if (ul != ealength) { | bcopy(EXTATTR_NEXT(eap), eap, easize - i); | ||||
bcopy(p + ul, p + ealength, easize - i); | easize -= ul; | ||||
easize += (ealength - ul); | |||||
} | tmp = ip->i_ea_area; | ||||
if (easize > NXADDR * fs->fs_bsize) { | |||||
free(eae, M_TEMP); | |||||
ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | |||||
if (ip->i_ea_area != NULL && ip->i_ea_error == 0) | |||||
ip->i_ea_error = ENOSPC; | |||||
return(ENOSPC); | |||||
} | |||||
p = ip->i_ea_area; | |||||
ip->i_ea_area = eae; | ip->i_ea_area = eae; | ||||
ip->i_ea_len = easize; | ip->i_ea_len = easize; | ||||
free(p, M_TEMP); | free(tmp, M_TEMP); | ||||
error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td); | error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td); | ||||
return(error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Vnode operation to retrieve a named extended attribute. | * Vnode operation to retrieve a named extended attribute. | ||||
*/ | */ | ||||
static int | static int | ||||
ffs_getextattr(struct vop_getextattr_args *ap) | ffs_getextattr(struct vop_getextattr_args *ap) | ||||
/* | /* | ||||
Show All 37 Lines | if (ealen >= 0) { | ||||
if (ap->a_size != NULL) | if (ap->a_size != NULL) | ||||
*ap->a_size = ealen; | *ap->a_size = ealen; | ||||
else if (ap->a_uio != NULL) | else if (ap->a_uio != NULL) | ||||
error = uiomove(p, ealen, ap->a_uio); | error = uiomove(p, ealen, ap->a_uio); | ||||
} else | } else | ||||
error = ENOATTR; | error = ENOATTR; | ||||
ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ||||
return(error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Vnode operation to retrieve extended attributes on a vnode. | * Vnode operation to retrieve extended attributes on a vnode. | ||||
*/ | */ | ||||
static int | static int | ||||
ffs_listextattr(struct vop_listextattr_args *ap) | ffs_listextattr(struct vop_listextattr_args *ap) | ||||
/* | /* | ||||
vop_listextattr { | vop_listextattr { | ||||
IN struct vnode *a_vp; | IN struct vnode *a_vp; | ||||
IN int a_attrnamespace; | IN int a_attrnamespace; | ||||
INOUT struct uio *a_uio; | INOUT struct uio *a_uio; | ||||
OUT size_t *a_size; | OUT size_t *a_size; | ||||
IN struct ucred *a_cred; | IN struct ucred *a_cred; | ||||
IN struct thread *a_td; | IN struct thread *a_td; | ||||
}; | }; | ||||
*/ | */ | ||||
{ | { | ||||
struct inode *ip; | struct inode *ip; | ||||
u_char *eae, *p, *pe, *pn; | struct extattr *eap, *eaend; | ||||
unsigned easize; | |||||
uint32_t ul; | |||||
int error, ealen; | int error, ealen; | ||||
ip = VTOI(ap->a_vp); | ip = VTOI(ap->a_vp); | ||||
if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) | if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, | error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, | ||||
ap->a_cred, ap->a_td, VREAD); | ap->a_cred, ap->a_td, VREAD); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); | error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
eae = ip->i_ea_area; | |||||
easize = ip->i_ea_len; | |||||
error = 0; | error = 0; | ||||
if (ap->a_size != NULL) | if (ap->a_size != NULL) | ||||
*ap->a_size = 0; | *ap->a_size = 0; | ||||
pe = eae + easize; | |||||
for(p = eae; error == 0 && p < pe; p = pn) { | KASSERT(ALIGNED_TO(ip->i_ea_area, struct extattr), ("unaligned")); | ||||
bcopy(p, &ul, sizeof(ul)); | eap = (struct extattr *)ip->i_ea_area; | ||||
pn = p + ul; | eaend = (struct extattr *)(ip->i_ea_area + ip->i_ea_len); | ||||
if (pn > pe) | for (; error == 0 && eap < eaend; eap = EXTATTR_NEXT(eap)) { | ||||
/* make sure this entry is complete */ | |||||
if (EXTATTR_NEXT(eap) > eaend) | |||||
break; | break; | ||||
p += sizeof(ul); | if (eap->ea_namespace != ap->a_attrnamespace) | ||||
if (*p++ != ap->a_attrnamespace) | |||||
continue; | continue; | ||||
p++; /* pad2 */ | |||||
ealen = *p; | ealen = eap->ea_namelength; | ||||
if (ap->a_size != NULL) { | if (ap->a_size != NULL) | ||||
*ap->a_size += ealen + 1; | *ap->a_size += ealen + 1; | ||||
} else if (ap->a_uio != NULL) { | else if (ap->a_uio != NULL) | ||||
error = uiomove(p, ealen + 1, ap->a_uio); | error = uiomove(&eap->ea_namelength, ealen + 1, | ||||
ap->a_uio); | |||||
} | } | ||||
} | |||||
ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ||||
return(error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Vnode operation to set a named attribute. | * Vnode operation to set a named attribute. | ||||
*/ | */ | ||||
static int | static int | ||||
ffs_setextattr(struct vop_setextattr_args *ap) | ffs_setextattr(struct vop_setextattr_args *ap) | ||||
/* | /* | ||||
vop_setextattr { | vop_setextattr { | ||||
IN struct vnode *a_vp; | IN struct vnode *a_vp; | ||||
IN int a_attrnamespace; | IN int a_attrnamespace; | ||||
IN const char *a_name; | IN const char *a_name; | ||||
INOUT struct uio *a_uio; | INOUT struct uio *a_uio; | ||||
IN struct ucred *a_cred; | IN struct ucred *a_cred; | ||||
IN struct thread *a_td; | IN struct thread *a_td; | ||||
}; | }; | ||||
*/ | */ | ||||
{ | { | ||||
struct inode *ip; | struct inode *ip; | ||||
struct fs *fs; | struct fs *fs; | ||||
struct extattr *eap; | |||||
uint32_t ealength, ul; | uint32_t ealength, ul; | ||||
ssize_t ealen; | ssize_t ealen; | ||||
int olen, eapad1, eapad2, error, i, easize; | int olen, eapad1, eapad2, error, i, easize; | ||||
u_char *eae, *p; | u_char *eae; | ||||
void *tmp; | |||||
ip = VTOI(ap->a_vp); | ip = VTOI(ap->a_vp); | ||||
fs = ITOFS(ip); | fs = ITOFS(ip); | ||||
if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) | if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
if (strlen(ap->a_name) == 0) | if (strlen(ap->a_name) == 0) | ||||
Show All 23 Lines | if (error) { | ||||
return (error); | return (error); | ||||
} | } | ||||
error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); | error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
ealength = sizeof(uint32_t) + 3 + strlen(ap->a_name); | ealength = sizeof(uint32_t) + 3 + strlen(ap->a_name); | ||||
eapad1 = 8 - (ealength % 8); | eapad1 = roundup2(ealength, 8) - ealength; | ||||
if (eapad1 == 8) | eapad2 = roundup2(ealen, 8) - ealen; | ||||
eapad1 = 0; | |||||
eapad2 = 8 - (ealen % 8); | |||||
if (eapad2 == 8) | |||||
eapad2 = 0; | |||||
ealength += eapad1 + ealen + eapad2; | ealength += eapad1 + ealen + eapad2; | ||||
/* | |||||
* CEM: rewrites of the same size or smaller could be done in-place | |||||
* instead. (We don't acquire any fine-grained locks in here either, | |||||
* so we could also do bigger writes in-place.) | |||||
*/ | |||||
eae = malloc(ip->i_ea_len + ealength, M_TEMP, M_WAITOK); | eae = malloc(ip->i_ea_len + ealength, M_TEMP, M_WAITOK); | ||||
bcopy(ip->i_ea_area, eae, ip->i_ea_len); | bcopy(ip->i_ea_area, eae, ip->i_ea_len); | ||||
easize = ip->i_ea_len; | easize = ip->i_ea_len; | ||||
olen = ffs_findextattr(eae, easize, | olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name, | ||||
ap->a_attrnamespace, ap->a_name, &p, NULL); | &eap, NULL); | ||||
if (olen == -1) { | if (olen == -1) { | ||||
/* new, append at end */ | /* new, append at end */ | ||||
p = eae + easize; | KASSERT(ALIGNED_TO(eae + easize, struct extattr), | ||||
("unaligned")); | |||||
eap = (struct extattr *)(eae + easize); | |||||
easize += ealength; | easize += ealength; | ||||
} else { | } else { | ||||
bcopy(p, &ul, sizeof ul); | ul = eap->ea_length; | ||||
i = p - eae + ul; | i = (u_char *)EXTATTR_NEXT(eap) - eae; | ||||
if (ul != ealength) { | if (ul != ealength) { | ||||
bcopy(p + ul, p + ealength, easize - i); | bcopy(EXTATTR_NEXT(eap), (u_char *)eap + ealength, | ||||
easize - i); | |||||
easize += (ealength - ul); | easize += (ealength - ul); | ||||
} | } | ||||
} | } | ||||
if (easize > lblktosize(fs, NXADDR)) { | if (easize > lblktosize(fs, NXADDR)) { | ||||
free(eae, M_TEMP); | free(eae, M_TEMP); | ||||
ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ||||
if (ip->i_ea_area != NULL && ip->i_ea_error == 0) | if (ip->i_ea_area != NULL && ip->i_ea_error == 0) | ||||
ip->i_ea_error = ENOSPC; | ip->i_ea_error = ENOSPC; | ||||
return(ENOSPC); | return (ENOSPC); | ||||
} | } | ||||
bcopy(&ealength, p, sizeof(ealength)); | eap->ea_length = ealength; | ||||
p += sizeof(ealength); | eap->ea_namespace = ap->a_attrnamespace; | ||||
*p++ = ap->a_attrnamespace; | eap->ea_contentpadlen = eapad2; | ||||
*p++ = eapad2; | eap->ea_namelength = strlen(ap->a_name); | ||||
*p++ = strlen(ap->a_name); | memcpy(eap->ea_name, ap->a_name, strlen(ap->a_name)); | ||||
strcpy(p, ap->a_name); | bzero(&eap->ea_name[strlen(ap->a_name)], eapad1); | ||||
p += strlen(ap->a_name); | error = uiomove(EXTATTR_CONTENT(eap), ealen, ap->a_uio); | ||||
bzero(p, eapad1); | |||||
p += eapad1; | |||||
error = uiomove(p, ealen, ap->a_uio); | |||||
if (error) { | if (error) { | ||||
free(eae, M_TEMP); | free(eae, M_TEMP); | ||||
ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); | ||||
if (ip->i_ea_area != NULL && ip->i_ea_error == 0) | if (ip->i_ea_area != NULL && ip->i_ea_error == 0) | ||||
ip->i_ea_error = error; | ip->i_ea_error = error; | ||||
return(error); | return (error); | ||||
} | } | ||||
p += ealen; | bzero((u_char *)EXTATTR_CONTENT(eap) + ealen, eapad2); | ||||
bzero(p, eapad2); | |||||
p = ip->i_ea_area; | tmp = ip->i_ea_area; | ||||
ip->i_ea_area = eae; | ip->i_ea_area = eae; | ||||
ip->i_ea_len = easize; | ip->i_ea_len = easize; | ||||
free(p, M_TEMP); | free(tmp, M_TEMP); | ||||
error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td); | error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td); | ||||
return(error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Vnode pointer to File handle | * Vnode pointer to File handle | ||||
*/ | */ | ||||
static int | static int | ||||
ffs_vptofh(struct vop_vptofh_args *ap) | ffs_vptofh(struct vop_vptofh_args *ap) | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 51 Lines • Show Last 20 Lines |