Changeset View
Standalone View
sys/fs/unionfs/union_vnops.c
Show First 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | ||||||||||
#include <sys/stat.h> | #include <sys/stat.h> | |||||||||
#include <sys/dirent.h> | #include <sys/dirent.h> | |||||||||
#include <sys/proc.h> | #include <sys/proc.h> | |||||||||
#include <sys/bio.h> | #include <sys/bio.h> | |||||||||
#include <sys/buf.h> | #include <sys/buf.h> | |||||||||
#include <fs/unionfs/union.h> | #include <fs/unionfs/union.h> | |||||||||
#include <machine/atomic.h> | ||||||||||
#include <vm/vm.h> | #include <vm/vm.h> | |||||||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | |||||||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | |||||||||
#include <vm/vnode_pager.h> | #include <vm/vnode_pager.h> | |||||||||
#if 0 | #if 0 | |||||||||
#define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args) | #define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args) | |||||||||
#define UNIONFS_IDBG_RENAME | #define UNIONFS_IDBG_RENAME | |||||||||
▲ Show 20 Lines • Show All 594 Lines • ▼ Show 20 Lines | if (accmode & VWRITE) | |||||||||
mask |= S_IWOTH; | mask |= S_IWOTH; | |||||||||
return ((vmode & mask) == mask ? 0 : EACCES); | return ((vmode & mask) == mask ? 0 : EACCES); | |||||||||
} | } | |||||||||
static int | static int | |||||||||
unionfs_access(struct vop_access_args *ap) | unionfs_access(struct vop_access_args *ap) | |||||||||
{ | { | |||||||||
struct mount *uppermp; | ||||||||||
struct unionfs_mount *ump; | struct unionfs_mount *ump; | |||||||||
struct unionfs_node *unp; | struct unionfs_node *unp; | |||||||||
struct vnode *uvp; | struct vnode *uvp; | |||||||||
struct vnode *lvp; | struct vnode *lvp; | |||||||||
struct thread *td; | struct thread *td; | |||||||||
struct vattr va; | struct vattr va; | |||||||||
accmode_t accmode; | accmode_t accmode; | |||||||||
int error; | int error; | |||||||||
Show All 27 Lines | if (uvp != NULLVP) { | |||||||||
UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); | UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); | |||||||||
return (error); | return (error); | |||||||||
} | } | |||||||||
if (lvp != NULLVP) { | if (lvp != NULLVP) { | |||||||||
if (accmode & VWRITE) { | if (accmode & VWRITE) { | |||||||||
if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) { | uppermp = atomic_load_ptr(&ump->um_uppervp->v_mount); | |||||||||
if (uppermp == NULL) | ||||||||||
return (ENOENT); | ||||||||||
/* | ||||||||||
kib: mnt_flag is uint64_t, and reading it without mnt_ilock on 32bit arches is not guaranteed to be… | ||||||||||
Done Inline Actionsgood point, will fix while here. jah: good point, will fix while here. | ||||||||||
Done Inline ActionsOn second reading, I'm not sure that non-atomicity of mnt_flag matters here. If we don't care about MNT_ILOCK here, then we can rely on type-stability of struct mount to simplify this path as you note below for VOP_GETATTR. Otherwise, I don't think we can safely use the ilock mutex across mount recycling, so we'll need to both ref the mount and lock the ilock. jah: On second reading, I'm not sure that non-atomicity of mnt_flag matters here.
We only care about… | ||||||||||
* struct mount* is type-stable, so we should be able | ||||||||||
* to safely access uppermp->mnt_flag even if a | ||||||||||
* concurrent unmount recycles the object. | ||||||||||
*/ | ||||||||||
if (uppermp->mnt_flag & MNT_RDONLY) { | ||||||||||
markjUnsubmitted Not Done Inline Actions
markj: | ||||||||||
switch (ap->a_vp->v_type) { | switch (ap->a_vp->v_type) { | |||||||||
case VREG: | case VREG: | |||||||||
case VDIR: | case VDIR: | |||||||||
case VLNK: | case VLNK: | |||||||||
return (EROFS); | return (EROFS); | |||||||||
default: | default: | |||||||||
break; | break; | |||||||||
} | } | |||||||||
Show All 20 Lines | unionfs_access(struct vop_access_args *ap) | |||||||||
UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); | UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error); | |||||||||
return (error); | return (error); | |||||||||
} | } | |||||||||
static int | static int | |||||||||
unionfs_getattr(struct vop_getattr_args *ap) | unionfs_getattr(struct vop_getattr_args *ap) | |||||||||
{ | { | |||||||||
int error; | struct mount *uppermp; | |||||||||
struct unionfs_node *unp; | struct unionfs_node *unp; | |||||||||
struct unionfs_mount *ump; | struct unionfs_mount *ump; | |||||||||
struct vnode *uvp; | struct vnode *uvp; | |||||||||
struct vnode *lvp; | struct vnode *lvp; | |||||||||
struct thread *td; | struct thread *td; | |||||||||
struct vattr va; | struct vattr va; | |||||||||
int error; | ||||||||||
UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); | UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n"); | |||||||||
KASSERT_UNIONFS_VNODE(ap->a_vp); | KASSERT_UNIONFS_VNODE(ap->a_vp); | |||||||||
unp = VTOUNIONFS(ap->a_vp); | unp = VTOUNIONFS(ap->a_vp); | |||||||||
ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); | ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); | |||||||||
uvp = unp->un_uppervp; | uvp = unp->un_uppervp; | |||||||||
lvp = unp->un_lowervp; | lvp = unp->un_lowervp; | |||||||||
td = curthread; | td = curthread; | |||||||||
if (uvp != NULLVP) { | if (uvp != NULLVP) { | |||||||||
if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0) | if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0) | |||||||||
ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; | ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; | |||||||||
UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", | UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n", | |||||||||
ap->a_vap->va_mode, ap->a_vap->va_uid, | ap->a_vap->va_mode, ap->a_vap->va_uid, | |||||||||
ap->a_vap->va_gid, error); | ap->a_vap->va_gid, error); | |||||||||
return (error); | return (error); | |||||||||
} | } | |||||||||
error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); | error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred); | |||||||||
if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) { | uppermp = atomic_load_ptr(&ump->um_uppervp->v_mount); | |||||||||
if (uppermp == NULL) | ||||||||||
error = ENOENT; | ||||||||||
/* | ||||||||||
Not Done Inline ActionsI think there you can get away with reading uppervp->v_mount and storing it in local var. Then check the pointer for != NULL, and you can freely dereference it without taking a reference. struct mount is type-stable, i.e. it can be reused, but only for another mount. There I do not believe that this is critical. kib: I think there you can get away with reading uppervp->v_mount and storing it in local var. Then… | ||||||||||
* struct mount* is type-stable, so we should be able to safely | ||||||||||
* access uppermp->mnt_flag even if a concurrent unmount recycles | ||||||||||
* the object. | ||||||||||
*/ | ||||||||||
if (error == 0 && !(uppermp->mnt_flag & MNT_RDONLY)) { | ||||||||||
markjUnsubmitted Not Done Inline Actions
markj: | ||||||||||
jahAuthorUnsubmitted Done Inline Actionsjah: >
| ||||||||||
/* correct the attr toward shadow file/dir. */ | /* correct the attr toward shadow file/dir. */ | |||||||||
if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { | if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) { | |||||||||
unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td); | unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td); | |||||||||
ap->a_vap->va_mode = va.va_mode; | ap->a_vap->va_mode = va.va_mode; | |||||||||
ap->a_vap->va_uid = va.va_uid; | ap->a_vap->va_uid = va.va_uid; | |||||||||
ap->a_vap->va_gid = va.va_gid; | ap->a_vap->va_gid = va.va_gid; | |||||||||
} | } | |||||||||
} | } | |||||||||
▲ Show 20 Lines • Show All 1,764 Lines • Show Last 20 Lines |
mnt_flag is uint64_t, and reading it without mnt_ilock on 32bit arches is not guaranteed to be atomic.