diff --git a/sys/kern/kern_lockf.c b/sys/kern/kern_lockf.c --- a/sys/kern/kern_lockf.c +++ b/sys/kern/kern_lockf.c @@ -68,14 +68,18 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include #include +#include #include #include #include @@ -85,11 +89,6 @@ #ifdef LOCKF_DEBUG #include -#include -#include -#include -#include - static int lockf_debug = 0; /* control debug output */ SYSCTL_INT(_debug, OID_AUTO, lockf_debug, CTLFLAG_RW, &lockf_debug, 0, ""); #endif @@ -571,13 +570,6 @@ vref(vp); } - /* - * XXX The problem is that VTOI is ufs specific, so it will - * break LOCKF_DEBUG for all other FS's other than UFS because - * it casts the vnode->data ptr to struct inode *. - */ -/* lock->lf_inode = VTOI(ap->a_vp); */ - lock->lf_inode = (struct inode *)0; lock->lf_type = fl->l_type; LIST_INIT(&lock->lf_outedges); LIST_INIT(&lock->lf_inedges); @@ -2471,6 +2463,125 @@ return (g); } +struct kinfo_lockf_linked { + struct kinfo_lockf kl; + struct vnode *vp; + STAILQ_ENTRY(kinfo_lockf_linked) link; +}; + +static int +sysctl_kern_lockf_run(struct sbuf *sb) +{ + struct lockf *ls; + struct lockf_entry *lf; + struct kinfo_lockf_linked *klf; + struct vnode *vp; + struct ucred *ucred; + char *fullpath, *freepath; + struct stat stt; + fsid_t fsidx; + STAILQ_HEAD(, kinfo_lockf_linked) locks; + int error, gerror; + + /* + * In order to keep the locking simple, we iterate over the + * active lock lists to build a list of locks that need + * releasing. We then call the iterator for each one in turn. + * + * We take an extra reference to the vnode for the duration to + * make sure it doesn't go away before we are finished. + */ + STAILQ_INIT(&locks); + sx_slock(&lf_lock_states_lock); + LIST_FOREACH(ls, &lf_lock_states, ls_link) { + sx_slock(&ls->ls_lock); + LIST_FOREACH(lf, &ls->ls_active, lf_link) { + vp = lf->lf_vnode; + if (vp == NULL || VN_IS_DOOMED(vp)) + continue; + vhold(vp); + klf = malloc(sizeof(struct kinfo_lockf_linked), + M_LOCKF, M_WAITOK | M_ZERO); + klf->vp = vp; + klf->kl.kl_structsize = sizeof(struct kinfo_lockf); + klf->kl.kl_start = lf->lf_start; + klf->kl.kl_len = lf->lf_end == OFF_MAX ? 0 : + lf->lf_end - lf->lf_start + 1; + klf->kl.kl_rw = lf->lf_type == F_RDLCK ? KLOCK_RW_READ : + KLOCK_RW_WRITE; + if (lf->lf_owner->lo_sysid != 0) { + klf->kl.kl_pid = lf->lf_owner->lo_pid; + klf->kl.kl_sysid = lf->lf_owner->lo_sysid; + klf->kl.kl_type = KLOCK_TYPE_REMOTE; + } else if (lf->lf_owner->lo_pid == -1) { + klf->kl.kl_pid = -1; + klf->kl.kl_sysid = 0; + klf->kl.kl_type = KLOCK_TYPE_FLOCK; + } else { + klf->kl.kl_pid = lf->lf_owner->lo_pid; + klf->kl.kl_sysid = 0; + klf->kl.kl_type = KLOCK_TYPE_PID; + } + memcpy(&klf->kl.kl_file_fsid, &fsidx, sizeof(fsidx)); + STAILQ_INSERT_TAIL(&locks, klf, link); + } + sx_sunlock(&ls->ls_lock); + } + sx_sunlock(&lf_lock_states_lock); + + gerror = 0; + ucred = curthread->td_ucred; + while ((klf = STAILQ_FIRST(&locks)) != NULL) { + STAILQ_REMOVE_HEAD(&locks, link); + vp = klf->vp; + if (gerror == 0 && vn_lock(vp, LK_SHARED | LK_RETRY) == 0) { + error = prison_canseemount(ucred, vp->v_mount); + if (error == 0) + error = VOP_STAT(vp, &stt, ucred, NOCRED); + if (error == 0) + fsidx = vp->v_mount->mnt_stat.f_fsid; + VOP_UNLOCK(vp); + if (error == 0) { + klf->kl.kl_file_rdev = stt.st_rdev; + klf->kl.kl_file_fileid = stt.st_ino; + freepath = NULL; + fullpath = "-"; + error = vn_fullpath(vp, &fullpath, &freepath); + if (error == 0) + strlcpy(klf->kl.kl_path, fullpath, + sizeof(klf->kl.kl_path)); + free(freepath, M_TEMP); + if (sbuf_bcat(sb, &klf->kl, + klf->kl.kl_structsize) != 0) { + gerror = sbuf_error(sb); + } + } + } + vdrop(vp); + free(klf, M_LOCKF); + } + + return (gerror); +} + +static int +sysctl_kern_lockf(SYSCTL_HANDLER_ARGS) +{ + struct sbuf sb; + int error, error2; + + sbuf_new_for_sysctl(&sb, NULL, sizeof(struct kinfo_lockf) * 5, req); + sbuf_clear_flags(&sb, SBUF_INCLUDENUL); + error = sysctl_kern_lockf_run(&sb); + error2 = sbuf_finish(&sb); + sbuf_delete(&sb); + return (error != 0 ? error : error2); +} +SYSCTL_PROC(_kern, KERN_LOCKF, lockf, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, + 0, 0, sysctl_kern_lockf, "S,lockf", + "Advisory locks table"); + #ifdef LOCKF_DEBUG /* * Print description of a lock owner @@ -2498,10 +2609,8 @@ printf("%s: lock %p for ", tag, (void *)lock); lf_print_owner(lock->lf_owner); - if (lock->lf_inode != (struct inode *)0) - printf(" in ino %ju on dev <%s>,", - (uintmax_t)lock->lf_inode->i_number, - devtoname(ITODEV(lock->lf_inode))); + printf("\nvnode %p", lock->lf_vnode); + VOP_PRINT(lock->lf_vnode); printf(" %s, start %jd, end ", lock->lf_type == F_RDLCK ? "shared" : lock->lf_type == F_WRLCK ? "exclusive" : @@ -2524,12 +2633,8 @@ struct lockf_entry *lf, *blk; struct lockf_edge *e; - if (lock->lf_inode == (struct inode *)0) - return; - - printf("%s: Lock list for ino %ju on dev <%s>:\n", - tag, (uintmax_t)lock->lf_inode->i_number, - devtoname(ITODEV(lock->lf_inode))); + printf("%s: Lock list for vnode %p:\n", + tag, lock->lf_vnode); LIST_FOREACH(lf, &lock->lf_vnode->v_lockf->ls_active, lf_link) { printf("\tlock %p for ",(void *)lf); lf_print_owner(lock->lf_owner); diff --git a/sys/sys/lockf.h b/sys/sys/lockf.h --- a/sys/sys/lockf.h +++ b/sys/sys/lockf.h @@ -77,7 +77,6 @@ off_t lf_end; /* (s) Byte # of the end of the lock (OFF_MAX=EOF) */ struct lock_owner *lf_owner; /* (c) Owner of the lock */ struct vnode *lf_vnode; /* (c) File being locked (only valid for active lock) */ - struct inode *lf_inode; /* (c) Back pointer to the inode */ struct task *lf_async_task;/* (c) Async lock callback */ LIST_ENTRY(lockf_entry) lf_link; /* (s) Linkage for lock lists */ struct lockf_edge_list lf_outedges; /* (s) list of out-edges */ diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -976,6 +976,7 @@ #define KERN_HOSTUUID 36 /* string: host UUID identifier */ #define KERN_ARND 37 /* int: from arc4rand() */ #define KERN_MAXPHYS 38 /* int: MAXPHYS value */ +#define KERN_LOCKF 39 /* struct: lockf reports */ /* * KERN_PROC subtypes */ diff --git a/sys/sys/user.h b/sys/sys/user.h --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -452,6 +452,28 @@ char kf_path[PATH_MAX]; /* Path to file, if any. */ }; +struct kinfo_lockf { + int kl_structsize; /* Variable size of record. */ + int kl_rw; + int kl_type; + int kl_pid; + int kl_sysid; + int kl_pad0; + uint64_t kl_file_fsid; + uint64_t kl_file_rdev; + uint64_t kl_file_fileid; + off_t kl_start; + off_t kl_len; /* len == 0 till the EOF */ + char kl_path[PATH_MAX]; +}; + +#define KLOCK_RW_READ 0x01 +#define KLOCK_RW_WRITE 0x02 + +#define KLOCK_TYPE_FLOCK 0x01 +#define KLOCK_TYPE_PID 0x02 +#define KLOCK_TYPE_REMOTE 0x03 + /* * The KERN_PROC_VMMAP sysctl allows a process to dump the VM layout of * another process as a series of entries. diff --git a/sys/ufs/ufs/acl.h b/sys/ufs/ufs/acl.h --- a/sys/ufs/ufs/acl.h +++ b/sys/ufs/ufs/acl.h @@ -39,8 +39,12 @@ #ifdef _KERNEL -int ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td); -int ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td); +struct inode; + +int ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, + struct thread *td); +int ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, + struct thread *td); void ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl); void ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip);