19454b2d8SWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4dfdcada3SDoug Rabson * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 5dfdcada3SDoug Rabson * Authors: Doug Rabson <dfr@rabson.org> 6dfdcada3SDoug Rabson * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 7dfdcada3SDoug Rabson * 8dfdcada3SDoug Rabson * Redistribution and use in source and binary forms, with or without 9dfdcada3SDoug Rabson * modification, are permitted provided that the following conditions 10dfdcada3SDoug Rabson * are met: 11dfdcada3SDoug Rabson * 1. Redistributions of source code must retain the above copyright 12dfdcada3SDoug Rabson * notice, this list of conditions and the following disclaimer. 13dfdcada3SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 14dfdcada3SDoug Rabson * notice, this list of conditions and the following disclaimer in the 15dfdcada3SDoug Rabson * documentation and/or other materials provided with the distribution. 16dfdcada3SDoug Rabson * 17dfdcada3SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18dfdcada3SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19dfdcada3SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20dfdcada3SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21dfdcada3SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22dfdcada3SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23dfdcada3SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24dfdcada3SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25dfdcada3SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26dfdcada3SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27dfdcada3SDoug Rabson * SUCH DAMAGE. 28dfdcada3SDoug Rabson */ 29dfdcada3SDoug Rabson /*- 3092dc7331SDavid Greenman * Copyright (c) 1982, 1986, 1989, 1993 3192dc7331SDavid Greenman * The Regents of the University of California. All rights reserved. 3292dc7331SDavid Greenman * 3392dc7331SDavid Greenman * This code is derived from software contributed to Berkeley by 3492dc7331SDavid Greenman * Scooter Morris at Genentech Inc. 3592dc7331SDavid Greenman * 3692dc7331SDavid Greenman * Redistribution and use in source and binary forms, with or without 3792dc7331SDavid Greenman * modification, are permitted provided that the following conditions 3892dc7331SDavid Greenman * are met: 3992dc7331SDavid Greenman * 1. Redistributions of source code must retain the above copyright 4092dc7331SDavid Greenman * notice, this list of conditions and the following disclaimer. 4192dc7331SDavid Greenman * 2. Redistributions in binary form must reproduce the above copyright 4292dc7331SDavid Greenman * notice, this list of conditions and the following disclaimer in the 4392dc7331SDavid Greenman * documentation and/or other materials provided with the distribution. 4469a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 4592dc7331SDavid Greenman * may be used to endorse or promote products derived from this software 4692dc7331SDavid Greenman * without specific prior written permission. 4792dc7331SDavid Greenman * 4892dc7331SDavid Greenman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4992dc7331SDavid Greenman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5092dc7331SDavid Greenman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5192dc7331SDavid Greenman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5292dc7331SDavid Greenman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5392dc7331SDavid Greenman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5492dc7331SDavid Greenman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5592dc7331SDavid Greenman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5692dc7331SDavid Greenman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5792dc7331SDavid Greenman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5892dc7331SDavid Greenman * SUCH DAMAGE. 5992dc7331SDavid Greenman * 6092dc7331SDavid Greenman * @(#)ufs_lockf.c 8.3 (Berkeley) 1/6/94 6192dc7331SDavid Greenman */ 6292dc7331SDavid Greenman 63677b542eSDavid E. O'Brien #include <sys/cdefs.h> 64677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 65677b542eSDavid E. O'Brien 663f2076daSEivind Eklund #include "opt_debug_lockf.h" 673f2076daSEivind Eklund 6892dc7331SDavid Greenman #include <sys/param.h> 6992dc7331SDavid Greenman #include <sys/systm.h> 70dfdcada3SDoug Rabson #include <sys/hash.h> 71eca39864SKonstantin Belousov #include <sys/jail.h> 721c5bb3eaSPeter Wemm #include <sys/kernel.h> 73104a9b7eSAlexander Kabaev #include <sys/limits.h> 741cd52ec3SBruce Evans #include <sys/lock.h> 757f52a691SPoul-Henning Kamp #include <sys/mount.h> 76fb919e4dSMark Murray #include <sys/mutex.h> 7792dc7331SDavid Greenman #include <sys/proc.h> 78eca39864SKonstantin Belousov #include <sys/sbuf.h> 79eca39864SKonstantin Belousov #include <sys/stat.h> 80dfdcada3SDoug Rabson #include <sys/sx.h> 81b71fec07SBruce Evans #include <sys/unistd.h> 82eca39864SKonstantin Belousov #include <sys/user.h> 8392dc7331SDavid Greenman #include <sys/vnode.h> 8492dc7331SDavid Greenman #include <sys/malloc.h> 8592dc7331SDavid Greenman #include <sys/fcntl.h> 8692dc7331SDavid Greenman #include <sys/lockf.h> 87dfdcada3SDoug Rabson #include <sys/taskqueue.h> 8892dc7331SDavid Greenman 8992dc7331SDavid Greenman #ifdef LOCKF_DEBUG 90996c772fSJohn Dyson #include <sys/sysctl.h> 91a8687b6dSBruce Evans 92dfdcada3SDoug Rabson static int lockf_debug = 0; /* control debug output */ 937f725eacSBruce Evans SYSCTL_INT(_debug, OID_AUTO, lockf_debug, CTLFLAG_RW, &lockf_debug, 0, ""); 9492dc7331SDavid Greenman #endif 9592dc7331SDavid Greenman 96d745c852SEd Schouten static MALLOC_DEFINE(M_LOCKF, "lockf", "Byte-range locking structures"); 9755166637SPoul-Henning Kamp 98dfdcada3SDoug Rabson struct owner_edge; 99dfdcada3SDoug Rabson struct owner_vertex; 100dfdcada3SDoug Rabson struct owner_vertex_list; 101dfdcada3SDoug Rabson struct owner_graph; 102dfdcada3SDoug Rabson 103dfdcada3SDoug Rabson #define NOLOCKF (struct lockf_entry *)0 10492dc7331SDavid Greenman #define SELF 0x1 10592dc7331SDavid Greenman #define OTHERS 0x2 106dfdcada3SDoug Rabson static void lf_init(void *); 107d357c16aSMateusz Guzik static int lf_hash_owner(caddr_t, struct vnode *, struct flock *, int); 108dfdcada3SDoug Rabson static int lf_owner_matches(struct lock_owner *, caddr_t, struct flock *, 109dfdcada3SDoug Rabson int); 110dfdcada3SDoug Rabson static struct lockf_entry * 111dfdcada3SDoug Rabson lf_alloc_lock(struct lock_owner *); 1128af54d4cSKonstantin Belousov static int lf_free_lock(struct lockf_entry *); 113dfdcada3SDoug Rabson static int lf_clearlock(struct lockf *, struct lockf_entry *); 114dfdcada3SDoug Rabson static int lf_overlaps(struct lockf_entry *, struct lockf_entry *); 115dfdcada3SDoug Rabson static int lf_blocks(struct lockf_entry *, struct lockf_entry *); 116dfdcada3SDoug Rabson static void lf_free_edge(struct lockf_edge *); 117dfdcada3SDoug Rabson static struct lockf_edge * 118dfdcada3SDoug Rabson lf_alloc_edge(void); 119dfdcada3SDoug Rabson static void lf_alloc_vertex(struct lockf_entry *); 120dfdcada3SDoug Rabson static int lf_add_edge(struct lockf_entry *, struct lockf_entry *); 121dfdcada3SDoug Rabson static void lf_remove_edge(struct lockf_edge *); 122dfdcada3SDoug Rabson static void lf_remove_outgoing(struct lockf_entry *); 123dfdcada3SDoug Rabson static void lf_remove_incoming(struct lockf_entry *); 124dfdcada3SDoug Rabson static int lf_add_outgoing(struct lockf *, struct lockf_entry *); 125dfdcada3SDoug Rabson static int lf_add_incoming(struct lockf *, struct lockf_entry *); 126dfdcada3SDoug Rabson static int lf_findoverlap(struct lockf_entry **, struct lockf_entry *, 127dfdcada3SDoug Rabson int); 128dfdcada3SDoug Rabson static struct lockf_entry * 129dfdcada3SDoug Rabson lf_getblock(struct lockf *, struct lockf_entry *); 130dfdcada3SDoug Rabson static int lf_getlock(struct lockf *, struct lockf_entry *, struct flock *); 131dfdcada3SDoug Rabson static void lf_insert_lock(struct lockf *, struct lockf_entry *); 132dfdcada3SDoug Rabson static void lf_wakeup_lock(struct lockf *, struct lockf_entry *); 133dfdcada3SDoug Rabson static void lf_update_dependancies(struct lockf *, struct lockf_entry *, 134dfdcada3SDoug Rabson int all, struct lockf_entry_list *); 135dfdcada3SDoug Rabson static void lf_set_start(struct lockf *, struct lockf_entry *, off_t, 136dfdcada3SDoug Rabson struct lockf_entry_list*); 137dfdcada3SDoug Rabson static void lf_set_end(struct lockf *, struct lockf_entry *, off_t, 138dfdcada3SDoug Rabson struct lockf_entry_list*); 139dfdcada3SDoug Rabson static int lf_setlock(struct lockf *, struct lockf_entry *, 140dfdcada3SDoug Rabson struct vnode *, void **cookiep); 141dfdcada3SDoug Rabson static int lf_cancel(struct lockf *, struct lockf_entry *, void *); 142dfdcada3SDoug Rabson static void lf_split(struct lockf *, struct lockf_entry *, 143dfdcada3SDoug Rabson struct lockf_entry *, struct lockf_entry_list *); 144013e6650SJeff Roberson #ifdef LOCKF_DEBUG 145dfdcada3SDoug Rabson static int graph_reaches(struct owner_vertex *x, struct owner_vertex *y, 146dfdcada3SDoug Rabson struct owner_vertex_list *path); 147dfdcada3SDoug Rabson static void graph_check(struct owner_graph *g, int checkorder); 148dfdcada3SDoug Rabson static void graph_print_vertices(struct owner_vertex_list *set); 149013e6650SJeff Roberson #endif 150dfdcada3SDoug Rabson static int graph_delta_forward(struct owner_graph *g, 151dfdcada3SDoug Rabson struct owner_vertex *x, struct owner_vertex *y, 152dfdcada3SDoug Rabson struct owner_vertex_list *delta); 153dfdcada3SDoug Rabson static int graph_delta_backward(struct owner_graph *g, 154dfdcada3SDoug Rabson struct owner_vertex *x, struct owner_vertex *y, 155dfdcada3SDoug Rabson struct owner_vertex_list *delta); 156dfdcada3SDoug Rabson static int graph_add_indices(int *indices, int n, 157dfdcada3SDoug Rabson struct owner_vertex_list *set); 158dfdcada3SDoug Rabson static int graph_assign_indices(struct owner_graph *g, int *indices, 159dfdcada3SDoug Rabson int nextunused, struct owner_vertex_list *set); 160dfdcada3SDoug Rabson static int graph_add_edge(struct owner_graph *g, 161dfdcada3SDoug Rabson struct owner_vertex *x, struct owner_vertex *y); 162dfdcada3SDoug Rabson static void graph_remove_edge(struct owner_graph *g, 163dfdcada3SDoug Rabson struct owner_vertex *x, struct owner_vertex *y); 164dfdcada3SDoug Rabson static struct owner_vertex *graph_alloc_vertex(struct owner_graph *g, 165dfdcada3SDoug Rabson struct lock_owner *lo); 166dfdcada3SDoug Rabson static void graph_free_vertex(struct owner_graph *g, 167dfdcada3SDoug Rabson struct owner_vertex *v); 168dfdcada3SDoug Rabson static struct owner_graph * graph_init(struct owner_graph *g); 169dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 170dfdcada3SDoug Rabson static void lf_print(char *, struct lockf_entry *); 171dfdcada3SDoug Rabson static void lf_printlist(char *, struct lockf_entry *); 172dfdcada3SDoug Rabson static void lf_print_owner(struct lock_owner *); 173dfdcada3SDoug Rabson #endif 174dfdcada3SDoug Rabson 175dfdcada3SDoug Rabson /* 176dfdcada3SDoug Rabson * This structure is used to keep track of both local and remote lock 177dfdcada3SDoug Rabson * owners. The lf_owner field of the struct lockf_entry points back at 178dfdcada3SDoug Rabson * the lock owner structure. Each possible lock owner (local proc for 179dfdcada3SDoug Rabson * POSIX fcntl locks, local file for BSD flock locks or <pid,sysid> 180dfdcada3SDoug Rabson * pair for remote locks) is represented by a unique instance of 181dfdcada3SDoug Rabson * struct lock_owner. 182dfdcada3SDoug Rabson * 183dfdcada3SDoug Rabson * If a lock owner has a lock that blocks some other lock or a lock 184dfdcada3SDoug Rabson * that is waiting for some other lock, it also has a vertex in the 185dfdcada3SDoug Rabson * owner_graph below. 186dfdcada3SDoug Rabson * 187dfdcada3SDoug Rabson * Locks: 188dfdcada3SDoug Rabson * (s) locked by state->ls_lock 189dfdcada3SDoug Rabson * (S) locked by lf_lock_states_lock 190dfdcada3SDoug Rabson * (g) locked by lf_owner_graph_lock 191dfdcada3SDoug Rabson * (c) const until freeing 192dfdcada3SDoug Rabson */ 193dfdcada3SDoug Rabson #define LOCK_OWNER_HASH_SIZE 256 194dfdcada3SDoug Rabson 195dfdcada3SDoug Rabson struct lock_owner { 196dfdcada3SDoug Rabson LIST_ENTRY(lock_owner) lo_link; /* (l) hash chain */ 197dfdcada3SDoug Rabson int lo_refs; /* (l) Number of locks referring to this */ 198dfdcada3SDoug Rabson int lo_flags; /* (c) Flags passwd to lf_advlock */ 199dfdcada3SDoug Rabson caddr_t lo_id; /* (c) Id value passed to lf_advlock */ 200dfdcada3SDoug Rabson pid_t lo_pid; /* (c) Process Id of the lock owner */ 201dfdcada3SDoug Rabson int lo_sysid; /* (c) System Id of the lock owner */ 202833dc05aSMateusz Guzik int lo_hash; /* (c) Used to lock the appropriate chain */ 203dfdcada3SDoug Rabson struct owner_vertex *lo_vertex; /* (g) entry in deadlock graph */ 204dfdcada3SDoug Rabson }; 205dfdcada3SDoug Rabson 206dfdcada3SDoug Rabson LIST_HEAD(lock_owner_list, lock_owner); 207dfdcada3SDoug Rabson 208833dc05aSMateusz Guzik struct lock_owner_chain { 209833dc05aSMateusz Guzik struct sx lock; 210833dc05aSMateusz Guzik struct lock_owner_list list; 211833dc05aSMateusz Guzik }; 212833dc05aSMateusz Guzik 213dfdcada3SDoug Rabson static struct sx lf_lock_states_lock; 214dfdcada3SDoug Rabson static struct lockf_list lf_lock_states; /* (S) */ 215833dc05aSMateusz Guzik static struct lock_owner_chain lf_lock_owners[LOCK_OWNER_HASH_SIZE]; 216dfdcada3SDoug Rabson 217dfdcada3SDoug Rabson /* 218dfdcada3SDoug Rabson * Structures for deadlock detection. 219dfdcada3SDoug Rabson * 220dfdcada3SDoug Rabson * We have two types of directed graph, the first is the set of locks, 221dfdcada3SDoug Rabson * both active and pending on a vnode. Within this graph, active locks 222dfdcada3SDoug Rabson * are terminal nodes in the graph (i.e. have no out-going 223dfdcada3SDoug Rabson * edges). Pending locks have out-going edges to each blocking active 224dfdcada3SDoug Rabson * lock that prevents the lock from being granted and also to each 225dfdcada3SDoug Rabson * older pending lock that would block them if it was active. The 226dfdcada3SDoug Rabson * graph for each vnode is naturally acyclic; new edges are only ever 227dfdcada3SDoug Rabson * added to or from new nodes (either new pending locks which only add 228dfdcada3SDoug Rabson * out-going edges or new active locks which only add in-coming edges) 229dfdcada3SDoug Rabson * therefore they cannot create loops in the lock graph. 230dfdcada3SDoug Rabson * 231dfdcada3SDoug Rabson * The second graph is a global graph of lock owners. Each lock owner 232dfdcada3SDoug Rabson * is a vertex in that graph and an edge is added to the graph 233dfdcada3SDoug Rabson * whenever an edge is added to a vnode graph, with end points 234dfdcada3SDoug Rabson * corresponding to owner of the new pending lock and the owner of the 235dfdcada3SDoug Rabson * lock upon which it waits. In order to prevent deadlock, we only add 236dfdcada3SDoug Rabson * an edge to this graph if the new edge would not create a cycle. 237dfdcada3SDoug Rabson * 238dfdcada3SDoug Rabson * The lock owner graph is topologically sorted, i.e. if a node has 239dfdcada3SDoug Rabson * any outgoing edges, then it has an order strictly less than any 240dfdcada3SDoug Rabson * node to which it has an outgoing edge. We preserve this ordering 241dfdcada3SDoug Rabson * (and detect cycles) on edge insertion using Algorithm PK from the 242dfdcada3SDoug Rabson * paper "A Dynamic Topological Sort Algorithm for Directed Acyclic 243dfdcada3SDoug Rabson * Graphs" (ACM Journal of Experimental Algorithms, Vol 11, Article 244dfdcada3SDoug Rabson * No. 1.7) 245dfdcada3SDoug Rabson */ 246dfdcada3SDoug Rabson struct owner_vertex; 247dfdcada3SDoug Rabson 248dfdcada3SDoug Rabson struct owner_edge { 249dfdcada3SDoug Rabson LIST_ENTRY(owner_edge) e_outlink; /* (g) link from's out-edge list */ 250dfdcada3SDoug Rabson LIST_ENTRY(owner_edge) e_inlink; /* (g) link to's in-edge list */ 251dfdcada3SDoug Rabson int e_refs; /* (g) number of times added */ 252dfdcada3SDoug Rabson struct owner_vertex *e_from; /* (c) out-going from here */ 253dfdcada3SDoug Rabson struct owner_vertex *e_to; /* (c) in-coming to here */ 254dfdcada3SDoug Rabson }; 255dfdcada3SDoug Rabson LIST_HEAD(owner_edge_list, owner_edge); 256dfdcada3SDoug Rabson 257dfdcada3SDoug Rabson struct owner_vertex { 258dfdcada3SDoug Rabson TAILQ_ENTRY(owner_vertex) v_link; /* (g) workspace for edge insertion */ 259dfdcada3SDoug Rabson uint32_t v_gen; /* (g) workspace for edge insertion */ 260dfdcada3SDoug Rabson int v_order; /* (g) order of vertex in graph */ 261dfdcada3SDoug Rabson struct owner_edge_list v_outedges;/* (g) list of out-edges */ 262dfdcada3SDoug Rabson struct owner_edge_list v_inedges; /* (g) list of in-edges */ 263dfdcada3SDoug Rabson struct lock_owner *v_owner; /* (c) corresponding lock owner */ 264dfdcada3SDoug Rabson }; 265dfdcada3SDoug Rabson TAILQ_HEAD(owner_vertex_list, owner_vertex); 266dfdcada3SDoug Rabson 267dfdcada3SDoug Rabson struct owner_graph { 268dfdcada3SDoug Rabson struct owner_vertex** g_vertices; /* (g) pointers to vertices */ 269dfdcada3SDoug Rabson int g_size; /* (g) number of vertices */ 270dfdcada3SDoug Rabson int g_space; /* (g) space allocated for vertices */ 271dfdcada3SDoug Rabson int *g_indexbuf; /* (g) workspace for loop detection */ 272dfdcada3SDoug Rabson uint32_t g_gen; /* (g) increment when re-ordering */ 273dfdcada3SDoug Rabson }; 274dfdcada3SDoug Rabson 275dfdcada3SDoug Rabson static struct sx lf_owner_graph_lock; 276dfdcada3SDoug Rabson static struct owner_graph lf_owner_graph; 277dfdcada3SDoug Rabson 278dfdcada3SDoug Rabson /* 279dfdcada3SDoug Rabson * Initialise various structures and locks. 280dfdcada3SDoug Rabson */ 281dfdcada3SDoug Rabson static void 282dfdcada3SDoug Rabson lf_init(void *dummy) 283dfdcada3SDoug Rabson { 284dfdcada3SDoug Rabson int i; 285dfdcada3SDoug Rabson 286dfdcada3SDoug Rabson sx_init(&lf_lock_states_lock, "lock states lock"); 287dfdcada3SDoug Rabson LIST_INIT(&lf_lock_states); 288dfdcada3SDoug Rabson 289833dc05aSMateusz Guzik for (i = 0; i < LOCK_OWNER_HASH_SIZE; i++) { 290833dc05aSMateusz Guzik sx_init(&lf_lock_owners[i].lock, "lock owners lock"); 291833dc05aSMateusz Guzik LIST_INIT(&lf_lock_owners[i].list); 292833dc05aSMateusz Guzik } 293dfdcada3SDoug Rabson 294dfdcada3SDoug Rabson sx_init(&lf_owner_graph_lock, "owner graph lock"); 295dfdcada3SDoug Rabson graph_init(&lf_owner_graph); 296dfdcada3SDoug Rabson } 297dfdcada3SDoug Rabson SYSINIT(lf_init, SI_SUB_LOCK, SI_ORDER_FIRST, lf_init, NULL); 298dfdcada3SDoug Rabson 299dfdcada3SDoug Rabson /* 300dfdcada3SDoug Rabson * Generate a hash value for a lock owner. 301dfdcada3SDoug Rabson */ 302dfdcada3SDoug Rabson static int 303d357c16aSMateusz Guzik lf_hash_owner(caddr_t id, struct vnode *vp, struct flock *fl, int flags) 304dfdcada3SDoug Rabson { 305dfdcada3SDoug Rabson uint32_t h; 306dfdcada3SDoug Rabson 307dfdcada3SDoug Rabson if (flags & F_REMOTE) { 308dfdcada3SDoug Rabson h = HASHSTEP(0, fl->l_pid); 309dfdcada3SDoug Rabson h = HASHSTEP(h, fl->l_sysid); 310dfdcada3SDoug Rabson } else if (flags & F_FLOCK) { 311dfdcada3SDoug Rabson h = ((uintptr_t) id) >> 7; 312dfdcada3SDoug Rabson } else { 313d357c16aSMateusz Guzik h = ((uintptr_t) vp) >> 7; 314dfdcada3SDoug Rabson } 315dfdcada3SDoug Rabson 316dfdcada3SDoug Rabson return (h % LOCK_OWNER_HASH_SIZE); 317dfdcada3SDoug Rabson } 318dfdcada3SDoug Rabson 319dfdcada3SDoug Rabson /* 320dfdcada3SDoug Rabson * Return true if a lock owner matches the details passed to 321dfdcada3SDoug Rabson * lf_advlock. 322dfdcada3SDoug Rabson */ 323dfdcada3SDoug Rabson static int 324dfdcada3SDoug Rabson lf_owner_matches(struct lock_owner *lo, caddr_t id, struct flock *fl, 325dfdcada3SDoug Rabson int flags) 326dfdcada3SDoug Rabson { 327dfdcada3SDoug Rabson if (flags & F_REMOTE) { 328dfdcada3SDoug Rabson return lo->lo_pid == fl->l_pid 329dfdcada3SDoug Rabson && lo->lo_sysid == fl->l_sysid; 330dfdcada3SDoug Rabson } else { 331dfdcada3SDoug Rabson return lo->lo_id == id; 332dfdcada3SDoug Rabson } 333dfdcada3SDoug Rabson } 334dfdcada3SDoug Rabson 335dfdcada3SDoug Rabson static struct lockf_entry * 336dfdcada3SDoug Rabson lf_alloc_lock(struct lock_owner *lo) 337dfdcada3SDoug Rabson { 338dfdcada3SDoug Rabson struct lockf_entry *lf; 339dfdcada3SDoug Rabson 340dfdcada3SDoug Rabson lf = malloc(sizeof(struct lockf_entry), M_LOCKF, M_WAITOK|M_ZERO); 341dfdcada3SDoug Rabson 342dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 343dfdcada3SDoug Rabson if (lockf_debug & 4) 344dfdcada3SDoug Rabson printf("Allocated lock %p\n", lf); 345dfdcada3SDoug Rabson #endif 346dfdcada3SDoug Rabson if (lo) { 347833dc05aSMateusz Guzik sx_xlock(&lf_lock_owners[lo->lo_hash].lock); 348dfdcada3SDoug Rabson lo->lo_refs++; 349833dc05aSMateusz Guzik sx_xunlock(&lf_lock_owners[lo->lo_hash].lock); 350dfdcada3SDoug Rabson lf->lf_owner = lo; 351dfdcada3SDoug Rabson } 352dfdcada3SDoug Rabson 353dfdcada3SDoug Rabson return (lf); 354dfdcada3SDoug Rabson } 355dfdcada3SDoug Rabson 3568af54d4cSKonstantin Belousov static int 357dfdcada3SDoug Rabson lf_free_lock(struct lockf_entry *lock) 358dfdcada3SDoug Rabson { 359833dc05aSMateusz Guzik struct sx *chainlock; 3608af54d4cSKonstantin Belousov 3618af54d4cSKonstantin Belousov KASSERT(lock->lf_refs > 0, ("lockf_entry negative ref count %p", lock)); 3628af54d4cSKonstantin Belousov if (--lock->lf_refs > 0) 3638af54d4cSKonstantin Belousov return (0); 364dfdcada3SDoug Rabson /* 365dfdcada3SDoug Rabson * Adjust the lock_owner reference count and 366dfdcada3SDoug Rabson * reclaim the entry if this is the last lock 367dfdcada3SDoug Rabson * for that owner. 368dfdcada3SDoug Rabson */ 369dfdcada3SDoug Rabson struct lock_owner *lo = lock->lf_owner; 370dfdcada3SDoug Rabson if (lo) { 371dfdcada3SDoug Rabson KASSERT(LIST_EMPTY(&lock->lf_outedges), 372e3043798SPedro F. Giffuni ("freeing lock with dependencies")); 373dfdcada3SDoug Rabson KASSERT(LIST_EMPTY(&lock->lf_inedges), 374dfdcada3SDoug Rabson ("freeing lock with dependants")); 375833dc05aSMateusz Guzik chainlock = &lf_lock_owners[lo->lo_hash].lock; 376833dc05aSMateusz Guzik sx_xlock(chainlock); 377dfdcada3SDoug Rabson KASSERT(lo->lo_refs > 0, ("lock owner refcount")); 378dfdcada3SDoug Rabson lo->lo_refs--; 379dfdcada3SDoug Rabson if (lo->lo_refs == 0) { 380dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 381dfdcada3SDoug Rabson if (lockf_debug & 1) 382dfdcada3SDoug Rabson printf("lf_free_lock: freeing lock owner %p\n", 383dfdcada3SDoug Rabson lo); 384dfdcada3SDoug Rabson #endif 385dfdcada3SDoug Rabson if (lo->lo_vertex) { 386dfdcada3SDoug Rabson sx_xlock(&lf_owner_graph_lock); 387dfdcada3SDoug Rabson graph_free_vertex(&lf_owner_graph, 388dfdcada3SDoug Rabson lo->lo_vertex); 389dfdcada3SDoug Rabson sx_xunlock(&lf_owner_graph_lock); 390dfdcada3SDoug Rabson } 391dfdcada3SDoug Rabson LIST_REMOVE(lo, lo_link); 392dfdcada3SDoug Rabson free(lo, M_LOCKF); 393dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 394dfdcada3SDoug Rabson if (lockf_debug & 4) 395dfdcada3SDoug Rabson printf("Freed lock owner %p\n", lo); 396dfdcada3SDoug Rabson #endif 397dfdcada3SDoug Rabson } 398833dc05aSMateusz Guzik sx_unlock(chainlock); 399dfdcada3SDoug Rabson } 400dfdcada3SDoug Rabson if ((lock->lf_flags & F_REMOTE) && lock->lf_vnode) { 401dfdcada3SDoug Rabson vrele(lock->lf_vnode); 402dfdcada3SDoug Rabson lock->lf_vnode = NULL; 403dfdcada3SDoug Rabson } 404dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 405dfdcada3SDoug Rabson if (lockf_debug & 4) 406dfdcada3SDoug Rabson printf("Freed lock %p\n", lock); 407dfdcada3SDoug Rabson #endif 408dfdcada3SDoug Rabson free(lock, M_LOCKF); 4098af54d4cSKonstantin Belousov return (1); 410dfdcada3SDoug Rabson } 41192dc7331SDavid Greenman 41292dc7331SDavid Greenman /* 41392dc7331SDavid Greenman * Advisory record locking support 41492dc7331SDavid Greenman */ 41592dc7331SDavid Greenman int 416dfdcada3SDoug Rabson lf_advlockasync(struct vop_advlockasync_args *ap, struct lockf **statep, 417dfdcada3SDoug Rabson u_quad_t size) 41892dc7331SDavid Greenman { 4190d3323f5SMateusz Guzik struct lockf *state; 420bc02f1d9SJeff Roberson struct flock *fl = ap->a_fl; 421dfdcada3SDoug Rabson struct lockf_entry *lock; 422bc02f1d9SJeff Roberson struct vnode *vp = ap->a_vp; 423dfdcada3SDoug Rabson caddr_t id = ap->a_id; 424dfdcada3SDoug Rabson int flags = ap->a_flags; 425dfdcada3SDoug Rabson int hash; 426dfdcada3SDoug Rabson struct lock_owner *lo; 427c4778eedSAndrey A. Chernov off_t start, end, oadd; 42892dc7331SDavid Greenman int error; 42992dc7331SDavid Greenman 43092dc7331SDavid Greenman /* 431dfdcada3SDoug Rabson * Handle the F_UNLKSYS case first - no need to mess about 432dfdcada3SDoug Rabson * creating a lock owner for this one. 433dfdcada3SDoug Rabson */ 434dfdcada3SDoug Rabson if (ap->a_op == F_UNLCKSYS) { 435dfdcada3SDoug Rabson lf_clearremotesys(fl->l_sysid); 436dfdcada3SDoug Rabson return (0); 437dfdcada3SDoug Rabson } 438dfdcada3SDoug Rabson 439dfdcada3SDoug Rabson /* 44092dc7331SDavid Greenman * Convert the flock structure into a start and end. 44192dc7331SDavid Greenman */ 44292dc7331SDavid Greenman switch (fl->l_whence) { 44392dc7331SDavid Greenman case SEEK_SET: 44492dc7331SDavid Greenman case SEEK_CUR: 44592dc7331SDavid Greenman /* 44692dc7331SDavid Greenman * Caller is responsible for adding any necessary offset 44792dc7331SDavid Greenman * when SEEK_CUR is used. 44892dc7331SDavid Greenman */ 44992dc7331SDavid Greenman start = fl->l_start; 45092dc7331SDavid Greenman break; 45192dc7331SDavid Greenman 45292dc7331SDavid Greenman case SEEK_END: 453c8e76343SAndrey A. Chernov if (size > OFF_MAX || 454bc02f1d9SJeff Roberson (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 455bc02f1d9SJeff Roberson return (EOVERFLOW); 45692dc7331SDavid Greenman start = size + fl->l_start; 45792dc7331SDavid Greenman break; 45892dc7331SDavid Greenman 45992dc7331SDavid Greenman default: 460bc02f1d9SJeff Roberson return (EINVAL); 46192dc7331SDavid Greenman } 462bc02f1d9SJeff Roberson if (start < 0) 463bc02f1d9SJeff Roberson return (EINVAL); 464f510e1c2SAndrey A. Chernov if (fl->l_len < 0) { 465bc02f1d9SJeff Roberson if (start == 0) 466bc02f1d9SJeff Roberson return (EINVAL); 467f510e1c2SAndrey A. Chernov end = start - 1; 46862be011eSAndrey A. Chernov start += fl->l_len; 469bc02f1d9SJeff Roberson if (start < 0) 470bc02f1d9SJeff Roberson return (EINVAL); 471dfdcada3SDoug Rabson } else if (fl->l_len == 0) { 472dfdcada3SDoug Rabson end = OFF_MAX; 473dfdcada3SDoug Rabson } else { 474c4778eedSAndrey A. Chernov oadd = fl->l_len - 1; 475bc02f1d9SJeff Roberson if (oadd > OFF_MAX - start) 476bc02f1d9SJeff Roberson return (EOVERFLOW); 47769cc1d0dSAndrey A. Chernov end = start + oadd; 478a88bd8aaSBruce Evans } 4793bcc218fSKonstantin Belousov 4803bcc218fSKonstantin Belousov retry_setlock: 4813bcc218fSKonstantin Belousov 482a88bd8aaSBruce Evans /* 483a88bd8aaSBruce Evans * Avoid the common case of unlocking when inode has no locks. 484a88bd8aaSBruce Evans */ 4857d853f62SMateusz Guzik if (ap->a_op != F_SETLK && (*statep) == NULL) { 486842832aeSDoug Rabson VI_LOCK(vp); 487842832aeSDoug Rabson if ((*statep) == NULL) { 488a88bd8aaSBruce Evans fl->l_type = F_UNLCK; 489842832aeSDoug Rabson VI_UNLOCK(vp); 490bc02f1d9SJeff Roberson return (0); 491a88bd8aaSBruce Evans } 492842832aeSDoug Rabson VI_UNLOCK(vp); 4937d853f62SMateusz Guzik } 494dfdcada3SDoug Rabson 49592dc7331SDavid Greenman /* 496dfdcada3SDoug Rabson * Map our arguments to an existing lock owner or create one 497dfdcada3SDoug Rabson * if this is the first time we have seen this owner. 498bc02f1d9SJeff Roberson */ 499d357c16aSMateusz Guzik hash = lf_hash_owner(id, vp, fl, flags); 500833dc05aSMateusz Guzik sx_xlock(&lf_lock_owners[hash].lock); 501833dc05aSMateusz Guzik LIST_FOREACH(lo, &lf_lock_owners[hash].list, lo_link) 502dfdcada3SDoug Rabson if (lf_owner_matches(lo, id, fl, flags)) 503dfdcada3SDoug Rabson break; 504dfdcada3SDoug Rabson if (!lo) { 505dfdcada3SDoug Rabson /* 506dfdcada3SDoug Rabson * We initialise the lock with a reference 507dfdcada3SDoug Rabson * count which matches the new lockf_entry 508dfdcada3SDoug Rabson * structure created below. 509dfdcada3SDoug Rabson */ 510dfdcada3SDoug Rabson lo = malloc(sizeof(struct lock_owner), M_LOCKF, 511dfdcada3SDoug Rabson M_WAITOK|M_ZERO); 512dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 513dfdcada3SDoug Rabson if (lockf_debug & 4) 514dfdcada3SDoug Rabson printf("Allocated lock owner %p\n", lo); 515dfdcada3SDoug Rabson #endif 516dfdcada3SDoug Rabson 517dfdcada3SDoug Rabson lo->lo_refs = 1; 518dfdcada3SDoug Rabson lo->lo_flags = flags; 519dfdcada3SDoug Rabson lo->lo_id = id; 520833dc05aSMateusz Guzik lo->lo_hash = hash; 521dfdcada3SDoug Rabson if (flags & F_REMOTE) { 522dfdcada3SDoug Rabson lo->lo_pid = fl->l_pid; 523dfdcada3SDoug Rabson lo->lo_sysid = fl->l_sysid; 524dfdcada3SDoug Rabson } else if (flags & F_FLOCK) { 525dfdcada3SDoug Rabson lo->lo_pid = -1; 526dfdcada3SDoug Rabson lo->lo_sysid = 0; 527dfdcada3SDoug Rabson } else { 528dfdcada3SDoug Rabson struct proc *p = (struct proc *) id; 529dfdcada3SDoug Rabson lo->lo_pid = p->p_pid; 530dfdcada3SDoug Rabson lo->lo_sysid = 0; 531004e08beSKonstantin Belousov } 532dfdcada3SDoug Rabson lo->lo_vertex = NULL; 533dfdcada3SDoug Rabson 534dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 535dfdcada3SDoug Rabson if (lockf_debug & 1) { 536dfdcada3SDoug Rabson printf("lf_advlockasync: new lock owner %p ", lo); 537dfdcada3SDoug Rabson lf_print_owner(lo); 538dfdcada3SDoug Rabson printf("\n"); 539dfdcada3SDoug Rabson } 540dfdcada3SDoug Rabson #endif 541dfdcada3SDoug Rabson 542833dc05aSMateusz Guzik LIST_INSERT_HEAD(&lf_lock_owners[hash].list, lo, lo_link); 543dfdcada3SDoug Rabson } else { 544bc02f1d9SJeff Roberson /* 545dfdcada3SDoug Rabson * We have seen this lock owner before, increase its 546dfdcada3SDoug Rabson * reference count to account for the new lockf_entry 547dfdcada3SDoug Rabson * structure we create below. 54892dc7331SDavid Greenman */ 549dfdcada3SDoug Rabson lo->lo_refs++; 550dfdcada3SDoug Rabson } 551833dc05aSMateusz Guzik sx_xunlock(&lf_lock_owners[hash].lock); 552dfdcada3SDoug Rabson 553dfdcada3SDoug Rabson /* 554dfdcada3SDoug Rabson * Create the lockf structure. We initialise the lf_owner 555dfdcada3SDoug Rabson * field here instead of in lf_alloc_lock() to avoid paying 556dfdcada3SDoug Rabson * the lf_lock_owners_lock tax twice. 557dfdcada3SDoug Rabson */ 558dfdcada3SDoug Rabson lock = lf_alloc_lock(NULL); 5598af54d4cSKonstantin Belousov lock->lf_refs = 1; 56092dc7331SDavid Greenman lock->lf_start = start; 56192dc7331SDavid Greenman lock->lf_end = end; 562dfdcada3SDoug Rabson lock->lf_owner = lo; 563dfdcada3SDoug Rabson lock->lf_vnode = vp; 564dfdcada3SDoug Rabson if (flags & F_REMOTE) { 565dfdcada3SDoug Rabson /* 566dfdcada3SDoug Rabson * For remote locks, the caller may release its ref to 567dfdcada3SDoug Rabson * the vnode at any time - we have to ref it here to 568dfdcada3SDoug Rabson * prevent it from being recycled unexpectedly. 569dfdcada3SDoug Rabson */ 570dfdcada3SDoug Rabson vref(vp); 571dfdcada3SDoug Rabson } 572dfdcada3SDoug Rabson 57392dc7331SDavid Greenman lock->lf_type = fl->l_type; 574dfdcada3SDoug Rabson LIST_INIT(&lock->lf_outedges); 575dfdcada3SDoug Rabson LIST_INIT(&lock->lf_inedges); 576dfdcada3SDoug Rabson lock->lf_async_task = ap->a_task; 57792dc7331SDavid Greenman lock->lf_flags = ap->a_flags; 578dfdcada3SDoug Rabson 57992dc7331SDavid Greenman /* 580dfdcada3SDoug Rabson * Do the requested operation. First find our state structure 581dfdcada3SDoug Rabson * and create a new one if necessary - the caller's *statep 582dfdcada3SDoug Rabson * variable and the state's ls_threads count is protected by 583dfdcada3SDoug Rabson * the vnode interlock. 58492dc7331SDavid Greenman */ 585bc02f1d9SJeff Roberson VI_LOCK(vp); 586abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) { 587eab626f1SKonstantin Belousov VI_UNLOCK(vp); 588eab626f1SKonstantin Belousov lf_free_lock(lock); 589eab626f1SKonstantin Belousov return (ENOENT); 590eab626f1SKonstantin Belousov } 591dfdcada3SDoug Rabson 592dfdcada3SDoug Rabson /* 593dfdcada3SDoug Rabson * Allocate a state structure if necessary. 594dfdcada3SDoug Rabson */ 595dfdcada3SDoug Rabson state = *statep; 596dfdcada3SDoug Rabson if (state == NULL) { 597dfdcada3SDoug Rabson struct lockf *ls; 598dfdcada3SDoug Rabson 599dfdcada3SDoug Rabson VI_UNLOCK(vp); 600dfdcada3SDoug Rabson 601dfdcada3SDoug Rabson ls = malloc(sizeof(struct lockf), M_LOCKF, M_WAITOK|M_ZERO); 602dfdcada3SDoug Rabson sx_init(&ls->ls_lock, "ls_lock"); 603dfdcada3SDoug Rabson LIST_INIT(&ls->ls_active); 604dfdcada3SDoug Rabson LIST_INIT(&ls->ls_pending); 60560cdfde0SDoug Rabson ls->ls_threads = 1; 606dfdcada3SDoug Rabson 607dfdcada3SDoug Rabson sx_xlock(&lf_lock_states_lock); 608dfdcada3SDoug Rabson LIST_INSERT_HEAD(&lf_lock_states, ls, ls_link); 609dfdcada3SDoug Rabson sx_xunlock(&lf_lock_states_lock); 610dfdcada3SDoug Rabson 611dfdcada3SDoug Rabson /* 612dfdcada3SDoug Rabson * Cope if we lost a race with some other thread while 613dfdcada3SDoug Rabson * trying to allocate memory. 614dfdcada3SDoug Rabson */ 615dfdcada3SDoug Rabson VI_LOCK(vp); 616abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) { 617eab626f1SKonstantin Belousov VI_UNLOCK(vp); 618eab626f1SKonstantin Belousov sx_xlock(&lf_lock_states_lock); 619eab626f1SKonstantin Belousov LIST_REMOVE(ls, ls_link); 620eab626f1SKonstantin Belousov sx_xunlock(&lf_lock_states_lock); 621eab626f1SKonstantin Belousov sx_destroy(&ls->ls_lock); 622eab626f1SKonstantin Belousov free(ls, M_LOCKF); 623eab626f1SKonstantin Belousov lf_free_lock(lock); 624eab626f1SKonstantin Belousov return (ENOENT); 625eab626f1SKonstantin Belousov } 626dfdcada3SDoug Rabson if ((*statep) == NULL) { 62760cdfde0SDoug Rabson state = *statep = ls; 62860cdfde0SDoug Rabson VI_UNLOCK(vp); 629dfdcada3SDoug Rabson } else { 63060cdfde0SDoug Rabson state = *statep; 631d363fa41SMateusz Guzik MPASS(state->ls_threads >= 0); 63260cdfde0SDoug Rabson state->ls_threads++; 63360cdfde0SDoug Rabson VI_UNLOCK(vp); 63460cdfde0SDoug Rabson 635dfdcada3SDoug Rabson sx_xlock(&lf_lock_states_lock); 636dfdcada3SDoug Rabson LIST_REMOVE(ls, ls_link); 637dfdcada3SDoug Rabson sx_xunlock(&lf_lock_states_lock); 638dfdcada3SDoug Rabson sx_destroy(&ls->ls_lock); 639dfdcada3SDoug Rabson free(ls, M_LOCKF); 640dfdcada3SDoug Rabson } 64160cdfde0SDoug Rabson } else { 642d363fa41SMateusz Guzik MPASS(state->ls_threads >= 0); 643dfdcada3SDoug Rabson state->ls_threads++; 644dfdcada3SDoug Rabson VI_UNLOCK(vp); 64560cdfde0SDoug Rabson } 646dfdcada3SDoug Rabson 647dfdcada3SDoug Rabson sx_xlock(&state->ls_lock); 648b33d6177SKonstantin Belousov /* 649b33d6177SKonstantin Belousov * Recheck the doomed vnode after state->ls_lock is 650b33d6177SKonstantin Belousov * locked. lf_purgelocks() requires that no new threads add 651abd80ddbSMateusz Guzik * pending locks when vnode is marked by VIRF_DOOMED flag. 652b33d6177SKonstantin Belousov */ 653abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) { 654d363fa41SMateusz Guzik VI_LOCK(vp); 655d363fa41SMateusz Guzik MPASS(state->ls_threads > 0); 656f02c9d28SKonstantin Belousov state->ls_threads--; 657f02c9d28SKonstantin Belousov wakeup(state); 658b33d6177SKonstantin Belousov VI_UNLOCK(vp); 6595dd6aabaSKonstantin Belousov sx_xunlock(&state->ls_lock); 660b33d6177SKonstantin Belousov lf_free_lock(lock); 661b33d6177SKonstantin Belousov return (ENOENT); 662b33d6177SKonstantin Belousov } 663b33d6177SKonstantin Belousov 66492dc7331SDavid Greenman switch (ap->a_op) { 66592dc7331SDavid Greenman case F_SETLK: 666dfdcada3SDoug Rabson error = lf_setlock(state, lock, vp, ap->a_cookiep); 667bc02f1d9SJeff Roberson break; 66892dc7331SDavid Greenman 66992dc7331SDavid Greenman case F_UNLCK: 670dfdcada3SDoug Rabson error = lf_clearlock(state, lock); 671dfdcada3SDoug Rabson lf_free_lock(lock); 672bc02f1d9SJeff Roberson break; 67392dc7331SDavid Greenman 67492dc7331SDavid Greenman case F_GETLK: 675dfdcada3SDoug Rabson error = lf_getlock(state, lock, fl); 676dfdcada3SDoug Rabson lf_free_lock(lock); 677dfdcada3SDoug Rabson break; 678dfdcada3SDoug Rabson 679dfdcada3SDoug Rabson case F_CANCEL: 680dfdcada3SDoug Rabson if (ap->a_cookiep) 681dfdcada3SDoug Rabson error = lf_cancel(state, lock, *ap->a_cookiep); 682dfdcada3SDoug Rabson else 683dfdcada3SDoug Rabson error = EINVAL; 684dfdcada3SDoug Rabson lf_free_lock(lock); 685bc02f1d9SJeff Roberson break; 68692dc7331SDavid Greenman 68792dc7331SDavid Greenman default: 688dfdcada3SDoug Rabson lf_free_lock(lock); 689013e6650SJeff Roberson error = EINVAL; 690bc02f1d9SJeff Roberson break; 69192dc7331SDavid Greenman } 692dfdcada3SDoug Rabson 693826b3d31SAndriy Gapon #ifdef DIAGNOSTIC 694dfdcada3SDoug Rabson /* 695dfdcada3SDoug Rabson * Check for some can't happen stuff. In this case, the active 696dfdcada3SDoug Rabson * lock list becoming disordered or containing mutually 697dfdcada3SDoug Rabson * blocking locks. We also check the pending list for locks 698dfdcada3SDoug Rabson * which should be active (i.e. have no out-going edges). 699dfdcada3SDoug Rabson */ 700dfdcada3SDoug Rabson LIST_FOREACH(lock, &state->ls_active, lf_link) { 701dfdcada3SDoug Rabson struct lockf_entry *lf; 702dfdcada3SDoug Rabson if (LIST_NEXT(lock, lf_link)) 703dfdcada3SDoug Rabson KASSERT((lock->lf_start 704dfdcada3SDoug Rabson <= LIST_NEXT(lock, lf_link)->lf_start), 705dfdcada3SDoug Rabson ("locks disordered")); 706dfdcada3SDoug Rabson LIST_FOREACH(lf, &state->ls_active, lf_link) { 707dfdcada3SDoug Rabson if (lock == lf) 708dfdcada3SDoug Rabson break; 709dfdcada3SDoug Rabson KASSERT(!lf_blocks(lock, lf), 710dfdcada3SDoug Rabson ("two conflicting active locks")); 711dfdcada3SDoug Rabson if (lock->lf_owner == lf->lf_owner) 712dfdcada3SDoug Rabson KASSERT(!lf_overlaps(lock, lf), 713dfdcada3SDoug Rabson ("two overlapping locks from same owner")); 714dfdcada3SDoug Rabson } 715dfdcada3SDoug Rabson } 716dfdcada3SDoug Rabson LIST_FOREACH(lock, &state->ls_pending, lf_link) { 717dfdcada3SDoug Rabson KASSERT(!LIST_EMPTY(&lock->lf_outedges), 718dfdcada3SDoug Rabson ("pending lock which should be active")); 719dfdcada3SDoug Rabson } 720dfdcada3SDoug Rabson #endif 721dfdcada3SDoug Rabson sx_xunlock(&state->ls_lock); 722dfdcada3SDoug Rabson 723dfdcada3SDoug Rabson VI_LOCK(vp); 724d363fa41SMateusz Guzik MPASS(state->ls_threads > 0); 725dfdcada3SDoug Rabson state->ls_threads--; 726d363fa41SMateusz Guzik if (state->ls_threads != 0) { 727717df0b0SMateusz Guzik wakeup(state); 728dfdcada3SDoug Rabson } 729bc02f1d9SJeff Roberson VI_UNLOCK(vp); 730dfdcada3SDoug Rabson 7313bcc218fSKonstantin Belousov if (error == EDOOFUS) { 7323bcc218fSKonstantin Belousov KASSERT(ap->a_op == F_SETLK, ("EDOOFUS")); 7333bcc218fSKonstantin Belousov goto retry_setlock; 7343bcc218fSKonstantin Belousov } 735013e6650SJeff Roberson return (error); 73692dc7331SDavid Greenman } 73792dc7331SDavid Greenman 738dfdcada3SDoug Rabson int 739dfdcada3SDoug Rabson lf_advlock(struct vop_advlock_args *ap, struct lockf **statep, u_quad_t size) 740dfdcada3SDoug Rabson { 741dfdcada3SDoug Rabson struct vop_advlockasync_args a; 742dfdcada3SDoug Rabson 743dfdcada3SDoug Rabson a.a_vp = ap->a_vp; 744dfdcada3SDoug Rabson a.a_id = ap->a_id; 745dfdcada3SDoug Rabson a.a_op = ap->a_op; 746dfdcada3SDoug Rabson a.a_fl = ap->a_fl; 747dfdcada3SDoug Rabson a.a_flags = ap->a_flags; 748dfdcada3SDoug Rabson a.a_task = NULL; 749dfdcada3SDoug Rabson a.a_cookiep = NULL; 750dfdcada3SDoug Rabson 751dfdcada3SDoug Rabson return (lf_advlockasync(&a, statep, size)); 752dfdcada3SDoug Rabson } 753dfdcada3SDoug Rabson 754eab626f1SKonstantin Belousov void 755eab626f1SKonstantin Belousov lf_purgelocks(struct vnode *vp, struct lockf **statep) 756eab626f1SKonstantin Belousov { 757eab626f1SKonstantin Belousov struct lockf *state; 758eab626f1SKonstantin Belousov struct lockf_entry *lock, *nlock; 759eab626f1SKonstantin Belousov 760eab626f1SKonstantin Belousov /* 761eab626f1SKonstantin Belousov * For this to work correctly, the caller must ensure that no 762eab626f1SKonstantin Belousov * other threads enter the locking system for this vnode, 763abd80ddbSMateusz Guzik * e.g. by checking VIRF_DOOMED. We wake up any threads that are 764eab626f1SKonstantin Belousov * sleeping waiting for locks on this vnode and then free all 765eab626f1SKonstantin Belousov * the remaining locks. 766eab626f1SKonstantin Belousov */ 767eab626f1SKonstantin Belousov VI_LOCK(vp); 768abd80ddbSMateusz Guzik KASSERT(VN_IS_DOOMED(vp), 769b33d6177SKonstantin Belousov ("lf_purgelocks: vp %p has not vgone yet", vp)); 770eab626f1SKonstantin Belousov state = *statep; 7710d3323f5SMateusz Guzik if (state == NULL) { 7720d3323f5SMateusz Guzik VI_UNLOCK(vp); 7730d3323f5SMateusz Guzik return; 7740d3323f5SMateusz Guzik } 775b33d6177SKonstantin Belousov *statep = NULL; 776c72ead28SMateusz Guzik if (LIST_EMPTY(&state->ls_active) && state->ls_threads == 0) { 777c72ead28SMateusz Guzik KASSERT(LIST_EMPTY(&state->ls_pending), 778c72ead28SMateusz Guzik ("freeing state with pending locks")); 779c72ead28SMateusz Guzik VI_UNLOCK(vp); 780c72ead28SMateusz Guzik goto out_free; 781c72ead28SMateusz Guzik } 782d363fa41SMateusz Guzik MPASS(state->ls_threads >= 0); 783eab626f1SKonstantin Belousov state->ls_threads++; 784eab626f1SKonstantin Belousov VI_UNLOCK(vp); 785eab626f1SKonstantin Belousov 786eab626f1SKonstantin Belousov sx_xlock(&state->ls_lock); 787eab626f1SKonstantin Belousov sx_xlock(&lf_owner_graph_lock); 788eab626f1SKonstantin Belousov LIST_FOREACH_SAFE(lock, &state->ls_pending, lf_link, nlock) { 789eab626f1SKonstantin Belousov LIST_REMOVE(lock, lf_link); 790eab626f1SKonstantin Belousov lf_remove_outgoing(lock); 791eab626f1SKonstantin Belousov lf_remove_incoming(lock); 792eab626f1SKonstantin Belousov 793eab626f1SKonstantin Belousov /* 794eab626f1SKonstantin Belousov * If its an async lock, we can just free it 795eab626f1SKonstantin Belousov * here, otherwise we let the sleeping thread 796eab626f1SKonstantin Belousov * free it. 797eab626f1SKonstantin Belousov */ 798eab626f1SKonstantin Belousov if (lock->lf_async_task) { 799eab626f1SKonstantin Belousov lf_free_lock(lock); 800eab626f1SKonstantin Belousov } else { 801eab626f1SKonstantin Belousov lock->lf_flags |= F_INTR; 802eab626f1SKonstantin Belousov wakeup(lock); 803eab626f1SKonstantin Belousov } 804eab626f1SKonstantin Belousov } 805eab626f1SKonstantin Belousov sx_xunlock(&lf_owner_graph_lock); 806eab626f1SKonstantin Belousov sx_xunlock(&state->ls_lock); 807eab626f1SKonstantin Belousov 808eab626f1SKonstantin Belousov /* 809eab626f1SKonstantin Belousov * Wait for all other threads, sleeping and otherwise 810eab626f1SKonstantin Belousov * to leave. 811eab626f1SKonstantin Belousov */ 812eab626f1SKonstantin Belousov VI_LOCK(vp); 813eab626f1SKonstantin Belousov while (state->ls_threads > 1) 814eab626f1SKonstantin Belousov msleep(state, VI_MTX(vp), 0, "purgelocks", 0); 815eab626f1SKonstantin Belousov VI_UNLOCK(vp); 816eab626f1SKonstantin Belousov 817eab626f1SKonstantin Belousov /* 818eab626f1SKonstantin Belousov * We can just free all the active locks since they 819e3043798SPedro F. Giffuni * will have no dependencies (we removed them all 820eab626f1SKonstantin Belousov * above). We don't need to bother locking since we 821eab626f1SKonstantin Belousov * are the last thread using this state structure. 822eab626f1SKonstantin Belousov */ 8239727972eSKonstantin Belousov KASSERT(LIST_EMPTY(&state->ls_pending), 8249727972eSKonstantin Belousov ("lock pending for %p", state)); 8259727972eSKonstantin Belousov LIST_FOREACH_SAFE(lock, &state->ls_active, lf_link, nlock) { 826eab626f1SKonstantin Belousov LIST_REMOVE(lock, lf_link); 827eab626f1SKonstantin Belousov lf_free_lock(lock); 828eab626f1SKonstantin Belousov } 829c72ead28SMateusz Guzik out_free: 830eab626f1SKonstantin Belousov sx_xlock(&lf_lock_states_lock); 831eab626f1SKonstantin Belousov LIST_REMOVE(state, ls_link); 832eab626f1SKonstantin Belousov sx_xunlock(&lf_lock_states_lock); 833eab626f1SKonstantin Belousov sx_destroy(&state->ls_lock); 834eab626f1SKonstantin Belousov free(state, M_LOCKF); 835eab626f1SKonstantin Belousov } 836eab626f1SKonstantin Belousov 837dfdcada3SDoug Rabson /* 838dfdcada3SDoug Rabson * Return non-zero if locks 'x' and 'y' overlap. 839dfdcada3SDoug Rabson */ 840dfdcada3SDoug Rabson static int 841dfdcada3SDoug Rabson lf_overlaps(struct lockf_entry *x, struct lockf_entry *y) 842dfdcada3SDoug Rabson { 843dfdcada3SDoug Rabson 844dfdcada3SDoug Rabson return (x->lf_start <= y->lf_end && x->lf_end >= y->lf_start); 845dfdcada3SDoug Rabson } 846dfdcada3SDoug Rabson 847dfdcada3SDoug Rabson /* 848dfdcada3SDoug Rabson * Return non-zero if lock 'x' is blocked by lock 'y' (or vice versa). 849dfdcada3SDoug Rabson */ 850dfdcada3SDoug Rabson static int 851dfdcada3SDoug Rabson lf_blocks(struct lockf_entry *x, struct lockf_entry *y) 852dfdcada3SDoug Rabson { 853dfdcada3SDoug Rabson 854dfdcada3SDoug Rabson return x->lf_owner != y->lf_owner 855dfdcada3SDoug Rabson && (x->lf_type == F_WRLCK || y->lf_type == F_WRLCK) 856dfdcada3SDoug Rabson && lf_overlaps(x, y); 857dfdcada3SDoug Rabson } 858dfdcada3SDoug Rabson 859dfdcada3SDoug Rabson /* 860dfdcada3SDoug Rabson * Allocate a lock edge from the free list 861dfdcada3SDoug Rabson */ 862dfdcada3SDoug Rabson static struct lockf_edge * 863dfdcada3SDoug Rabson lf_alloc_edge(void) 864dfdcada3SDoug Rabson { 865dfdcada3SDoug Rabson 866dfdcada3SDoug Rabson return (malloc(sizeof(struct lockf_edge), M_LOCKF, M_WAITOK|M_ZERO)); 867dfdcada3SDoug Rabson } 868dfdcada3SDoug Rabson 869dfdcada3SDoug Rabson /* 870dfdcada3SDoug Rabson * Free a lock edge. 871dfdcada3SDoug Rabson */ 872dfdcada3SDoug Rabson static void 873dfdcada3SDoug Rabson lf_free_edge(struct lockf_edge *e) 874dfdcada3SDoug Rabson { 875dfdcada3SDoug Rabson 876dfdcada3SDoug Rabson free(e, M_LOCKF); 877dfdcada3SDoug Rabson } 878dfdcada3SDoug Rabson 879dfdcada3SDoug Rabson /* 880dfdcada3SDoug Rabson * Ensure that the lock's owner has a corresponding vertex in the 881dfdcada3SDoug Rabson * owner graph. 882dfdcada3SDoug Rabson */ 883dfdcada3SDoug Rabson static void 884dfdcada3SDoug Rabson lf_alloc_vertex(struct lockf_entry *lock) 885dfdcada3SDoug Rabson { 886dfdcada3SDoug Rabson struct owner_graph *g = &lf_owner_graph; 887dfdcada3SDoug Rabson 888dfdcada3SDoug Rabson if (!lock->lf_owner->lo_vertex) 889dfdcada3SDoug Rabson lock->lf_owner->lo_vertex = 890dfdcada3SDoug Rabson graph_alloc_vertex(g, lock->lf_owner); 891dfdcada3SDoug Rabson } 892dfdcada3SDoug Rabson 893dfdcada3SDoug Rabson /* 894dfdcada3SDoug Rabson * Attempt to record an edge from lock x to lock y. Return EDEADLK if 895dfdcada3SDoug Rabson * the new edge would cause a cycle in the owner graph. 896dfdcada3SDoug Rabson */ 897dfdcada3SDoug Rabson static int 898dfdcada3SDoug Rabson lf_add_edge(struct lockf_entry *x, struct lockf_entry *y) 899dfdcada3SDoug Rabson { 900dfdcada3SDoug Rabson struct owner_graph *g = &lf_owner_graph; 901dfdcada3SDoug Rabson struct lockf_edge *e; 902dfdcada3SDoug Rabson int error; 903dfdcada3SDoug Rabson 904826b3d31SAndriy Gapon #ifdef DIAGNOSTIC 905dfdcada3SDoug Rabson LIST_FOREACH(e, &x->lf_outedges, le_outlink) 906dfdcada3SDoug Rabson KASSERT(e->le_to != y, ("adding lock edge twice")); 907dfdcada3SDoug Rabson #endif 908dfdcada3SDoug Rabson 909dfdcada3SDoug Rabson /* 910dfdcada3SDoug Rabson * Make sure the two owners have entries in the owner graph. 911dfdcada3SDoug Rabson */ 912dfdcada3SDoug Rabson lf_alloc_vertex(x); 913dfdcada3SDoug Rabson lf_alloc_vertex(y); 914dfdcada3SDoug Rabson 915dfdcada3SDoug Rabson error = graph_add_edge(g, x->lf_owner->lo_vertex, 916dfdcada3SDoug Rabson y->lf_owner->lo_vertex); 917dfdcada3SDoug Rabson if (error) 918dfdcada3SDoug Rabson return (error); 919dfdcada3SDoug Rabson 920dfdcada3SDoug Rabson e = lf_alloc_edge(); 921dfdcada3SDoug Rabson LIST_INSERT_HEAD(&x->lf_outedges, e, le_outlink); 922dfdcada3SDoug Rabson LIST_INSERT_HEAD(&y->lf_inedges, e, le_inlink); 923dfdcada3SDoug Rabson e->le_from = x; 924dfdcada3SDoug Rabson e->le_to = y; 925dfdcada3SDoug Rabson 926dfdcada3SDoug Rabson return (0); 927dfdcada3SDoug Rabson } 928dfdcada3SDoug Rabson 929dfdcada3SDoug Rabson /* 930dfdcada3SDoug Rabson * Remove an edge from the lock graph. 931dfdcada3SDoug Rabson */ 932dfdcada3SDoug Rabson static void 933dfdcada3SDoug Rabson lf_remove_edge(struct lockf_edge *e) 934dfdcada3SDoug Rabson { 935dfdcada3SDoug Rabson struct owner_graph *g = &lf_owner_graph; 936dfdcada3SDoug Rabson struct lockf_entry *x = e->le_from; 937dfdcada3SDoug Rabson struct lockf_entry *y = e->le_to; 938dfdcada3SDoug Rabson 939dfdcada3SDoug Rabson graph_remove_edge(g, x->lf_owner->lo_vertex, y->lf_owner->lo_vertex); 940dfdcada3SDoug Rabson LIST_REMOVE(e, le_outlink); 941dfdcada3SDoug Rabson LIST_REMOVE(e, le_inlink); 942dfdcada3SDoug Rabson e->le_from = NULL; 943dfdcada3SDoug Rabson e->le_to = NULL; 944dfdcada3SDoug Rabson lf_free_edge(e); 945dfdcada3SDoug Rabson } 946dfdcada3SDoug Rabson 947dfdcada3SDoug Rabson /* 948dfdcada3SDoug Rabson * Remove all out-going edges from lock x. 949dfdcada3SDoug Rabson */ 950dfdcada3SDoug Rabson static void 951dfdcada3SDoug Rabson lf_remove_outgoing(struct lockf_entry *x) 952dfdcada3SDoug Rabson { 953dfdcada3SDoug Rabson struct lockf_edge *e; 954dfdcada3SDoug Rabson 955dfdcada3SDoug Rabson while ((e = LIST_FIRST(&x->lf_outedges)) != NULL) { 956dfdcada3SDoug Rabson lf_remove_edge(e); 957dfdcada3SDoug Rabson } 958dfdcada3SDoug Rabson } 959dfdcada3SDoug Rabson 960dfdcada3SDoug Rabson /* 961dfdcada3SDoug Rabson * Remove all in-coming edges from lock x. 962dfdcada3SDoug Rabson */ 963dfdcada3SDoug Rabson static void 964dfdcada3SDoug Rabson lf_remove_incoming(struct lockf_entry *x) 965dfdcada3SDoug Rabson { 966dfdcada3SDoug Rabson struct lockf_edge *e; 967dfdcada3SDoug Rabson 968dfdcada3SDoug Rabson while ((e = LIST_FIRST(&x->lf_inedges)) != NULL) { 969dfdcada3SDoug Rabson lf_remove_edge(e); 970dfdcada3SDoug Rabson } 971dfdcada3SDoug Rabson } 972dfdcada3SDoug Rabson 973dfdcada3SDoug Rabson /* 974dfdcada3SDoug Rabson * Walk the list of locks for the file and create an out-going edge 975dfdcada3SDoug Rabson * from lock to each blocking lock. 976dfdcada3SDoug Rabson */ 977dfdcada3SDoug Rabson static int 978dfdcada3SDoug Rabson lf_add_outgoing(struct lockf *state, struct lockf_entry *lock) 979dfdcada3SDoug Rabson { 980dfdcada3SDoug Rabson struct lockf_entry *overlap; 981dfdcada3SDoug Rabson int error; 982dfdcada3SDoug Rabson 983dfdcada3SDoug Rabson LIST_FOREACH(overlap, &state->ls_active, lf_link) { 984dfdcada3SDoug Rabson /* 985dfdcada3SDoug Rabson * We may assume that the active list is sorted by 986dfdcada3SDoug Rabson * lf_start. 987dfdcada3SDoug Rabson */ 988dfdcada3SDoug Rabson if (overlap->lf_start > lock->lf_end) 989dfdcada3SDoug Rabson break; 990dfdcada3SDoug Rabson if (!lf_blocks(lock, overlap)) 991dfdcada3SDoug Rabson continue; 992dfdcada3SDoug Rabson 993dfdcada3SDoug Rabson /* 994dfdcada3SDoug Rabson * We've found a blocking lock. Add the corresponding 995dfdcada3SDoug Rabson * edge to the graphs and see if it would cause a 996dfdcada3SDoug Rabson * deadlock. 997dfdcada3SDoug Rabson */ 998dfdcada3SDoug Rabson error = lf_add_edge(lock, overlap); 999dfdcada3SDoug Rabson 1000dfdcada3SDoug Rabson /* 1001dfdcada3SDoug Rabson * The only error that lf_add_edge returns is EDEADLK. 1002dfdcada3SDoug Rabson * Remove any edges we added and return the error. 1003dfdcada3SDoug Rabson */ 1004dfdcada3SDoug Rabson if (error) { 1005dfdcada3SDoug Rabson lf_remove_outgoing(lock); 1006dfdcada3SDoug Rabson return (error); 1007dfdcada3SDoug Rabson } 1008dfdcada3SDoug Rabson } 1009dfdcada3SDoug Rabson 1010dfdcada3SDoug Rabson /* 1011dfdcada3SDoug Rabson * We also need to add edges to sleeping locks that block 1012dfdcada3SDoug Rabson * us. This ensures that lf_wakeup_lock cannot grant two 1013dfdcada3SDoug Rabson * mutually blocking locks simultaneously and also enforces a 1014dfdcada3SDoug Rabson * 'first come, first served' fairness model. Note that this 1015dfdcada3SDoug Rabson * only happens if we are blocked by at least one active lock 1016dfdcada3SDoug Rabson * due to the call to lf_getblock in lf_setlock below. 1017dfdcada3SDoug Rabson */ 1018dfdcada3SDoug Rabson LIST_FOREACH(overlap, &state->ls_pending, lf_link) { 1019dfdcada3SDoug Rabson if (!lf_blocks(lock, overlap)) 1020dfdcada3SDoug Rabson continue; 1021dfdcada3SDoug Rabson /* 1022dfdcada3SDoug Rabson * We've found a blocking lock. Add the corresponding 1023dfdcada3SDoug Rabson * edge to the graphs and see if it would cause a 1024dfdcada3SDoug Rabson * deadlock. 1025dfdcada3SDoug Rabson */ 1026dfdcada3SDoug Rabson error = lf_add_edge(lock, overlap); 1027dfdcada3SDoug Rabson 1028dfdcada3SDoug Rabson /* 1029dfdcada3SDoug Rabson * The only error that lf_add_edge returns is EDEADLK. 1030dfdcada3SDoug Rabson * Remove any edges we added and return the error. 1031dfdcada3SDoug Rabson */ 1032dfdcada3SDoug Rabson if (error) { 1033dfdcada3SDoug Rabson lf_remove_outgoing(lock); 1034dfdcada3SDoug Rabson return (error); 1035dfdcada3SDoug Rabson } 1036dfdcada3SDoug Rabson } 1037dfdcada3SDoug Rabson 1038dfdcada3SDoug Rabson return (0); 1039dfdcada3SDoug Rabson } 1040dfdcada3SDoug Rabson 1041dfdcada3SDoug Rabson /* 1042dfdcada3SDoug Rabson * Walk the list of pending locks for the file and create an in-coming 1043dfdcada3SDoug Rabson * edge from lock to each blocking lock. 1044dfdcada3SDoug Rabson */ 1045dfdcada3SDoug Rabson static int 1046dfdcada3SDoug Rabson lf_add_incoming(struct lockf *state, struct lockf_entry *lock) 1047dfdcada3SDoug Rabson { 1048dfdcada3SDoug Rabson struct lockf_entry *overlap; 1049dfdcada3SDoug Rabson int error; 1050dfdcada3SDoug Rabson 105163286976SMateusz Guzik sx_assert(&state->ls_lock, SX_XLOCKED); 105263286976SMateusz Guzik if (LIST_EMPTY(&state->ls_pending)) 105363286976SMateusz Guzik return (0); 105463286976SMateusz Guzik 105563286976SMateusz Guzik error = 0; 105663286976SMateusz Guzik sx_xlock(&lf_owner_graph_lock); 1057dfdcada3SDoug Rabson LIST_FOREACH(overlap, &state->ls_pending, lf_link) { 1058dfdcada3SDoug Rabson if (!lf_blocks(lock, overlap)) 1059dfdcada3SDoug Rabson continue; 1060dfdcada3SDoug Rabson 1061dfdcada3SDoug Rabson /* 1062dfdcada3SDoug Rabson * We've found a blocking lock. Add the corresponding 1063dfdcada3SDoug Rabson * edge to the graphs and see if it would cause a 1064dfdcada3SDoug Rabson * deadlock. 1065dfdcada3SDoug Rabson */ 1066dfdcada3SDoug Rabson error = lf_add_edge(overlap, lock); 1067dfdcada3SDoug Rabson 1068dfdcada3SDoug Rabson /* 1069dfdcada3SDoug Rabson * The only error that lf_add_edge returns is EDEADLK. 1070dfdcada3SDoug Rabson * Remove any edges we added and return the error. 1071dfdcada3SDoug Rabson */ 1072dfdcada3SDoug Rabson if (error) { 1073dfdcada3SDoug Rabson lf_remove_incoming(lock); 107463286976SMateusz Guzik break; 107563286976SMateusz Guzik } 107663286976SMateusz Guzik } 107763286976SMateusz Guzik sx_xunlock(&lf_owner_graph_lock); 1078dfdcada3SDoug Rabson return (error); 1079dfdcada3SDoug Rabson } 1080dfdcada3SDoug Rabson 1081dfdcada3SDoug Rabson /* 1082dfdcada3SDoug Rabson * Insert lock into the active list, keeping list entries ordered by 1083dfdcada3SDoug Rabson * increasing values of lf_start. 1084dfdcada3SDoug Rabson */ 1085dfdcada3SDoug Rabson static void 1086dfdcada3SDoug Rabson lf_insert_lock(struct lockf *state, struct lockf_entry *lock) 1087dfdcada3SDoug Rabson { 1088dfdcada3SDoug Rabson struct lockf_entry *lf, *lfprev; 1089dfdcada3SDoug Rabson 1090dfdcada3SDoug Rabson if (LIST_EMPTY(&state->ls_active)) { 1091dfdcada3SDoug Rabson LIST_INSERT_HEAD(&state->ls_active, lock, lf_link); 1092dfdcada3SDoug Rabson return; 1093dfdcada3SDoug Rabson } 1094dfdcada3SDoug Rabson 1095dfdcada3SDoug Rabson lfprev = NULL; 1096dfdcada3SDoug Rabson LIST_FOREACH(lf, &state->ls_active, lf_link) { 1097dfdcada3SDoug Rabson if (lf->lf_start > lock->lf_start) { 1098dfdcada3SDoug Rabson LIST_INSERT_BEFORE(lf, lock, lf_link); 1099dfdcada3SDoug Rabson return; 1100dfdcada3SDoug Rabson } 1101dfdcada3SDoug Rabson lfprev = lf; 1102dfdcada3SDoug Rabson } 1103dfdcada3SDoug Rabson LIST_INSERT_AFTER(lfprev, lock, lf_link); 1104dfdcada3SDoug Rabson } 1105dfdcada3SDoug Rabson 1106dfdcada3SDoug Rabson /* 1107dfdcada3SDoug Rabson * Wake up a sleeping lock and remove it from the pending list now 1108e3043798SPedro F. Giffuni * that all its dependencies have been resolved. The caller should 1109dfdcada3SDoug Rabson * arrange for the lock to be added to the active list, adjusting any 1110dfdcada3SDoug Rabson * existing locks for the same owner as needed. 1111dfdcada3SDoug Rabson */ 1112dfdcada3SDoug Rabson static void 1113dfdcada3SDoug Rabson lf_wakeup_lock(struct lockf *state, struct lockf_entry *wakelock) 1114dfdcada3SDoug Rabson { 1115dfdcada3SDoug Rabson 1116dfdcada3SDoug Rabson /* 1117dfdcada3SDoug Rabson * Remove from ls_pending list and wake up the caller 1118dfdcada3SDoug Rabson * or start the async notification, as appropriate. 1119dfdcada3SDoug Rabson */ 1120dfdcada3SDoug Rabson LIST_REMOVE(wakelock, lf_link); 1121dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 1122dfdcada3SDoug Rabson if (lockf_debug & 1) 1123dfdcada3SDoug Rabson lf_print("lf_wakeup_lock: awakening", wakelock); 1124dfdcada3SDoug Rabson #endif /* LOCKF_DEBUG */ 1125dfdcada3SDoug Rabson if (wakelock->lf_async_task) { 1126dfdcada3SDoug Rabson taskqueue_enqueue(taskqueue_thread, wakelock->lf_async_task); 1127dfdcada3SDoug Rabson } else { 1128dfdcada3SDoug Rabson wakeup(wakelock); 1129dfdcada3SDoug Rabson } 1130dfdcada3SDoug Rabson } 1131dfdcada3SDoug Rabson 1132dfdcada3SDoug Rabson /* 1133e3043798SPedro F. Giffuni * Re-check all dependent locks and remove edges to locks that we no 1134dfdcada3SDoug Rabson * longer block. If 'all' is non-zero, the lock has been removed and 1135e3043798SPedro F. Giffuni * we must remove all the dependencies, otherwise it has simply been 1136dfdcada3SDoug Rabson * reduced but remains active. Any pending locks which have been been 1137dfdcada3SDoug Rabson * unblocked are added to 'granted' 1138dfdcada3SDoug Rabson */ 1139dfdcada3SDoug Rabson static void 1140dfdcada3SDoug Rabson lf_update_dependancies(struct lockf *state, struct lockf_entry *lock, int all, 1141dfdcada3SDoug Rabson struct lockf_entry_list *granted) 1142dfdcada3SDoug Rabson { 1143dfdcada3SDoug Rabson struct lockf_edge *e, *ne; 1144dfdcada3SDoug Rabson struct lockf_entry *deplock; 1145dfdcada3SDoug Rabson 1146dfdcada3SDoug Rabson LIST_FOREACH_SAFE(e, &lock->lf_inedges, le_inlink, ne) { 1147dfdcada3SDoug Rabson deplock = e->le_from; 1148dfdcada3SDoug Rabson if (all || !lf_blocks(lock, deplock)) { 1149dfdcada3SDoug Rabson sx_xlock(&lf_owner_graph_lock); 1150dfdcada3SDoug Rabson lf_remove_edge(e); 1151dfdcada3SDoug Rabson sx_xunlock(&lf_owner_graph_lock); 1152dfdcada3SDoug Rabson if (LIST_EMPTY(&deplock->lf_outedges)) { 1153dfdcada3SDoug Rabson lf_wakeup_lock(state, deplock); 1154dfdcada3SDoug Rabson LIST_INSERT_HEAD(granted, deplock, lf_link); 1155dfdcada3SDoug Rabson } 1156dfdcada3SDoug Rabson } 1157dfdcada3SDoug Rabson } 1158dfdcada3SDoug Rabson } 1159dfdcada3SDoug Rabson 1160dfdcada3SDoug Rabson /* 1161e3043798SPedro F. Giffuni * Set the start of an existing active lock, updating dependencies and 1162dfdcada3SDoug Rabson * adding any newly woken locks to 'granted'. 1163dfdcada3SDoug Rabson */ 1164dfdcada3SDoug Rabson static void 1165dfdcada3SDoug Rabson lf_set_start(struct lockf *state, struct lockf_entry *lock, off_t new_start, 1166dfdcada3SDoug Rabson struct lockf_entry_list *granted) 1167dfdcada3SDoug Rabson { 1168dfdcada3SDoug Rabson 1169dfdcada3SDoug Rabson KASSERT(new_start >= lock->lf_start, ("can't increase lock")); 1170dfdcada3SDoug Rabson lock->lf_start = new_start; 1171dfdcada3SDoug Rabson LIST_REMOVE(lock, lf_link); 1172dfdcada3SDoug Rabson lf_insert_lock(state, lock); 1173dfdcada3SDoug Rabson lf_update_dependancies(state, lock, FALSE, granted); 1174dfdcada3SDoug Rabson } 1175dfdcada3SDoug Rabson 1176dfdcada3SDoug Rabson /* 1177e3043798SPedro F. Giffuni * Set the end of an existing active lock, updating dependencies and 1178dfdcada3SDoug Rabson * adding any newly woken locks to 'granted'. 1179dfdcada3SDoug Rabson */ 1180dfdcada3SDoug Rabson static void 1181dfdcada3SDoug Rabson lf_set_end(struct lockf *state, struct lockf_entry *lock, off_t new_end, 1182dfdcada3SDoug Rabson struct lockf_entry_list *granted) 1183dfdcada3SDoug Rabson { 1184dfdcada3SDoug Rabson 1185dfdcada3SDoug Rabson KASSERT(new_end <= lock->lf_end, ("can't increase lock")); 1186dfdcada3SDoug Rabson lock->lf_end = new_end; 1187dfdcada3SDoug Rabson lf_update_dependancies(state, lock, FALSE, granted); 1188dfdcada3SDoug Rabson } 1189dfdcada3SDoug Rabson 1190dfdcada3SDoug Rabson /* 1191dfdcada3SDoug Rabson * Add a lock to the active list, updating or removing any current 1192dfdcada3SDoug Rabson * locks owned by the same owner and processing any pending locks that 1193dfdcada3SDoug Rabson * become unblocked as a result. This code is also used for unlock 1194dfdcada3SDoug Rabson * since the logic for updating existing locks is identical. 1195dfdcada3SDoug Rabson * 1196dfdcada3SDoug Rabson * As a result of processing the new lock, we may unblock existing 1197dfdcada3SDoug Rabson * pending locks as a result of downgrading/unlocking. We simply 1198dfdcada3SDoug Rabson * activate the newly granted locks by looping. 1199dfdcada3SDoug Rabson * 1200e3043798SPedro F. Giffuni * Since the new lock already has its dependencies set up, we always 1201dfdcada3SDoug Rabson * add it to the list (unless its an unlock request). This may 1202dfdcada3SDoug Rabson * fragment the lock list in some pathological cases but its probably 1203dfdcada3SDoug Rabson * not a real problem. 1204dfdcada3SDoug Rabson */ 1205dfdcada3SDoug Rabson static void 1206dfdcada3SDoug Rabson lf_activate_lock(struct lockf *state, struct lockf_entry *lock) 1207dfdcada3SDoug Rabson { 1208dfdcada3SDoug Rabson struct lockf_entry *overlap, *lf; 1209dfdcada3SDoug Rabson struct lockf_entry_list granted; 1210dfdcada3SDoug Rabson int ovcase; 1211dfdcada3SDoug Rabson 1212dfdcada3SDoug Rabson LIST_INIT(&granted); 1213dfdcada3SDoug Rabson LIST_INSERT_HEAD(&granted, lock, lf_link); 1214dfdcada3SDoug Rabson 1215dfdcada3SDoug Rabson while (!LIST_EMPTY(&granted)) { 1216dfdcada3SDoug Rabson lock = LIST_FIRST(&granted); 1217dfdcada3SDoug Rabson LIST_REMOVE(lock, lf_link); 1218dfdcada3SDoug Rabson 1219dfdcada3SDoug Rabson /* 1220dfdcada3SDoug Rabson * Skip over locks owned by other processes. Handle 1221dfdcada3SDoug Rabson * any locks that overlap and are owned by ourselves. 1222dfdcada3SDoug Rabson */ 1223dfdcada3SDoug Rabson overlap = LIST_FIRST(&state->ls_active); 1224dfdcada3SDoug Rabson for (;;) { 1225dfdcada3SDoug Rabson ovcase = lf_findoverlap(&overlap, lock, SELF); 1226dfdcada3SDoug Rabson 1227dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 1228dfdcada3SDoug Rabson if (ovcase && (lockf_debug & 2)) { 1229dfdcada3SDoug Rabson printf("lf_setlock: overlap %d", ovcase); 1230dfdcada3SDoug Rabson lf_print("", overlap); 1231dfdcada3SDoug Rabson } 1232dfdcada3SDoug Rabson #endif 1233dfdcada3SDoug Rabson /* 1234dfdcada3SDoug Rabson * Six cases: 1235dfdcada3SDoug Rabson * 0) no overlap 1236dfdcada3SDoug Rabson * 1) overlap == lock 1237dfdcada3SDoug Rabson * 2) overlap contains lock 1238dfdcada3SDoug Rabson * 3) lock contains overlap 1239dfdcada3SDoug Rabson * 4) overlap starts before lock 1240dfdcada3SDoug Rabson * 5) overlap ends after lock 1241dfdcada3SDoug Rabson */ 1242dfdcada3SDoug Rabson switch (ovcase) { 1243dfdcada3SDoug Rabson case 0: /* no overlap */ 1244dfdcada3SDoug Rabson break; 1245dfdcada3SDoug Rabson 1246dfdcada3SDoug Rabson case 1: /* overlap == lock */ 1247dfdcada3SDoug Rabson /* 1248dfdcada3SDoug Rabson * We have already setup the 1249dfdcada3SDoug Rabson * dependants for the new lock, taking 1250dfdcada3SDoug Rabson * into account a possible downgrade 1251dfdcada3SDoug Rabson * or unlock. Remove the old lock. 1252dfdcada3SDoug Rabson */ 1253dfdcada3SDoug Rabson LIST_REMOVE(overlap, lf_link); 1254dfdcada3SDoug Rabson lf_update_dependancies(state, overlap, TRUE, 1255dfdcada3SDoug Rabson &granted); 1256dfdcada3SDoug Rabson lf_free_lock(overlap); 1257dfdcada3SDoug Rabson break; 1258dfdcada3SDoug Rabson 1259dfdcada3SDoug Rabson case 2: /* overlap contains lock */ 1260dfdcada3SDoug Rabson /* 1261dfdcada3SDoug Rabson * Just split the existing lock. 1262dfdcada3SDoug Rabson */ 1263dfdcada3SDoug Rabson lf_split(state, overlap, lock, &granted); 1264dfdcada3SDoug Rabson break; 1265dfdcada3SDoug Rabson 1266dfdcada3SDoug Rabson case 3: /* lock contains overlap */ 1267dfdcada3SDoug Rabson /* 1268dfdcada3SDoug Rabson * Delete the overlap and advance to 1269dfdcada3SDoug Rabson * the next entry in the list. 1270dfdcada3SDoug Rabson */ 1271dfdcada3SDoug Rabson lf = LIST_NEXT(overlap, lf_link); 1272dfdcada3SDoug Rabson LIST_REMOVE(overlap, lf_link); 1273dfdcada3SDoug Rabson lf_update_dependancies(state, overlap, TRUE, 1274dfdcada3SDoug Rabson &granted); 1275dfdcada3SDoug Rabson lf_free_lock(overlap); 1276dfdcada3SDoug Rabson overlap = lf; 1277dfdcada3SDoug Rabson continue; 1278dfdcada3SDoug Rabson 1279dfdcada3SDoug Rabson case 4: /* overlap starts before lock */ 1280dfdcada3SDoug Rabson /* 1281dfdcada3SDoug Rabson * Just update the overlap end and 1282dfdcada3SDoug Rabson * move on. 1283dfdcada3SDoug Rabson */ 1284dfdcada3SDoug Rabson lf_set_end(state, overlap, lock->lf_start - 1, 1285dfdcada3SDoug Rabson &granted); 1286dfdcada3SDoug Rabson overlap = LIST_NEXT(overlap, lf_link); 1287dfdcada3SDoug Rabson continue; 1288dfdcada3SDoug Rabson 1289dfdcada3SDoug Rabson case 5: /* overlap ends after lock */ 1290dfdcada3SDoug Rabson /* 1291dfdcada3SDoug Rabson * Change the start of overlap and 1292dfdcada3SDoug Rabson * re-insert. 1293dfdcada3SDoug Rabson */ 1294dfdcada3SDoug Rabson lf_set_start(state, overlap, lock->lf_end + 1, 1295dfdcada3SDoug Rabson &granted); 1296dfdcada3SDoug Rabson break; 1297dfdcada3SDoug Rabson } 1298dfdcada3SDoug Rabson break; 1299dfdcada3SDoug Rabson } 1300dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 1301dfdcada3SDoug Rabson if (lockf_debug & 1) { 1302dfdcada3SDoug Rabson if (lock->lf_type != F_UNLCK) 1303dfdcada3SDoug Rabson lf_print("lf_activate_lock: activated", lock); 1304dfdcada3SDoug Rabson else 1305dfdcada3SDoug Rabson lf_print("lf_activate_lock: unlocked", lock); 1306dfdcada3SDoug Rabson lf_printlist("lf_activate_lock", lock); 1307dfdcada3SDoug Rabson } 1308dfdcada3SDoug Rabson #endif /* LOCKF_DEBUG */ 1309dfdcada3SDoug Rabson if (lock->lf_type != F_UNLCK) 1310dfdcada3SDoug Rabson lf_insert_lock(state, lock); 1311dfdcada3SDoug Rabson } 1312dfdcada3SDoug Rabson } 1313dfdcada3SDoug Rabson 1314dfdcada3SDoug Rabson /* 1315dfdcada3SDoug Rabson * Cancel a pending lock request, either as a result of a signal or a 1316dfdcada3SDoug Rabson * cancel request for an async lock. 1317dfdcada3SDoug Rabson */ 1318dfdcada3SDoug Rabson static void 1319dfdcada3SDoug Rabson lf_cancel_lock(struct lockf *state, struct lockf_entry *lock) 1320dfdcada3SDoug Rabson { 1321dfdcada3SDoug Rabson struct lockf_entry_list granted; 1322dfdcada3SDoug Rabson 1323dfdcada3SDoug Rabson /* 1324dfdcada3SDoug Rabson * Note it is theoretically possible that cancelling this lock 1325dfdcada3SDoug Rabson * may allow some other pending lock to become 1326dfdcada3SDoug Rabson * active. Consider this case: 1327dfdcada3SDoug Rabson * 1328e3043798SPedro F. Giffuni * Owner Action Result Dependencies 1329dfdcada3SDoug Rabson * 1330dfdcada3SDoug Rabson * A: lock [0..0] succeeds 1331dfdcada3SDoug Rabson * B: lock [2..2] succeeds 1332dfdcada3SDoug Rabson * C: lock [1..2] blocked C->B 1333dfdcada3SDoug Rabson * D: lock [0..1] blocked C->B,D->A,D->C 1334dfdcada3SDoug Rabson * A: unlock [0..0] C->B,D->C 1335dfdcada3SDoug Rabson * C: cancel [1..2] 1336dfdcada3SDoug Rabson */ 1337dfdcada3SDoug Rabson 1338dfdcada3SDoug Rabson LIST_REMOVE(lock, lf_link); 1339dfdcada3SDoug Rabson 1340dfdcada3SDoug Rabson /* 1341dfdcada3SDoug Rabson * Removing out-going edges is simple. 1342dfdcada3SDoug Rabson */ 1343dfdcada3SDoug Rabson sx_xlock(&lf_owner_graph_lock); 1344dfdcada3SDoug Rabson lf_remove_outgoing(lock); 1345dfdcada3SDoug Rabson sx_xunlock(&lf_owner_graph_lock); 1346dfdcada3SDoug Rabson 1347dfdcada3SDoug Rabson /* 1348dfdcada3SDoug Rabson * Removing in-coming edges may allow some other lock to 1349dfdcada3SDoug Rabson * become active - we use lf_update_dependancies to figure 1350dfdcada3SDoug Rabson * this out. 1351dfdcada3SDoug Rabson */ 1352dfdcada3SDoug Rabson LIST_INIT(&granted); 1353dfdcada3SDoug Rabson lf_update_dependancies(state, lock, TRUE, &granted); 1354dfdcada3SDoug Rabson lf_free_lock(lock); 1355dfdcada3SDoug Rabson 1356dfdcada3SDoug Rabson /* 1357dfdcada3SDoug Rabson * Feed any newly active locks to lf_activate_lock. 1358dfdcada3SDoug Rabson */ 1359dfdcada3SDoug Rabson while (!LIST_EMPTY(&granted)) { 1360dfdcada3SDoug Rabson lock = LIST_FIRST(&granted); 1361dfdcada3SDoug Rabson LIST_REMOVE(lock, lf_link); 1362dfdcada3SDoug Rabson lf_activate_lock(state, lock); 1363dfdcada3SDoug Rabson } 1364dfdcada3SDoug Rabson } 1365dfdcada3SDoug Rabson 136692dc7331SDavid Greenman /* 136792dc7331SDavid Greenman * Set a byte-range lock. 136892dc7331SDavid Greenman */ 136987b6de2bSPoul-Henning Kamp static int 1370dfdcada3SDoug Rabson lf_setlock(struct lockf *state, struct lockf_entry *lock, struct vnode *vp, 1371dfdcada3SDoug Rabson void **cookiep) 137292dc7331SDavid Greenman { 137392dc7331SDavid Greenman static char lockstr[] = "lockf"; 1374883a5a4aSKonstantin Belousov int error, priority, stops_deferred; 137592dc7331SDavid Greenman 137692dc7331SDavid Greenman #ifdef LOCKF_DEBUG 137792dc7331SDavid Greenman if (lockf_debug & 1) 137892dc7331SDavid Greenman lf_print("lf_setlock", lock); 137992dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 138092dc7331SDavid Greenman 138192dc7331SDavid Greenman /* 138292dc7331SDavid Greenman * Set the priority 138392dc7331SDavid Greenman */ 138492dc7331SDavid Greenman priority = PLOCK; 138592dc7331SDavid Greenman if (lock->lf_type == F_WRLCK) 138692dc7331SDavid Greenman priority += 4; 1387c675522fSDoug Rabson if (!(lock->lf_flags & F_NOINTR)) 138892dc7331SDavid Greenman priority |= PCATCH; 138992dc7331SDavid Greenman /* 139092dc7331SDavid Greenman * Scan lock list for this file looking for locks that would block us. 139192dc7331SDavid Greenman */ 13928aec91b5SKonstantin Belousov if (lf_getblock(state, lock)) { 139392dc7331SDavid Greenman /* 139492dc7331SDavid Greenman * Free the structure and return if nonblocking. 139592dc7331SDavid Greenman */ 1396dfdcada3SDoug Rabson if ((lock->lf_flags & F_WAIT) == 0 1397dfdcada3SDoug Rabson && lock->lf_async_task == NULL) { 1398dfdcada3SDoug Rabson lf_free_lock(lock); 1399dfdcada3SDoug Rabson error = EAGAIN; 1400dfdcada3SDoug Rabson goto out; 140192dc7331SDavid Greenman } 140292dc7331SDavid Greenman 1403dfdcada3SDoug Rabson /* 140406c85cefSDoug Rabson * For flock type locks, we must first remove 140506c85cefSDoug Rabson * any shared locks that we hold before we sleep 140606c85cefSDoug Rabson * waiting for an exclusive lock. 140706c85cefSDoug Rabson */ 140806c85cefSDoug Rabson if ((lock->lf_flags & F_FLOCK) && 140906c85cefSDoug Rabson lock->lf_type == F_WRLCK) { 141006c85cefSDoug Rabson lock->lf_type = F_UNLCK; 141106c85cefSDoug Rabson lf_activate_lock(state, lock); 141206c85cefSDoug Rabson lock->lf_type = F_WRLCK; 141306c85cefSDoug Rabson } 141406c85cefSDoug Rabson 141506c85cefSDoug Rabson /* 1416dfdcada3SDoug Rabson * We are blocked. Create edges to each blocking lock, 1417dfdcada3SDoug Rabson * checking for deadlock using the owner graph. For 1418dfdcada3SDoug Rabson * simplicity, we run deadlock detection for all 1419dfdcada3SDoug Rabson * locks, posix and otherwise. 1420dfdcada3SDoug Rabson */ 1421dfdcada3SDoug Rabson sx_xlock(&lf_owner_graph_lock); 1422dfdcada3SDoug Rabson error = lf_add_outgoing(state, lock); 1423dfdcada3SDoug Rabson sx_xunlock(&lf_owner_graph_lock); 1424dfdcada3SDoug Rabson 1425dfdcada3SDoug Rabson if (error) { 1426dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 1427dfdcada3SDoug Rabson if (lockf_debug & 1) 1428dfdcada3SDoug Rabson lf_print("lf_setlock: deadlock", lock); 1429dfdcada3SDoug Rabson #endif 1430dfdcada3SDoug Rabson lf_free_lock(lock); 1431dfdcada3SDoug Rabson goto out; 143292dc7331SDavid Greenman } 1433dfdcada3SDoug Rabson 143492dc7331SDavid Greenman /* 1435dfdcada3SDoug Rabson * We have added edges to everything that blocks 1436dfdcada3SDoug Rabson * us. Sleep until they all go away. 143792dc7331SDavid Greenman */ 1438dfdcada3SDoug Rabson LIST_INSERT_HEAD(&state->ls_pending, lock, lf_link); 143992dc7331SDavid Greenman #ifdef LOCKF_DEBUG 144092dc7331SDavid Greenman if (lockf_debug & 1) { 1441dfdcada3SDoug Rabson struct lockf_edge *e; 1442dfdcada3SDoug Rabson LIST_FOREACH(e, &lock->lf_outedges, le_outlink) { 1443dfdcada3SDoug Rabson lf_print("lf_setlock: blocking on", e->le_to); 1444dfdcada3SDoug Rabson lf_printlist("lf_setlock", e->le_to); 1445dfdcada3SDoug Rabson } 144692dc7331SDavid Greenman } 144792dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 1448dfdcada3SDoug Rabson 1449dfdcada3SDoug Rabson if ((lock->lf_flags & F_WAIT) == 0) { 1450dfdcada3SDoug Rabson /* 1451dfdcada3SDoug Rabson * The caller requested async notification - 1452dfdcada3SDoug Rabson * this callback happens when the blocking 1453dfdcada3SDoug Rabson * lock is released, allowing the caller to 1454dfdcada3SDoug Rabson * make another attempt to take the lock. 1455dfdcada3SDoug Rabson */ 1456dfdcada3SDoug Rabson *cookiep = (void *) lock; 1457dfdcada3SDoug Rabson error = EINPROGRESS; 1458dfdcada3SDoug Rabson goto out; 1459dfdcada3SDoug Rabson } 1460dfdcada3SDoug Rabson 14618af54d4cSKonstantin Belousov lock->lf_refs++; 1462883a5a4aSKonstantin Belousov stops_deferred = sigdeferstop(SIGDEFERSTOP_ERESTART); 1463dfdcada3SDoug Rabson error = sx_sleep(lock, &state->ls_lock, priority, lockstr, 0); 1464883a5a4aSKonstantin Belousov sigallowstop(stops_deferred); 14658af54d4cSKonstantin Belousov if (lf_free_lock(lock)) { 14663bcc218fSKonstantin Belousov error = EDOOFUS; 14678af54d4cSKonstantin Belousov goto out; 14688af54d4cSKonstantin Belousov } 14698af54d4cSKonstantin Belousov 147092dc7331SDavid Greenman /* 14711168ab08SBruce Evans * We may have been awakened by a signal and/or by a 1472dfdcada3SDoug Rabson * debugger continuing us (in which cases we must 1473dfdcada3SDoug Rabson * remove our lock graph edges) and/or by another 1474dfdcada3SDoug Rabson * process releasing a lock (in which case our edges 1475dfdcada3SDoug Rabson * have already been removed and we have been moved to 1476eab626f1SKonstantin Belousov * the active list). We may also have been woken by 1477eab626f1SKonstantin Belousov * lf_purgelocks which we report to the caller as 1478eab626f1SKonstantin Belousov * EINTR. In that case, lf_purgelocks will have 1479eab626f1SKonstantin Belousov * removed our lock graph edges. 1480dfdcada3SDoug Rabson * 1481dfdcada3SDoug Rabson * Note that it is possible to receive a signal after 1482dfdcada3SDoug Rabson * we were successfully woken (and moved to the active 1483dfdcada3SDoug Rabson * list) but before we resumed execution. In this 1484dfdcada3SDoug Rabson * case, our lf_outedges list will be clear. We 1485dfdcada3SDoug Rabson * pretend there was no error. 1486dfdcada3SDoug Rabson * 1487dfdcada3SDoug Rabson * Note also, if we have been sleeping long enough, we 1488dfdcada3SDoug Rabson * may now have incoming edges from some newer lock 1489dfdcada3SDoug Rabson * which is waiting behind us in the queue. 149092dc7331SDavid Greenman */ 1491eab626f1SKonstantin Belousov if (lock->lf_flags & F_INTR) { 1492eab626f1SKonstantin Belousov error = EINTR; 1493eab626f1SKonstantin Belousov lf_free_lock(lock); 1494eab626f1SKonstantin Belousov goto out; 1495eab626f1SKonstantin Belousov } 1496dfdcada3SDoug Rabson if (LIST_EMPTY(&lock->lf_outedges)) { 1497dfdcada3SDoug Rabson error = 0; 1498dfdcada3SDoug Rabson } else { 1499dfdcada3SDoug Rabson lf_cancel_lock(state, lock); 1500dfdcada3SDoug Rabson goto out; 15011168ab08SBruce Evans } 1502dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 1503dfdcada3SDoug Rabson if (lockf_debug & 1) { 1504dfdcada3SDoug Rabson lf_print("lf_setlock: granted", lock); 1505dfdcada3SDoug Rabson } 1506dfdcada3SDoug Rabson #endif 1507dfdcada3SDoug Rabson goto out; 1508dfdcada3SDoug Rabson } 1509dfdcada3SDoug Rabson /* 1510dfdcada3SDoug Rabson * It looks like we are going to grant the lock. First add 1511dfdcada3SDoug Rabson * edges from any currently pending lock that the new lock 1512dfdcada3SDoug Rabson * would block. 1513dfdcada3SDoug Rabson */ 1514dfdcada3SDoug Rabson error = lf_add_incoming(state, lock); 15151168ab08SBruce Evans if (error) { 1516dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 1517dfdcada3SDoug Rabson if (lockf_debug & 1) 1518dfdcada3SDoug Rabson lf_print("lf_setlock: deadlock", lock); 1519dfdcada3SDoug Rabson #endif 1520dfdcada3SDoug Rabson lf_free_lock(lock); 1521dfdcada3SDoug Rabson goto out; 152292dc7331SDavid Greenman } 1523dfdcada3SDoug Rabson 152492dc7331SDavid Greenman /* 152592dc7331SDavid Greenman * No blocks!! Add the lock. Note that we will 152692dc7331SDavid Greenman * downgrade or upgrade any overlapping locks this 152792dc7331SDavid Greenman * process already owns. 152892dc7331SDavid Greenman */ 1529dfdcada3SDoug Rabson lf_activate_lock(state, lock); 1530dfdcada3SDoug Rabson error = 0; 1531dfdcada3SDoug Rabson out: 1532dfdcada3SDoug Rabson return (error); 153392dc7331SDavid Greenman } 153492dc7331SDavid Greenman 153592dc7331SDavid Greenman /* 153692dc7331SDavid Greenman * Remove a byte-range lock on an inode. 153792dc7331SDavid Greenman * 153892dc7331SDavid Greenman * Generally, find the lock (or an overlap to that lock) 153992dc7331SDavid Greenman * and remove it (or shrink it), then wakeup anyone we can. 154092dc7331SDavid Greenman */ 154187b6de2bSPoul-Henning Kamp static int 1542dfdcada3SDoug Rabson lf_clearlock(struct lockf *state, struct lockf_entry *unlock) 154392dc7331SDavid Greenman { 1544dfdcada3SDoug Rabson struct lockf_entry *overlap; 154592dc7331SDavid Greenman 1546dfdcada3SDoug Rabson overlap = LIST_FIRST(&state->ls_active); 1547dfdcada3SDoug Rabson 1548dfdcada3SDoug Rabson if (overlap == NOLOCKF) 154992dc7331SDavid Greenman return (0); 155092dc7331SDavid Greenman #ifdef LOCKF_DEBUG 155192dc7331SDavid Greenman if (unlock->lf_type != F_UNLCK) 155292dc7331SDavid Greenman panic("lf_clearlock: bad type"); 155392dc7331SDavid Greenman if (lockf_debug & 1) 155492dc7331SDavid Greenman lf_print("lf_clearlock", unlock); 155592dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 155692dc7331SDavid Greenman 1557dfdcada3SDoug Rabson lf_activate_lock(state, unlock); 155892dc7331SDavid Greenman 155992dc7331SDavid Greenman return (0); 156092dc7331SDavid Greenman } 156192dc7331SDavid Greenman 156292dc7331SDavid Greenman /* 1563dfdcada3SDoug Rabson * Check whether there is a blocking lock, and if so return its 1564dfdcada3SDoug Rabson * details in '*fl'. 156592dc7331SDavid Greenman */ 156687b6de2bSPoul-Henning Kamp static int 1567dfdcada3SDoug Rabson lf_getlock(struct lockf *state, struct lockf_entry *lock, struct flock *fl) 156892dc7331SDavid Greenman { 1569dfdcada3SDoug Rabson struct lockf_entry *block; 157092dc7331SDavid Greenman 157192dc7331SDavid Greenman #ifdef LOCKF_DEBUG 157292dc7331SDavid Greenman if (lockf_debug & 1) 157392dc7331SDavid Greenman lf_print("lf_getlock", lock); 157492dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 157592dc7331SDavid Greenman 1576dfdcada3SDoug Rabson if ((block = lf_getblock(state, lock))) { 157792dc7331SDavid Greenman fl->l_type = block->lf_type; 157892dc7331SDavid Greenman fl->l_whence = SEEK_SET; 157992dc7331SDavid Greenman fl->l_start = block->lf_start; 1580dfdcada3SDoug Rabson if (block->lf_end == OFF_MAX) 158192dc7331SDavid Greenman fl->l_len = 0; 158292dc7331SDavid Greenman else 158392dc7331SDavid Greenman fl->l_len = block->lf_end - block->lf_start + 1; 1584dfdcada3SDoug Rabson fl->l_pid = block->lf_owner->lo_pid; 1585dfdcada3SDoug Rabson fl->l_sysid = block->lf_owner->lo_sysid; 158692dc7331SDavid Greenman } else { 158792dc7331SDavid Greenman fl->l_type = F_UNLCK; 158892dc7331SDavid Greenman } 158992dc7331SDavid Greenman return (0); 159092dc7331SDavid Greenman } 159192dc7331SDavid Greenman 159292dc7331SDavid Greenman /* 1593dfdcada3SDoug Rabson * Cancel an async lock request. 1594dfdcada3SDoug Rabson */ 1595dfdcada3SDoug Rabson static int 1596dfdcada3SDoug Rabson lf_cancel(struct lockf *state, struct lockf_entry *lock, void *cookie) 1597dfdcada3SDoug Rabson { 1598dfdcada3SDoug Rabson struct lockf_entry *reallock; 1599dfdcada3SDoug Rabson 1600dfdcada3SDoug Rabson /* 1601dfdcada3SDoug Rabson * We need to match this request with an existing lock 1602dfdcada3SDoug Rabson * request. 1603dfdcada3SDoug Rabson */ 1604dfdcada3SDoug Rabson LIST_FOREACH(reallock, &state->ls_pending, lf_link) { 1605dfdcada3SDoug Rabson if ((void *) reallock == cookie) { 1606dfdcada3SDoug Rabson /* 1607dfdcada3SDoug Rabson * Double-check that this lock looks right 1608dfdcada3SDoug Rabson * (maybe use a rolling ID for the cancel 1609dfdcada3SDoug Rabson * cookie instead?) 1610dfdcada3SDoug Rabson */ 1611dfdcada3SDoug Rabson if (!(reallock->lf_vnode == lock->lf_vnode 1612dfdcada3SDoug Rabson && reallock->lf_start == lock->lf_start 1613dfdcada3SDoug Rabson && reallock->lf_end == lock->lf_end)) { 1614dfdcada3SDoug Rabson return (ENOENT); 1615dfdcada3SDoug Rabson } 1616dfdcada3SDoug Rabson 1617dfdcada3SDoug Rabson /* 1618dfdcada3SDoug Rabson * Make sure this lock was async and then just 1619dfdcada3SDoug Rabson * remove it from its wait lists. 1620dfdcada3SDoug Rabson */ 1621dfdcada3SDoug Rabson if (!reallock->lf_async_task) { 1622dfdcada3SDoug Rabson return (ENOENT); 1623dfdcada3SDoug Rabson } 1624dfdcada3SDoug Rabson 1625dfdcada3SDoug Rabson /* 1626dfdcada3SDoug Rabson * Note that since any other thread must take 1627dfdcada3SDoug Rabson * state->ls_lock before it can possibly 1628dfdcada3SDoug Rabson * trigger the async callback, we are safe 1629dfdcada3SDoug Rabson * from a race with lf_wakeup_lock, i.e. we 1630dfdcada3SDoug Rabson * can free the lock (actually our caller does 1631dfdcada3SDoug Rabson * this). 1632dfdcada3SDoug Rabson */ 1633dfdcada3SDoug Rabson lf_cancel_lock(state, reallock); 1634dfdcada3SDoug Rabson return (0); 1635dfdcada3SDoug Rabson } 1636dfdcada3SDoug Rabson } 1637dfdcada3SDoug Rabson 1638dfdcada3SDoug Rabson /* 1639dfdcada3SDoug Rabson * We didn't find a matching lock - not much we can do here. 1640dfdcada3SDoug Rabson */ 1641dfdcada3SDoug Rabson return (ENOENT); 1642dfdcada3SDoug Rabson } 1643dfdcada3SDoug Rabson 1644dfdcada3SDoug Rabson /* 164592dc7331SDavid Greenman * Walk the list of locks for an inode and 164692dc7331SDavid Greenman * return the first blocking lock. 164792dc7331SDavid Greenman */ 1648dfdcada3SDoug Rabson static struct lockf_entry * 1649dfdcada3SDoug Rabson lf_getblock(struct lockf *state, struct lockf_entry *lock) 165092dc7331SDavid Greenman { 1651dfdcada3SDoug Rabson struct lockf_entry *overlap; 165292dc7331SDavid Greenman 1653dfdcada3SDoug Rabson LIST_FOREACH(overlap, &state->ls_active, lf_link) { 165492dc7331SDavid Greenman /* 1655dfdcada3SDoug Rabson * We may assume that the active list is sorted by 1656dfdcada3SDoug Rabson * lf_start. 165792dc7331SDavid Greenman */ 1658dfdcada3SDoug Rabson if (overlap->lf_start > lock->lf_end) 1659dfdcada3SDoug Rabson break; 1660dfdcada3SDoug Rabson if (!lf_blocks(lock, overlap)) 1661dfdcada3SDoug Rabson continue; 166292dc7331SDavid Greenman return (overlap); 166392dc7331SDavid Greenman } 166492dc7331SDavid Greenman return (NOLOCKF); 166592dc7331SDavid Greenman } 166692dc7331SDavid Greenman 166792dc7331SDavid Greenman /* 1668dfdcada3SDoug Rabson * Walk the list of locks for an inode to find an overlapping lock (if 1669dfdcada3SDoug Rabson * any) and return a classification of that overlap. 1670dfdcada3SDoug Rabson * 1671dfdcada3SDoug Rabson * Arguments: 1672dfdcada3SDoug Rabson * *overlap The place in the lock list to start looking 1673dfdcada3SDoug Rabson * lock The lock which is being tested 1674dfdcada3SDoug Rabson * type Pass 'SELF' to test only locks with the same 1675dfdcada3SDoug Rabson * owner as lock, or 'OTHER' to test only locks 1676dfdcada3SDoug Rabson * with a different owner 1677dfdcada3SDoug Rabson * 1678dfdcada3SDoug Rabson * Returns one of six values: 1679dfdcada3SDoug Rabson * 0) no overlap 1680dfdcada3SDoug Rabson * 1) overlap == lock 1681dfdcada3SDoug Rabson * 2) overlap contains lock 1682dfdcada3SDoug Rabson * 3) lock contains overlap 1683dfdcada3SDoug Rabson * 4) overlap starts before lock 1684dfdcada3SDoug Rabson * 5) overlap ends after lock 1685dfdcada3SDoug Rabson * 1686dfdcada3SDoug Rabson * If there is an overlapping lock, '*overlap' is set to point at the 1687dfdcada3SDoug Rabson * overlapping lock. 168892dc7331SDavid Greenman * 168992dc7331SDavid Greenman * NOTE: this returns only the FIRST overlapping lock. There 169092dc7331SDavid Greenman * may be more than one. 169192dc7331SDavid Greenman */ 169287b6de2bSPoul-Henning Kamp static int 1693dfdcada3SDoug Rabson lf_findoverlap(struct lockf_entry **overlap, struct lockf_entry *lock, int type) 169492dc7331SDavid Greenman { 1695dfdcada3SDoug Rabson struct lockf_entry *lf; 169692dc7331SDavid Greenman off_t start, end; 1697dfdcada3SDoug Rabson int res; 169892dc7331SDavid Greenman 1699dfdcada3SDoug Rabson if ((*overlap) == NOLOCKF) { 170092dc7331SDavid Greenman return (0); 1701dfdcada3SDoug Rabson } 170292dc7331SDavid Greenman #ifdef LOCKF_DEBUG 170392dc7331SDavid Greenman if (lockf_debug & 2) 170492dc7331SDavid Greenman lf_print("lf_findoverlap: looking for overlap in", lock); 170592dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 170692dc7331SDavid Greenman start = lock->lf_start; 170792dc7331SDavid Greenman end = lock->lf_end; 1708dfdcada3SDoug Rabson res = 0; 1709dfdcada3SDoug Rabson while (*overlap) { 1710dfdcada3SDoug Rabson lf = *overlap; 1711dfdcada3SDoug Rabson if (lf->lf_start > end) 1712dfdcada3SDoug Rabson break; 1713dfdcada3SDoug Rabson if (((type & SELF) && lf->lf_owner != lock->lf_owner) || 1714dfdcada3SDoug Rabson ((type & OTHERS) && lf->lf_owner == lock->lf_owner)) { 1715dfdcada3SDoug Rabson *overlap = LIST_NEXT(lf, lf_link); 171692dc7331SDavid Greenman continue; 171792dc7331SDavid Greenman } 171892dc7331SDavid Greenman #ifdef LOCKF_DEBUG 171992dc7331SDavid Greenman if (lockf_debug & 2) 172092dc7331SDavid Greenman lf_print("\tchecking", lf); 172192dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 172292dc7331SDavid Greenman /* 172392dc7331SDavid Greenman * OK, check for overlap 172492dc7331SDavid Greenman * 172592dc7331SDavid Greenman * Six cases: 172692dc7331SDavid Greenman * 0) no overlap 172792dc7331SDavid Greenman * 1) overlap == lock 172892dc7331SDavid Greenman * 2) overlap contains lock 172992dc7331SDavid Greenman * 3) lock contains overlap 173092dc7331SDavid Greenman * 4) overlap starts before lock 173192dc7331SDavid Greenman * 5) overlap ends after lock 173292dc7331SDavid Greenman */ 1733dfdcada3SDoug Rabson if (start > lf->lf_end) { 173492dc7331SDavid Greenman /* Case 0 */ 173592dc7331SDavid Greenman #ifdef LOCKF_DEBUG 173692dc7331SDavid Greenman if (lockf_debug & 2) 173792dc7331SDavid Greenman printf("no overlap\n"); 173892dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 1739dfdcada3SDoug Rabson *overlap = LIST_NEXT(lf, lf_link); 174092dc7331SDavid Greenman continue; 174192dc7331SDavid Greenman } 1742dfdcada3SDoug Rabson if (lf->lf_start == start && lf->lf_end == end) { 174392dc7331SDavid Greenman /* Case 1 */ 174492dc7331SDavid Greenman #ifdef LOCKF_DEBUG 174592dc7331SDavid Greenman if (lockf_debug & 2) 174692dc7331SDavid Greenman printf("overlap == lock\n"); 174792dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 1748dfdcada3SDoug Rabson res = 1; 1749dfdcada3SDoug Rabson break; 175092dc7331SDavid Greenman } 1751dfdcada3SDoug Rabson if (lf->lf_start <= start && lf->lf_end >= end) { 175292dc7331SDavid Greenman /* Case 2 */ 175392dc7331SDavid Greenman #ifdef LOCKF_DEBUG 175492dc7331SDavid Greenman if (lockf_debug & 2) 175592dc7331SDavid Greenman printf("overlap contains lock\n"); 175692dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 1757dfdcada3SDoug Rabson res = 2; 1758dfdcada3SDoug Rabson break; 175992dc7331SDavid Greenman } 1760dfdcada3SDoug Rabson if (start <= lf->lf_start && end >= lf->lf_end) { 176192dc7331SDavid Greenman /* Case 3 */ 176292dc7331SDavid Greenman #ifdef LOCKF_DEBUG 176392dc7331SDavid Greenman if (lockf_debug & 2) 176492dc7331SDavid Greenman printf("lock contains overlap\n"); 176592dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 1766dfdcada3SDoug Rabson res = 3; 1767dfdcada3SDoug Rabson break; 176892dc7331SDavid Greenman } 1769dfdcada3SDoug Rabson if (lf->lf_start < start && lf->lf_end >= start) { 177092dc7331SDavid Greenman /* Case 4 */ 177192dc7331SDavid Greenman #ifdef LOCKF_DEBUG 177292dc7331SDavid Greenman if (lockf_debug & 2) 177392dc7331SDavid Greenman printf("overlap starts before lock\n"); 177492dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 1775dfdcada3SDoug Rabson res = 4; 1776dfdcada3SDoug Rabson break; 177792dc7331SDavid Greenman } 1778dfdcada3SDoug Rabson if (lf->lf_start > start && lf->lf_end > end) { 177992dc7331SDavid Greenman /* Case 5 */ 178092dc7331SDavid Greenman #ifdef LOCKF_DEBUG 178192dc7331SDavid Greenman if (lockf_debug & 2) 178292dc7331SDavid Greenman printf("overlap ends after lock\n"); 178392dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 1784dfdcada3SDoug Rabson res = 5; 1785dfdcada3SDoug Rabson break; 178692dc7331SDavid Greenman } 178792dc7331SDavid Greenman panic("lf_findoverlap: default"); 178892dc7331SDavid Greenman } 1789dfdcada3SDoug Rabson return (res); 179092dc7331SDavid Greenman } 179192dc7331SDavid Greenman 179292dc7331SDavid Greenman /* 1793dfdcada3SDoug Rabson * Split an the existing 'lock1', based on the extent of the lock 1794dfdcada3SDoug Rabson * described by 'lock2'. The existing lock should cover 'lock2' 1795dfdcada3SDoug Rabson * entirely. 1796dfdcada3SDoug Rabson * 1797dfdcada3SDoug Rabson * Any pending locks which have been been unblocked are added to 1798dfdcada3SDoug Rabson * 'granted' 179992dc7331SDavid Greenman */ 180087b6de2bSPoul-Henning Kamp static void 1801dfdcada3SDoug Rabson lf_split(struct lockf *state, struct lockf_entry *lock1, 1802dfdcada3SDoug Rabson struct lockf_entry *lock2, struct lockf_entry_list *granted) 180392dc7331SDavid Greenman { 1804dfdcada3SDoug Rabson struct lockf_entry *splitlock; 180592dc7331SDavid Greenman 180692dc7331SDavid Greenman #ifdef LOCKF_DEBUG 180792dc7331SDavid Greenman if (lockf_debug & 2) { 180892dc7331SDavid Greenman lf_print("lf_split", lock1); 180992dc7331SDavid Greenman lf_print("splitting from", lock2); 181092dc7331SDavid Greenman } 181192dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 181292dc7331SDavid Greenman /* 1813dfdcada3SDoug Rabson * Check to see if we don't need to split at all. 181492dc7331SDavid Greenman */ 181592dc7331SDavid Greenman if (lock1->lf_start == lock2->lf_start) { 1816dfdcada3SDoug Rabson lf_set_start(state, lock1, lock2->lf_end + 1, granted); 181792dc7331SDavid Greenman return; 181892dc7331SDavid Greenman } 181992dc7331SDavid Greenman if (lock1->lf_end == lock2->lf_end) { 1820dfdcada3SDoug Rabson lf_set_end(state, lock1, lock2->lf_start - 1, granted); 182192dc7331SDavid Greenman return; 182292dc7331SDavid Greenman } 182392dc7331SDavid Greenman /* 182492dc7331SDavid Greenman * Make a new lock consisting of the last part of 1825dfdcada3SDoug Rabson * the encompassing lock. 182692dc7331SDavid Greenman */ 1827dfdcada3SDoug Rabson splitlock = lf_alloc_lock(lock1->lf_owner); 1828dfdcada3SDoug Rabson memcpy(splitlock, lock1, sizeof *splitlock); 18298af54d4cSKonstantin Belousov splitlock->lf_refs = 1; 1830dfdcada3SDoug Rabson if (splitlock->lf_flags & F_REMOTE) 1831dfdcada3SDoug Rabson vref(splitlock->lf_vnode); 1832dfdcada3SDoug Rabson 1833dfdcada3SDoug Rabson /* 1834dfdcada3SDoug Rabson * This cannot cause a deadlock since any edges we would add 1835dfdcada3SDoug Rabson * to splitlock already exist in lock1. We must be sure to add 1836e3043798SPedro F. Giffuni * necessary dependencies to splitlock before we reduce lock1 1837dfdcada3SDoug Rabson * otherwise we may accidentally grant a pending lock that 1838dfdcada3SDoug Rabson * was blocked by the tail end of lock1. 1839dfdcada3SDoug Rabson */ 184092dc7331SDavid Greenman splitlock->lf_start = lock2->lf_end + 1; 1841dfdcada3SDoug Rabson LIST_INIT(&splitlock->lf_outedges); 1842dfdcada3SDoug Rabson LIST_INIT(&splitlock->lf_inedges); 1843dfdcada3SDoug Rabson lf_add_incoming(state, splitlock); 1844dfdcada3SDoug Rabson 1845dfdcada3SDoug Rabson lf_set_end(state, lock1, lock2->lf_start - 1, granted); 1846dfdcada3SDoug Rabson 184792dc7331SDavid Greenman /* 184892dc7331SDavid Greenman * OK, now link it in 184992dc7331SDavid Greenman */ 1850dfdcada3SDoug Rabson lf_insert_lock(state, splitlock); 1851dfdcada3SDoug Rabson } 1852dfdcada3SDoug Rabson 1853c675522fSDoug Rabson struct lockdesc { 1854c675522fSDoug Rabson STAILQ_ENTRY(lockdesc) link; 1855dfdcada3SDoug Rabson struct vnode *vp; 1856dfdcada3SDoug Rabson struct flock fl; 1857dfdcada3SDoug Rabson }; 1858c675522fSDoug Rabson STAILQ_HEAD(lockdesclist, lockdesc); 1859dfdcada3SDoug Rabson 1860c675522fSDoug Rabson int 1861c675522fSDoug Rabson lf_iteratelocks_sysid(int sysid, lf_iterator *fn, void *arg) 1862dfdcada3SDoug Rabson { 1863dfdcada3SDoug Rabson struct lockf *ls; 1864dfdcada3SDoug Rabson struct lockf_entry *lf; 1865c675522fSDoug Rabson struct lockdesc *ldesc; 1866c675522fSDoug Rabson struct lockdesclist locks; 1867c675522fSDoug Rabson int error; 1868dfdcada3SDoug Rabson 1869dfdcada3SDoug Rabson /* 1870dfdcada3SDoug Rabson * In order to keep the locking simple, we iterate over the 1871dfdcada3SDoug Rabson * active lock lists to build a list of locks that need 1872c675522fSDoug Rabson * releasing. We then call the iterator for each one in turn. 1873dfdcada3SDoug Rabson * 1874dfdcada3SDoug Rabson * We take an extra reference to the vnode for the duration to 1875dfdcada3SDoug Rabson * make sure it doesn't go away before we are finished. 1876dfdcada3SDoug Rabson */ 1877dfdcada3SDoug Rabson STAILQ_INIT(&locks); 1878dfdcada3SDoug Rabson sx_xlock(&lf_lock_states_lock); 1879dfdcada3SDoug Rabson LIST_FOREACH(ls, &lf_lock_states, ls_link) { 1880dfdcada3SDoug Rabson sx_xlock(&ls->ls_lock); 1881dfdcada3SDoug Rabson LIST_FOREACH(lf, &ls->ls_active, lf_link) { 1882dfdcada3SDoug Rabson if (lf->lf_owner->lo_sysid != sysid) 1883dfdcada3SDoug Rabson continue; 1884dfdcada3SDoug Rabson 1885c675522fSDoug Rabson ldesc = malloc(sizeof(struct lockdesc), M_LOCKF, 1886dfdcada3SDoug Rabson M_WAITOK); 1887c675522fSDoug Rabson ldesc->vp = lf->lf_vnode; 1888c675522fSDoug Rabson vref(ldesc->vp); 1889c675522fSDoug Rabson ldesc->fl.l_start = lf->lf_start; 1890dfdcada3SDoug Rabson if (lf->lf_end == OFF_MAX) 1891c675522fSDoug Rabson ldesc->fl.l_len = 0; 1892dfdcada3SDoug Rabson else 1893c675522fSDoug Rabson ldesc->fl.l_len = 1894dfdcada3SDoug Rabson lf->lf_end - lf->lf_start + 1; 1895c675522fSDoug Rabson ldesc->fl.l_whence = SEEK_SET; 1896c675522fSDoug Rabson ldesc->fl.l_type = F_UNLCK; 1897c675522fSDoug Rabson ldesc->fl.l_pid = lf->lf_owner->lo_pid; 1898c675522fSDoug Rabson ldesc->fl.l_sysid = sysid; 1899c675522fSDoug Rabson STAILQ_INSERT_TAIL(&locks, ldesc, link); 1900dfdcada3SDoug Rabson } 1901dfdcada3SDoug Rabson sx_xunlock(&ls->ls_lock); 1902dfdcada3SDoug Rabson } 1903dfdcada3SDoug Rabson sx_xunlock(&lf_lock_states_lock); 1904dfdcada3SDoug Rabson 1905c675522fSDoug Rabson /* 1906c675522fSDoug Rabson * Call the iterator function for each lock in turn. If the 1907c675522fSDoug Rabson * iterator returns an error code, just free the rest of the 1908c675522fSDoug Rabson * lockdesc structures. 1909c675522fSDoug Rabson */ 1910c675522fSDoug Rabson error = 0; 1911c675522fSDoug Rabson while ((ldesc = STAILQ_FIRST(&locks)) != NULL) { 1912dfdcada3SDoug Rabson STAILQ_REMOVE_HEAD(&locks, link); 1913c675522fSDoug Rabson if (!error) 1914c675522fSDoug Rabson error = fn(ldesc->vp, &ldesc->fl, arg); 1915c675522fSDoug Rabson vrele(ldesc->vp); 1916c675522fSDoug Rabson free(ldesc, M_LOCKF); 1917dfdcada3SDoug Rabson } 1918c675522fSDoug Rabson 1919c675522fSDoug Rabson return (error); 1920c675522fSDoug Rabson } 1921c675522fSDoug Rabson 1922c675522fSDoug Rabson int 1923c675522fSDoug Rabson lf_iteratelocks_vnode(struct vnode *vp, lf_iterator *fn, void *arg) 1924c675522fSDoug Rabson { 1925c675522fSDoug Rabson struct lockf *ls; 1926c675522fSDoug Rabson struct lockf_entry *lf; 1927c675522fSDoug Rabson struct lockdesc *ldesc; 1928c675522fSDoug Rabson struct lockdesclist locks; 1929c675522fSDoug Rabson int error; 1930c675522fSDoug Rabson 1931c675522fSDoug Rabson /* 1932c675522fSDoug Rabson * In order to keep the locking simple, we iterate over the 1933c675522fSDoug Rabson * active lock lists to build a list of locks that need 1934c675522fSDoug Rabson * releasing. We then call the iterator for each one in turn. 1935c675522fSDoug Rabson * 1936c675522fSDoug Rabson * We take an extra reference to the vnode for the duration to 1937c675522fSDoug Rabson * make sure it doesn't go away before we are finished. 1938c675522fSDoug Rabson */ 1939c675522fSDoug Rabson STAILQ_INIT(&locks); 194028fe6a3fSKonstantin Belousov VI_LOCK(vp); 1941c675522fSDoug Rabson ls = vp->v_lockf; 194228fe6a3fSKonstantin Belousov if (!ls) { 194328fe6a3fSKonstantin Belousov VI_UNLOCK(vp); 1944c675522fSDoug Rabson return (0); 194528fe6a3fSKonstantin Belousov } 1946d363fa41SMateusz Guzik MPASS(ls->ls_threads >= 0); 194728fe6a3fSKonstantin Belousov ls->ls_threads++; 194828fe6a3fSKonstantin Belousov VI_UNLOCK(vp); 1949c675522fSDoug Rabson 1950c675522fSDoug Rabson sx_xlock(&ls->ls_lock); 1951c675522fSDoug Rabson LIST_FOREACH(lf, &ls->ls_active, lf_link) { 1952c675522fSDoug Rabson ldesc = malloc(sizeof(struct lockdesc), M_LOCKF, 1953c675522fSDoug Rabson M_WAITOK); 1954c675522fSDoug Rabson ldesc->vp = lf->lf_vnode; 1955c675522fSDoug Rabson vref(ldesc->vp); 1956c675522fSDoug Rabson ldesc->fl.l_start = lf->lf_start; 1957c675522fSDoug Rabson if (lf->lf_end == OFF_MAX) 1958c675522fSDoug Rabson ldesc->fl.l_len = 0; 1959c675522fSDoug Rabson else 1960c675522fSDoug Rabson ldesc->fl.l_len = 1961c675522fSDoug Rabson lf->lf_end - lf->lf_start + 1; 1962c675522fSDoug Rabson ldesc->fl.l_whence = SEEK_SET; 1963c675522fSDoug Rabson ldesc->fl.l_type = F_UNLCK; 1964c675522fSDoug Rabson ldesc->fl.l_pid = lf->lf_owner->lo_pid; 1965c675522fSDoug Rabson ldesc->fl.l_sysid = lf->lf_owner->lo_sysid; 1966c675522fSDoug Rabson STAILQ_INSERT_TAIL(&locks, ldesc, link); 1967c675522fSDoug Rabson } 1968c675522fSDoug Rabson sx_xunlock(&ls->ls_lock); 196928fe6a3fSKonstantin Belousov VI_LOCK(vp); 1970d363fa41SMateusz Guzik MPASS(ls->ls_threads > 0); 197128fe6a3fSKonstantin Belousov ls->ls_threads--; 197228fe6a3fSKonstantin Belousov wakeup(ls); 197328fe6a3fSKonstantin Belousov VI_UNLOCK(vp); 1974c675522fSDoug Rabson 1975c675522fSDoug Rabson /* 1976c675522fSDoug Rabson * Call the iterator function for each lock in turn. If the 1977c675522fSDoug Rabson * iterator returns an error code, just free the rest of the 1978c675522fSDoug Rabson * lockdesc structures. 1979c675522fSDoug Rabson */ 1980c675522fSDoug Rabson error = 0; 1981c675522fSDoug Rabson while ((ldesc = STAILQ_FIRST(&locks)) != NULL) { 1982c675522fSDoug Rabson STAILQ_REMOVE_HEAD(&locks, link); 1983c675522fSDoug Rabson if (!error) 1984c675522fSDoug Rabson error = fn(ldesc->vp, &ldesc->fl, arg); 1985c675522fSDoug Rabson vrele(ldesc->vp); 1986c675522fSDoug Rabson free(ldesc, M_LOCKF); 1987c675522fSDoug Rabson } 1988c675522fSDoug Rabson 1989c675522fSDoug Rabson return (error); 1990c675522fSDoug Rabson } 1991c675522fSDoug Rabson 1992c675522fSDoug Rabson static int 1993c675522fSDoug Rabson lf_clearremotesys_iterator(struct vnode *vp, struct flock *fl, void *arg) 1994c675522fSDoug Rabson { 1995c675522fSDoug Rabson 1996c675522fSDoug Rabson VOP_ADVLOCK(vp, 0, F_UNLCK, fl, F_REMOTE); 1997c675522fSDoug Rabson return (0); 1998c675522fSDoug Rabson } 1999c675522fSDoug Rabson 2000c675522fSDoug Rabson void 2001c675522fSDoug Rabson lf_clearremotesys(int sysid) 2002c675522fSDoug Rabson { 2003c675522fSDoug Rabson 2004c675522fSDoug Rabson KASSERT(sysid != 0, ("Can't clear local locks with F_UNLCKSYS")); 2005c675522fSDoug Rabson lf_iteratelocks_sysid(sysid, lf_clearremotesys_iterator, NULL); 2006dfdcada3SDoug Rabson } 2007dfdcada3SDoug Rabson 2008dfdcada3SDoug Rabson int 2009dfdcada3SDoug Rabson lf_countlocks(int sysid) 2010dfdcada3SDoug Rabson { 2011dfdcada3SDoug Rabson int i; 2012dfdcada3SDoug Rabson struct lock_owner *lo; 2013dfdcada3SDoug Rabson int count; 2014dfdcada3SDoug Rabson 2015dfdcada3SDoug Rabson count = 0; 2016833dc05aSMateusz Guzik for (i = 0; i < LOCK_OWNER_HASH_SIZE; i++) { 2017833dc05aSMateusz Guzik sx_xlock(&lf_lock_owners[i].lock); 2018833dc05aSMateusz Guzik LIST_FOREACH(lo, &lf_lock_owners[i].list, lo_link) 2019dfdcada3SDoug Rabson if (lo->lo_sysid == sysid) 2020dfdcada3SDoug Rabson count += lo->lo_refs; 2021833dc05aSMateusz Guzik sx_xunlock(&lf_lock_owners[i].lock); 2022833dc05aSMateusz Guzik } 2023dfdcada3SDoug Rabson 2024dfdcada3SDoug Rabson return (count); 2025dfdcada3SDoug Rabson } 2026dfdcada3SDoug Rabson 2027dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 2028dfdcada3SDoug Rabson 2029dfdcada3SDoug Rabson /* 2030dfdcada3SDoug Rabson * Return non-zero if y is reachable from x using a brute force 2031dfdcada3SDoug Rabson * search. If reachable and path is non-null, return the route taken 2032dfdcada3SDoug Rabson * in path. 2033dfdcada3SDoug Rabson */ 2034dfdcada3SDoug Rabson static int 2035dfdcada3SDoug Rabson graph_reaches(struct owner_vertex *x, struct owner_vertex *y, 2036dfdcada3SDoug Rabson struct owner_vertex_list *path) 2037dfdcada3SDoug Rabson { 2038dfdcada3SDoug Rabson struct owner_edge *e; 2039dfdcada3SDoug Rabson 2040dfdcada3SDoug Rabson if (x == y) { 2041dfdcada3SDoug Rabson if (path) 2042dfdcada3SDoug Rabson TAILQ_INSERT_HEAD(path, x, v_link); 2043dfdcada3SDoug Rabson return 1; 2044dfdcada3SDoug Rabson } 2045dfdcada3SDoug Rabson 2046dfdcada3SDoug Rabson LIST_FOREACH(e, &x->v_outedges, e_outlink) { 2047dfdcada3SDoug Rabson if (graph_reaches(e->e_to, y, path)) { 2048dfdcada3SDoug Rabson if (path) 2049dfdcada3SDoug Rabson TAILQ_INSERT_HEAD(path, x, v_link); 2050dfdcada3SDoug Rabson return 1; 2051dfdcada3SDoug Rabson } 2052dfdcada3SDoug Rabson } 2053dfdcada3SDoug Rabson return 0; 205492dc7331SDavid Greenman } 205592dc7331SDavid Greenman 205692dc7331SDavid Greenman /* 2057dfdcada3SDoug Rabson * Perform consistency checks on the graph. Make sure the values of 2058dfdcada3SDoug Rabson * v_order are correct. If checkorder is non-zero, check no vertex can 2059dfdcada3SDoug Rabson * reach any other vertex with a smaller order. 206092dc7331SDavid Greenman */ 206187b6de2bSPoul-Henning Kamp static void 2062dfdcada3SDoug Rabson graph_check(struct owner_graph *g, int checkorder) 206392dc7331SDavid Greenman { 2064dfdcada3SDoug Rabson int i, j; 206592dc7331SDavid Greenman 2066dfdcada3SDoug Rabson for (i = 0; i < g->g_size; i++) { 2067dfdcada3SDoug Rabson if (!g->g_vertices[i]->v_owner) 2068dfdcada3SDoug Rabson continue; 2069dfdcada3SDoug Rabson KASSERT(g->g_vertices[i]->v_order == i, 2070dfdcada3SDoug Rabson ("lock graph vertices disordered")); 2071dfdcada3SDoug Rabson if (checkorder) { 2072dfdcada3SDoug Rabson for (j = 0; j < i; j++) { 2073dfdcada3SDoug Rabson if (!g->g_vertices[j]->v_owner) 2074dfdcada3SDoug Rabson continue; 2075dfdcada3SDoug Rabson KASSERT(!graph_reaches(g->g_vertices[i], 2076dfdcada3SDoug Rabson g->g_vertices[j], NULL), 2077dfdcada3SDoug Rabson ("lock graph vertices disordered")); 2078dfdcada3SDoug Rabson } 2079dfdcada3SDoug Rabson } 2080dfdcada3SDoug Rabson } 2081dfdcada3SDoug Rabson } 2082dfdcada3SDoug Rabson 2083dfdcada3SDoug Rabson static void 2084dfdcada3SDoug Rabson graph_print_vertices(struct owner_vertex_list *set) 2085dfdcada3SDoug Rabson { 2086dfdcada3SDoug Rabson struct owner_vertex *v; 2087dfdcada3SDoug Rabson 2088dfdcada3SDoug Rabson printf("{ "); 2089dfdcada3SDoug Rabson TAILQ_FOREACH(v, set, v_link) { 2090dfdcada3SDoug Rabson printf("%d:", v->v_order); 2091dfdcada3SDoug Rabson lf_print_owner(v->v_owner); 2092dfdcada3SDoug Rabson if (TAILQ_NEXT(v, v_link)) 2093dfdcada3SDoug Rabson printf(", "); 2094dfdcada3SDoug Rabson } 2095dfdcada3SDoug Rabson printf(" }\n"); 2096dfdcada3SDoug Rabson } 2097dfdcada3SDoug Rabson 2098dfdcada3SDoug Rabson #endif 2099dfdcada3SDoug Rabson 2100dfdcada3SDoug Rabson /* 2101dfdcada3SDoug Rabson * Calculate the sub-set of vertices v from the affected region [y..x] 2102dfdcada3SDoug Rabson * where v is reachable from y. Return -1 if a loop was detected 2103dfdcada3SDoug Rabson * (i.e. x is reachable from y, otherwise the number of vertices in 2104dfdcada3SDoug Rabson * this subset. 2105dfdcada3SDoug Rabson */ 2106dfdcada3SDoug Rabson static int 2107dfdcada3SDoug Rabson graph_delta_forward(struct owner_graph *g, struct owner_vertex *x, 2108dfdcada3SDoug Rabson struct owner_vertex *y, struct owner_vertex_list *delta) 2109dfdcada3SDoug Rabson { 2110dfdcada3SDoug Rabson uint32_t gen; 2111dfdcada3SDoug Rabson struct owner_vertex *v; 2112dfdcada3SDoug Rabson struct owner_edge *e; 2113dfdcada3SDoug Rabson int n; 2114dfdcada3SDoug Rabson 2115dfdcada3SDoug Rabson /* 2116dfdcada3SDoug Rabson * We start with a set containing just y. Then for each vertex 2117dfdcada3SDoug Rabson * v in the set so far unprocessed, we add each vertex that v 2118dfdcada3SDoug Rabson * has an out-edge to and that is within the affected region 2119dfdcada3SDoug Rabson * [y..x]. If we see the vertex x on our travels, stop 2120dfdcada3SDoug Rabson * immediately. 2121dfdcada3SDoug Rabson */ 2122dfdcada3SDoug Rabson TAILQ_INIT(delta); 2123dfdcada3SDoug Rabson TAILQ_INSERT_TAIL(delta, y, v_link); 2124dfdcada3SDoug Rabson v = y; 2125dfdcada3SDoug Rabson n = 1; 2126dfdcada3SDoug Rabson gen = g->g_gen; 2127dfdcada3SDoug Rabson while (v) { 2128dfdcada3SDoug Rabson LIST_FOREACH(e, &v->v_outedges, e_outlink) { 2129dfdcada3SDoug Rabson if (e->e_to == x) 2130dfdcada3SDoug Rabson return -1; 2131dfdcada3SDoug Rabson if (e->e_to->v_order < x->v_order 2132dfdcada3SDoug Rabson && e->e_to->v_gen != gen) { 2133dfdcada3SDoug Rabson e->e_to->v_gen = gen; 2134dfdcada3SDoug Rabson TAILQ_INSERT_TAIL(delta, e->e_to, v_link); 2135dfdcada3SDoug Rabson n++; 2136dfdcada3SDoug Rabson } 2137dfdcada3SDoug Rabson } 2138dfdcada3SDoug Rabson v = TAILQ_NEXT(v, v_link); 2139dfdcada3SDoug Rabson } 2140dfdcada3SDoug Rabson 2141dfdcada3SDoug Rabson return (n); 2142dfdcada3SDoug Rabson } 2143dfdcada3SDoug Rabson 2144dfdcada3SDoug Rabson /* 2145dfdcada3SDoug Rabson * Calculate the sub-set of vertices v from the affected region [y..x] 2146dfdcada3SDoug Rabson * where v reaches x. Return the number of vertices in this subset. 2147dfdcada3SDoug Rabson */ 2148dfdcada3SDoug Rabson static int 2149dfdcada3SDoug Rabson graph_delta_backward(struct owner_graph *g, struct owner_vertex *x, 2150dfdcada3SDoug Rabson struct owner_vertex *y, struct owner_vertex_list *delta) 2151dfdcada3SDoug Rabson { 2152dfdcada3SDoug Rabson uint32_t gen; 2153dfdcada3SDoug Rabson struct owner_vertex *v; 2154dfdcada3SDoug Rabson struct owner_edge *e; 2155dfdcada3SDoug Rabson int n; 2156dfdcada3SDoug Rabson 2157dfdcada3SDoug Rabson /* 2158dfdcada3SDoug Rabson * We start with a set containing just x. Then for each vertex 2159dfdcada3SDoug Rabson * v in the set so far unprocessed, we add each vertex that v 2160dfdcada3SDoug Rabson * has an in-edge from and that is within the affected region 2161dfdcada3SDoug Rabson * [y..x]. 2162dfdcada3SDoug Rabson */ 2163dfdcada3SDoug Rabson TAILQ_INIT(delta); 2164dfdcada3SDoug Rabson TAILQ_INSERT_TAIL(delta, x, v_link); 2165dfdcada3SDoug Rabson v = x; 2166dfdcada3SDoug Rabson n = 1; 2167dfdcada3SDoug Rabson gen = g->g_gen; 2168dfdcada3SDoug Rabson while (v) { 2169dfdcada3SDoug Rabson LIST_FOREACH(e, &v->v_inedges, e_inlink) { 2170dfdcada3SDoug Rabson if (e->e_from->v_order > y->v_order 2171dfdcada3SDoug Rabson && e->e_from->v_gen != gen) { 2172dfdcada3SDoug Rabson e->e_from->v_gen = gen; 2173dfdcada3SDoug Rabson TAILQ_INSERT_HEAD(delta, e->e_from, v_link); 2174dfdcada3SDoug Rabson n++; 2175dfdcada3SDoug Rabson } 2176dfdcada3SDoug Rabson } 2177dfdcada3SDoug Rabson v = TAILQ_PREV(v, owner_vertex_list, v_link); 2178dfdcada3SDoug Rabson } 2179dfdcada3SDoug Rabson 2180dfdcada3SDoug Rabson return (n); 2181dfdcada3SDoug Rabson } 2182dfdcada3SDoug Rabson 2183dfdcada3SDoug Rabson static int 2184dfdcada3SDoug Rabson graph_add_indices(int *indices, int n, struct owner_vertex_list *set) 2185dfdcada3SDoug Rabson { 2186dfdcada3SDoug Rabson struct owner_vertex *v; 2187dfdcada3SDoug Rabson int i, j; 2188dfdcada3SDoug Rabson 2189dfdcada3SDoug Rabson TAILQ_FOREACH(v, set, v_link) { 2190dfdcada3SDoug Rabson for (i = n; 2191dfdcada3SDoug Rabson i > 0 && indices[i - 1] > v->v_order; i--) 2192dfdcada3SDoug Rabson ; 2193dfdcada3SDoug Rabson for (j = n - 1; j >= i; j--) 2194dfdcada3SDoug Rabson indices[j + 1] = indices[j]; 2195dfdcada3SDoug Rabson indices[i] = v->v_order; 2196dfdcada3SDoug Rabson n++; 2197dfdcada3SDoug Rabson } 2198dfdcada3SDoug Rabson 2199dfdcada3SDoug Rabson return (n); 2200dfdcada3SDoug Rabson } 2201dfdcada3SDoug Rabson 2202dfdcada3SDoug Rabson static int 2203dfdcada3SDoug Rabson graph_assign_indices(struct owner_graph *g, int *indices, int nextunused, 2204dfdcada3SDoug Rabson struct owner_vertex_list *set) 2205dfdcada3SDoug Rabson { 2206dfdcada3SDoug Rabson struct owner_vertex *v, *vlowest; 2207dfdcada3SDoug Rabson 2208dfdcada3SDoug Rabson while (!TAILQ_EMPTY(set)) { 2209dfdcada3SDoug Rabson vlowest = NULL; 2210dfdcada3SDoug Rabson TAILQ_FOREACH(v, set, v_link) { 2211dfdcada3SDoug Rabson if (!vlowest || v->v_order < vlowest->v_order) 2212dfdcada3SDoug Rabson vlowest = v; 2213dfdcada3SDoug Rabson } 2214dfdcada3SDoug Rabson TAILQ_REMOVE(set, vlowest, v_link); 2215dfdcada3SDoug Rabson vlowest->v_order = indices[nextunused]; 2216dfdcada3SDoug Rabson g->g_vertices[vlowest->v_order] = vlowest; 2217dfdcada3SDoug Rabson nextunused++; 2218dfdcada3SDoug Rabson } 2219dfdcada3SDoug Rabson 2220dfdcada3SDoug Rabson return (nextunused); 2221dfdcada3SDoug Rabson } 2222dfdcada3SDoug Rabson 2223dfdcada3SDoug Rabson static int 2224dfdcada3SDoug Rabson graph_add_edge(struct owner_graph *g, struct owner_vertex *x, 2225dfdcada3SDoug Rabson struct owner_vertex *y) 2226dfdcada3SDoug Rabson { 2227dfdcada3SDoug Rabson struct owner_edge *e; 2228dfdcada3SDoug Rabson struct owner_vertex_list deltaF, deltaB; 2229788390dfSMatt Macy int nF, n, vi, i; 2230dfdcada3SDoug Rabson int *indices; 2231788390dfSMatt Macy int nB __unused; 2232dfdcada3SDoug Rabson 2233dfdcada3SDoug Rabson sx_assert(&lf_owner_graph_lock, SX_XLOCKED); 2234dfdcada3SDoug Rabson 2235dfdcada3SDoug Rabson LIST_FOREACH(e, &x->v_outedges, e_outlink) { 2236dfdcada3SDoug Rabson if (e->e_to == y) { 2237dfdcada3SDoug Rabson e->e_refs++; 2238dfdcada3SDoug Rabson return (0); 223992dc7331SDavid Greenman } 224092dc7331SDavid Greenman } 224192dc7331SDavid Greenman 224292dc7331SDavid Greenman #ifdef LOCKF_DEBUG 2243dfdcada3SDoug Rabson if (lockf_debug & 8) { 2244dfdcada3SDoug Rabson printf("adding edge %d:", x->v_order); 2245dfdcada3SDoug Rabson lf_print_owner(x->v_owner); 2246dfdcada3SDoug Rabson printf(" -> %d:", y->v_order); 2247dfdcada3SDoug Rabson lf_print_owner(y->v_owner); 2248dfdcada3SDoug Rabson printf("\n"); 2249dfdcada3SDoug Rabson } 2250dfdcada3SDoug Rabson #endif 2251dfdcada3SDoug Rabson if (y->v_order < x->v_order) { 2252dfdcada3SDoug Rabson /* 2253dfdcada3SDoug Rabson * The new edge violates the order. First find the set 2254dfdcada3SDoug Rabson * of affected vertices reachable from y (deltaF) and 2255dfdcada3SDoug Rabson * the set of affect vertices affected that reach x 2256dfdcada3SDoug Rabson * (deltaB), using the graph generation number to 2257dfdcada3SDoug Rabson * detect whether we have visited a given vertex 2258dfdcada3SDoug Rabson * already. We re-order the graph so that each vertex 2259dfdcada3SDoug Rabson * in deltaB appears before each vertex in deltaF. 2260dfdcada3SDoug Rabson * 2261dfdcada3SDoug Rabson * If x is a member of deltaF, then the new edge would 2262dfdcada3SDoug Rabson * create a cycle. Otherwise, we may assume that 2263dfdcada3SDoug Rabson * deltaF and deltaB are disjoint. 2264dfdcada3SDoug Rabson */ 2265dfdcada3SDoug Rabson g->g_gen++; 2266dfdcada3SDoug Rabson if (g->g_gen == 0) { 2267dfdcada3SDoug Rabson /* 2268dfdcada3SDoug Rabson * Generation wrap. 2269dfdcada3SDoug Rabson */ 2270dfdcada3SDoug Rabson for (vi = 0; vi < g->g_size; vi++) { 2271dfdcada3SDoug Rabson g->g_vertices[vi]->v_gen = 0; 2272dfdcada3SDoug Rabson } 2273dfdcada3SDoug Rabson g->g_gen++; 2274dfdcada3SDoug Rabson } 2275dfdcada3SDoug Rabson nF = graph_delta_forward(g, x, y, &deltaF); 2276dfdcada3SDoug Rabson if (nF < 0) { 2277dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 2278dfdcada3SDoug Rabson if (lockf_debug & 8) { 2279dfdcada3SDoug Rabson struct owner_vertex_list path; 2280dfdcada3SDoug Rabson printf("deadlock: "); 2281dfdcada3SDoug Rabson TAILQ_INIT(&path); 2282dfdcada3SDoug Rabson graph_reaches(y, x, &path); 2283dfdcada3SDoug Rabson graph_print_vertices(&path); 2284dfdcada3SDoug Rabson } 2285dfdcada3SDoug Rabson #endif 2286dfdcada3SDoug Rabson return (EDEADLK); 2287dfdcada3SDoug Rabson } 2288dfdcada3SDoug Rabson 2289dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 2290dfdcada3SDoug Rabson if (lockf_debug & 8) { 2291dfdcada3SDoug Rabson printf("re-ordering graph vertices\n"); 2292dfdcada3SDoug Rabson printf("deltaF = "); 2293dfdcada3SDoug Rabson graph_print_vertices(&deltaF); 2294dfdcada3SDoug Rabson } 2295dfdcada3SDoug Rabson #endif 2296dfdcada3SDoug Rabson 2297dfdcada3SDoug Rabson nB = graph_delta_backward(g, x, y, &deltaB); 2298dfdcada3SDoug Rabson 2299dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 2300dfdcada3SDoug Rabson if (lockf_debug & 8) { 2301dfdcada3SDoug Rabson printf("deltaB = "); 2302dfdcada3SDoug Rabson graph_print_vertices(&deltaB); 2303dfdcada3SDoug Rabson } 2304dfdcada3SDoug Rabson #endif 2305dfdcada3SDoug Rabson 2306dfdcada3SDoug Rabson /* 2307dfdcada3SDoug Rabson * We first build a set of vertex indices (vertex 2308dfdcada3SDoug Rabson * order values) that we may use, then we re-assign 2309dfdcada3SDoug Rabson * orders first to those vertices in deltaB, then to 2310dfdcada3SDoug Rabson * deltaF. Note that the contents of deltaF and deltaB 2311dfdcada3SDoug Rabson * may be partially disordered - we perform an 2312dfdcada3SDoug Rabson * insertion sort while building our index set. 2313dfdcada3SDoug Rabson */ 2314dfdcada3SDoug Rabson indices = g->g_indexbuf; 2315dfdcada3SDoug Rabson n = graph_add_indices(indices, 0, &deltaF); 2316dfdcada3SDoug Rabson graph_add_indices(indices, n, &deltaB); 2317dfdcada3SDoug Rabson 2318dfdcada3SDoug Rabson /* 2319dfdcada3SDoug Rabson * We must also be sure to maintain the relative 2320dfdcada3SDoug Rabson * ordering of deltaF and deltaB when re-assigning 2321dfdcada3SDoug Rabson * vertices. We do this by iteratively removing the 2322dfdcada3SDoug Rabson * lowest ordered element from the set and assigning 2323dfdcada3SDoug Rabson * it the next value from our new ordering. 2324dfdcada3SDoug Rabson */ 2325dfdcada3SDoug Rabson i = graph_assign_indices(g, indices, 0, &deltaB); 2326dfdcada3SDoug Rabson graph_assign_indices(g, indices, i, &deltaF); 2327dfdcada3SDoug Rabson 2328dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 2329dfdcada3SDoug Rabson if (lockf_debug & 8) { 2330dfdcada3SDoug Rabson struct owner_vertex_list set; 2331dfdcada3SDoug Rabson TAILQ_INIT(&set); 2332dfdcada3SDoug Rabson for (i = 0; i < nB + nF; i++) 2333dfdcada3SDoug Rabson TAILQ_INSERT_TAIL(&set, 2334dfdcada3SDoug Rabson g->g_vertices[indices[i]], v_link); 2335dfdcada3SDoug Rabson printf("new ordering = "); 2336dfdcada3SDoug Rabson graph_print_vertices(&set); 2337dfdcada3SDoug Rabson } 2338dfdcada3SDoug Rabson #endif 2339dfdcada3SDoug Rabson } 2340dfdcada3SDoug Rabson 2341dfdcada3SDoug Rabson KASSERT(x->v_order < y->v_order, ("Failed to re-order graph")); 2342dfdcada3SDoug Rabson 2343dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 2344dfdcada3SDoug Rabson if (lockf_debug & 8) { 2345dfdcada3SDoug Rabson graph_check(g, TRUE); 2346dfdcada3SDoug Rabson } 2347dfdcada3SDoug Rabson #endif 2348dfdcada3SDoug Rabson 2349dfdcada3SDoug Rabson e = malloc(sizeof(struct owner_edge), M_LOCKF, M_WAITOK); 2350dfdcada3SDoug Rabson 2351dfdcada3SDoug Rabson LIST_INSERT_HEAD(&x->v_outedges, e, e_outlink); 2352dfdcada3SDoug Rabson LIST_INSERT_HEAD(&y->v_inedges, e, e_inlink); 2353dfdcada3SDoug Rabson e->e_refs = 1; 2354dfdcada3SDoug Rabson e->e_from = x; 2355dfdcada3SDoug Rabson e->e_to = y; 2356dfdcada3SDoug Rabson 2357dfdcada3SDoug Rabson return (0); 2358dfdcada3SDoug Rabson } 2359dfdcada3SDoug Rabson 2360dfdcada3SDoug Rabson /* 2361dfdcada3SDoug Rabson * Remove an edge x->y from the graph. 2362dfdcada3SDoug Rabson */ 2363dfdcada3SDoug Rabson static void 2364dfdcada3SDoug Rabson graph_remove_edge(struct owner_graph *g, struct owner_vertex *x, 2365dfdcada3SDoug Rabson struct owner_vertex *y) 2366dfdcada3SDoug Rabson { 2367dfdcada3SDoug Rabson struct owner_edge *e; 2368dfdcada3SDoug Rabson 2369dfdcada3SDoug Rabson sx_assert(&lf_owner_graph_lock, SX_XLOCKED); 2370dfdcada3SDoug Rabson 2371dfdcada3SDoug Rabson LIST_FOREACH(e, &x->v_outedges, e_outlink) { 2372dfdcada3SDoug Rabson if (e->e_to == y) 2373dfdcada3SDoug Rabson break; 2374dfdcada3SDoug Rabson } 2375dfdcada3SDoug Rabson KASSERT(e, ("Removing non-existent edge from deadlock graph")); 2376dfdcada3SDoug Rabson 2377dfdcada3SDoug Rabson e->e_refs--; 2378dfdcada3SDoug Rabson if (e->e_refs == 0) { 2379dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 2380dfdcada3SDoug Rabson if (lockf_debug & 8) { 2381dfdcada3SDoug Rabson printf("removing edge %d:", x->v_order); 2382dfdcada3SDoug Rabson lf_print_owner(x->v_owner); 2383dfdcada3SDoug Rabson printf(" -> %d:", y->v_order); 2384dfdcada3SDoug Rabson lf_print_owner(y->v_owner); 2385dfdcada3SDoug Rabson printf("\n"); 2386dfdcada3SDoug Rabson } 2387dfdcada3SDoug Rabson #endif 2388dfdcada3SDoug Rabson LIST_REMOVE(e, e_outlink); 2389dfdcada3SDoug Rabson LIST_REMOVE(e, e_inlink); 2390dfdcada3SDoug Rabson free(e, M_LOCKF); 2391dfdcada3SDoug Rabson } 2392dfdcada3SDoug Rabson } 2393dfdcada3SDoug Rabson 2394dfdcada3SDoug Rabson /* 2395dfdcada3SDoug Rabson * Allocate a vertex from the free list. Return ENOMEM if there are 2396dfdcada3SDoug Rabson * none. 2397dfdcada3SDoug Rabson */ 2398dfdcada3SDoug Rabson static struct owner_vertex * 2399dfdcada3SDoug Rabson graph_alloc_vertex(struct owner_graph *g, struct lock_owner *lo) 2400dfdcada3SDoug Rabson { 2401dfdcada3SDoug Rabson struct owner_vertex *v; 2402dfdcada3SDoug Rabson 2403dfdcada3SDoug Rabson sx_assert(&lf_owner_graph_lock, SX_XLOCKED); 2404dfdcada3SDoug Rabson 2405dfdcada3SDoug Rabson v = malloc(sizeof(struct owner_vertex), M_LOCKF, M_WAITOK); 2406dfdcada3SDoug Rabson if (g->g_size == g->g_space) { 2407dfdcada3SDoug Rabson g->g_vertices = realloc(g->g_vertices, 2408dfdcada3SDoug Rabson 2 * g->g_space * sizeof(struct owner_vertex *), 2409dfdcada3SDoug Rabson M_LOCKF, M_WAITOK); 2410dfdcada3SDoug Rabson free(g->g_indexbuf, M_LOCKF); 2411dfdcada3SDoug Rabson g->g_indexbuf = malloc(2 * g->g_space * sizeof(int), 2412dfdcada3SDoug Rabson M_LOCKF, M_WAITOK); 2413dfdcada3SDoug Rabson g->g_space = 2 * g->g_space; 2414dfdcada3SDoug Rabson } 2415dfdcada3SDoug Rabson v->v_order = g->g_size; 2416dfdcada3SDoug Rabson v->v_gen = g->g_gen; 2417dfdcada3SDoug Rabson g->g_vertices[g->g_size] = v; 2418dfdcada3SDoug Rabson g->g_size++; 2419dfdcada3SDoug Rabson 2420dfdcada3SDoug Rabson LIST_INIT(&v->v_outedges); 2421dfdcada3SDoug Rabson LIST_INIT(&v->v_inedges); 2422dfdcada3SDoug Rabson v->v_owner = lo; 2423dfdcada3SDoug Rabson 2424dfdcada3SDoug Rabson return (v); 2425dfdcada3SDoug Rabson } 2426dfdcada3SDoug Rabson 2427dfdcada3SDoug Rabson static void 2428dfdcada3SDoug Rabson graph_free_vertex(struct owner_graph *g, struct owner_vertex *v) 2429dfdcada3SDoug Rabson { 2430dfdcada3SDoug Rabson struct owner_vertex *w; 2431dfdcada3SDoug Rabson int i; 2432dfdcada3SDoug Rabson 2433dfdcada3SDoug Rabson sx_assert(&lf_owner_graph_lock, SX_XLOCKED); 2434dfdcada3SDoug Rabson 2435dfdcada3SDoug Rabson KASSERT(LIST_EMPTY(&v->v_outedges), ("Freeing vertex with edges")); 2436dfdcada3SDoug Rabson KASSERT(LIST_EMPTY(&v->v_inedges), ("Freeing vertex with edges")); 2437dfdcada3SDoug Rabson 2438dfdcada3SDoug Rabson /* 2439dfdcada3SDoug Rabson * Remove from the graph's array and close up the gap, 2440dfdcada3SDoug Rabson * renumbering the other vertices. 2441dfdcada3SDoug Rabson */ 2442dfdcada3SDoug Rabson for (i = v->v_order + 1; i < g->g_size; i++) { 2443dfdcada3SDoug Rabson w = g->g_vertices[i]; 2444dfdcada3SDoug Rabson w->v_order--; 2445dfdcada3SDoug Rabson g->g_vertices[i - 1] = w; 2446dfdcada3SDoug Rabson } 2447dfdcada3SDoug Rabson g->g_size--; 2448dfdcada3SDoug Rabson 2449dfdcada3SDoug Rabson free(v, M_LOCKF); 2450dfdcada3SDoug Rabson } 2451dfdcada3SDoug Rabson 2452dfdcada3SDoug Rabson static struct owner_graph * 2453dfdcada3SDoug Rabson graph_init(struct owner_graph *g) 2454dfdcada3SDoug Rabson { 2455dfdcada3SDoug Rabson 2456dfdcada3SDoug Rabson g->g_vertices = malloc(10 * sizeof(struct owner_vertex *), 2457dfdcada3SDoug Rabson M_LOCKF, M_WAITOK); 2458dfdcada3SDoug Rabson g->g_size = 0; 2459dfdcada3SDoug Rabson g->g_space = 10; 2460dfdcada3SDoug Rabson g->g_indexbuf = malloc(g->g_space * sizeof(int), M_LOCKF, M_WAITOK); 2461dfdcada3SDoug Rabson g->g_gen = 0; 2462dfdcada3SDoug Rabson 2463dfdcada3SDoug Rabson return (g); 2464dfdcada3SDoug Rabson } 2465dfdcada3SDoug Rabson 2466eca39864SKonstantin Belousov struct kinfo_lockf_linked { 2467eca39864SKonstantin Belousov struct kinfo_lockf kl; 2468eca39864SKonstantin Belousov struct vnode *vp; 2469eca39864SKonstantin Belousov STAILQ_ENTRY(kinfo_lockf_linked) link; 2470eca39864SKonstantin Belousov }; 2471eca39864SKonstantin Belousov 2472eca39864SKonstantin Belousov int 2473eca39864SKonstantin Belousov vfs_report_lockf(struct mount *mp, struct sbuf *sb) 2474eca39864SKonstantin Belousov { 2475eca39864SKonstantin Belousov struct lockf *ls; 2476eca39864SKonstantin Belousov struct lockf_entry *lf; 2477eca39864SKonstantin Belousov struct kinfo_lockf_linked *klf; 2478eca39864SKonstantin Belousov struct vnode *vp; 2479eca39864SKonstantin Belousov struct ucred *ucred; 2480eca39864SKonstantin Belousov char *fullpath, *freepath; 2481eca39864SKonstantin Belousov struct stat stt; 2482eca39864SKonstantin Belousov STAILQ_HEAD(, kinfo_lockf_linked) locks; 2483eca39864SKonstantin Belousov int error, gerror; 2484eca39864SKonstantin Belousov 2485eca39864SKonstantin Belousov STAILQ_INIT(&locks); 2486eca39864SKonstantin Belousov sx_slock(&lf_lock_states_lock); 2487eca39864SKonstantin Belousov LIST_FOREACH(ls, &lf_lock_states, ls_link) { 2488eca39864SKonstantin Belousov sx_slock(&ls->ls_lock); 2489eca39864SKonstantin Belousov LIST_FOREACH(lf, &ls->ls_active, lf_link) { 2490eca39864SKonstantin Belousov vp = lf->lf_vnode; 2491eca39864SKonstantin Belousov if (VN_IS_DOOMED(vp) || vp->v_mount != mp) 2492eca39864SKonstantin Belousov continue; 2493eca39864SKonstantin Belousov vhold(vp); 2494eca39864SKonstantin Belousov klf = malloc(sizeof(struct kinfo_lockf_linked), 2495eca39864SKonstantin Belousov M_LOCKF, M_WAITOK | M_ZERO); 2496eca39864SKonstantin Belousov klf->vp = vp; 2497eca39864SKonstantin Belousov klf->kl.kl_structsize = sizeof(struct kinfo_lockf); 2498eca39864SKonstantin Belousov klf->kl.kl_start = lf->lf_start; 2499eca39864SKonstantin Belousov klf->kl.kl_len = lf->lf_end == OFF_MAX ? 0 : 2500eca39864SKonstantin Belousov lf->lf_end - lf->lf_start + 1; 2501eca39864SKonstantin Belousov klf->kl.kl_rw = lf->lf_type == F_RDLCK ? 2502eca39864SKonstantin Belousov KLOCKF_RW_READ : KLOCKF_RW_WRITE; 2503eca39864SKonstantin Belousov if (lf->lf_owner->lo_sysid != 0) { 2504eca39864SKonstantin Belousov klf->kl.kl_pid = lf->lf_owner->lo_pid; 2505eca39864SKonstantin Belousov klf->kl.kl_sysid = lf->lf_owner->lo_sysid; 2506eca39864SKonstantin Belousov klf->kl.kl_type = KLOCKF_TYPE_REMOTE; 2507eca39864SKonstantin Belousov } else if (lf->lf_owner->lo_pid == -1) { 2508eca39864SKonstantin Belousov klf->kl.kl_pid = -1; 2509eca39864SKonstantin Belousov klf->kl.kl_sysid = 0; 2510eca39864SKonstantin Belousov klf->kl.kl_type = KLOCKF_TYPE_FLOCK; 2511eca39864SKonstantin Belousov } else { 2512eca39864SKonstantin Belousov klf->kl.kl_pid = lf->lf_owner->lo_pid; 2513eca39864SKonstantin Belousov klf->kl.kl_sysid = 0; 2514eca39864SKonstantin Belousov klf->kl.kl_type = KLOCKF_TYPE_PID; 2515eca39864SKonstantin Belousov } 2516eca39864SKonstantin Belousov STAILQ_INSERT_TAIL(&locks, klf, link); 2517eca39864SKonstantin Belousov } 2518eca39864SKonstantin Belousov sx_sunlock(&ls->ls_lock); 2519eca39864SKonstantin Belousov } 2520eca39864SKonstantin Belousov sx_sunlock(&lf_lock_states_lock); 2521eca39864SKonstantin Belousov 2522eca39864SKonstantin Belousov gerror = 0; 2523eca39864SKonstantin Belousov ucred = curthread->td_ucred; 2524eca39864SKonstantin Belousov while ((klf = STAILQ_FIRST(&locks)) != NULL) { 2525eca39864SKonstantin Belousov STAILQ_REMOVE_HEAD(&locks, link); 2526eca39864SKonstantin Belousov vp = klf->vp; 2527eca39864SKonstantin Belousov if (gerror == 0 && vn_lock(vp, LK_SHARED) == 0) { 2528eca39864SKonstantin Belousov error = prison_canseemount(ucred, vp->v_mount); 2529eca39864SKonstantin Belousov if (error == 0) 2530eca39864SKonstantin Belousov error = VOP_STAT(vp, &stt, ucred, NOCRED); 2531eca39864SKonstantin Belousov VOP_UNLOCK(vp); 2532eca39864SKonstantin Belousov if (error == 0) { 2533*8ae76949SDamjan Jovanovic klf->kl.kl_file_fsid = stt.st_dev; 2534eca39864SKonstantin Belousov klf->kl.kl_file_rdev = stt.st_rdev; 2535eca39864SKonstantin Belousov klf->kl.kl_file_fileid = stt.st_ino; 2536eca39864SKonstantin Belousov freepath = NULL; 2537eca39864SKonstantin Belousov fullpath = "-"; 2538eca39864SKonstantin Belousov error = vn_fullpath(vp, &fullpath, &freepath); 2539eca39864SKonstantin Belousov if (error == 0) 2540eca39864SKonstantin Belousov strlcpy(klf->kl.kl_path, fullpath, 2541eca39864SKonstantin Belousov sizeof(klf->kl.kl_path)); 2542eca39864SKonstantin Belousov free(freepath, M_TEMP); 2543eca39864SKonstantin Belousov if (sbuf_bcat(sb, &klf->kl, 2544eca39864SKonstantin Belousov klf->kl.kl_structsize) != 0) { 2545eca39864SKonstantin Belousov gerror = sbuf_error(sb); 2546eca39864SKonstantin Belousov } 2547eca39864SKonstantin Belousov } 2548eca39864SKonstantin Belousov } 2549eca39864SKonstantin Belousov vdrop(vp); 2550eca39864SKonstantin Belousov free(klf, M_LOCKF); 2551eca39864SKonstantin Belousov } 2552eca39864SKonstantin Belousov 2553eca39864SKonstantin Belousov return (gerror); 2554eca39864SKonstantin Belousov } 2555eca39864SKonstantin Belousov 2556eca39864SKonstantin Belousov static int 2557eca39864SKonstantin Belousov sysctl_kern_lockf_run(struct sbuf *sb) 2558eca39864SKonstantin Belousov { 2559eca39864SKonstantin Belousov struct mount *mp; 2560eca39864SKonstantin Belousov int error; 2561eca39864SKonstantin Belousov 2562eca39864SKonstantin Belousov error = 0; 2563eca39864SKonstantin Belousov mtx_lock(&mountlist_mtx); 2564eca39864SKonstantin Belousov TAILQ_FOREACH(mp, &mountlist, mnt_list) { 2565eca39864SKonstantin Belousov error = vfs_busy(mp, MBF_MNTLSTLOCK); 2566eca39864SKonstantin Belousov if (error != 0) 2567eca39864SKonstantin Belousov continue; 2568eca39864SKonstantin Belousov error = mp->mnt_op->vfs_report_lockf(mp, sb); 2569eca39864SKonstantin Belousov mtx_lock(&mountlist_mtx); 2570eca39864SKonstantin Belousov vfs_unbusy(mp); 2571eca39864SKonstantin Belousov if (error != 0) 2572eca39864SKonstantin Belousov break; 2573eca39864SKonstantin Belousov } 2574eca39864SKonstantin Belousov mtx_unlock(&mountlist_mtx); 2575eca39864SKonstantin Belousov return (error); 2576eca39864SKonstantin Belousov } 2577eca39864SKonstantin Belousov 2578eca39864SKonstantin Belousov static int 2579eca39864SKonstantin Belousov sysctl_kern_lockf(SYSCTL_HANDLER_ARGS) 2580eca39864SKonstantin Belousov { 2581eca39864SKonstantin Belousov struct sbuf sb; 2582eca39864SKonstantin Belousov int error, error2; 2583eca39864SKonstantin Belousov 2584eca39864SKonstantin Belousov sbuf_new_for_sysctl(&sb, NULL, sizeof(struct kinfo_lockf) * 5, req); 2585eca39864SKonstantin Belousov sbuf_clear_flags(&sb, SBUF_INCLUDENUL); 2586eca39864SKonstantin Belousov error = sysctl_kern_lockf_run(&sb); 2587eca39864SKonstantin Belousov error2 = sbuf_finish(&sb); 2588eca39864SKonstantin Belousov sbuf_delete(&sb); 2589eca39864SKonstantin Belousov return (error != 0 ? error : error2); 2590eca39864SKonstantin Belousov } 2591eca39864SKonstantin Belousov SYSCTL_PROC(_kern, KERN_LOCKF, lockf, 2592eca39864SKonstantin Belousov CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 2593eca39864SKonstantin Belousov 0, 0, sysctl_kern_lockf, "S,lockf", 2594eca39864SKonstantin Belousov "Advisory locks table"); 2595eca39864SKonstantin Belousov 2596dfdcada3SDoug Rabson #ifdef LOCKF_DEBUG 2597dfdcada3SDoug Rabson /* 2598dfdcada3SDoug Rabson * Print description of a lock owner 2599dfdcada3SDoug Rabson */ 2600dfdcada3SDoug Rabson static void 2601dfdcada3SDoug Rabson lf_print_owner(struct lock_owner *lo) 2602dfdcada3SDoug Rabson { 2603dfdcada3SDoug Rabson 2604dfdcada3SDoug Rabson if (lo->lo_flags & F_REMOTE) { 2605dfdcada3SDoug Rabson printf("remote pid %d, system %d", 2606dfdcada3SDoug Rabson lo->lo_pid, lo->lo_sysid); 2607dfdcada3SDoug Rabson } else if (lo->lo_flags & F_FLOCK) { 2608dfdcada3SDoug Rabson printf("file %p", lo->lo_id); 2609dfdcada3SDoug Rabson } else { 2610dfdcada3SDoug Rabson printf("local pid %d", lo->lo_pid); 2611dfdcada3SDoug Rabson } 2612dfdcada3SDoug Rabson } 2613dfdcada3SDoug Rabson 261492dc7331SDavid Greenman /* 261592dc7331SDavid Greenman * Print out a lock. 261692dc7331SDavid Greenman */ 2617013e6650SJeff Roberson static void 2618dfdcada3SDoug Rabson lf_print(char *tag, struct lockf_entry *lock) 261992dc7331SDavid Greenman { 262092dc7331SDavid Greenman 2621d974cf4dSBruce Evans printf("%s: lock %p for ", tag, (void *)lock); 2622dfdcada3SDoug Rabson lf_print_owner(lock->lf_owner); 262359e85819SKonstantin Belousov printf("\nvnode %p", lock->lf_vnode); 262459e85819SKonstantin Belousov VOP_PRINT(lock->lf_vnode); 2625dfdcada3SDoug Rabson printf(" %s, start %jd, end ", 262692dc7331SDavid Greenman lock->lf_type == F_RDLCK ? "shared" : 262792dc7331SDavid Greenman lock->lf_type == F_WRLCK ? "exclusive" : 2628a7a00d05SMaxime Henrion lock->lf_type == F_UNLCK ? "unlock" : "unknown", 2629dfdcada3SDoug Rabson (intmax_t)lock->lf_start); 2630dfdcada3SDoug Rabson if (lock->lf_end == OFF_MAX) 2631dfdcada3SDoug Rabson printf("EOF"); 263259aff5fcSAlfred Perlstein else 2633dfdcada3SDoug Rabson printf("%jd", (intmax_t)lock->lf_end); 2634dfdcada3SDoug Rabson if (!LIST_EMPTY(&lock->lf_outedges)) 2635dfdcada3SDoug Rabson printf(" block %p\n", 2636dfdcada3SDoug Rabson (void *)LIST_FIRST(&lock->lf_outedges)->le_to); 263792dc7331SDavid Greenman else 263892dc7331SDavid Greenman printf("\n"); 263992dc7331SDavid Greenman } 264092dc7331SDavid Greenman 2641013e6650SJeff Roberson static void 2642dfdcada3SDoug Rabson lf_printlist(char *tag, struct lockf_entry *lock) 264392dc7331SDavid Greenman { 2644dfdcada3SDoug Rabson struct lockf_entry *lf, *blk; 2645dfdcada3SDoug Rabson struct lockf_edge *e; 264692dc7331SDavid Greenman 264759e85819SKonstantin Belousov printf("%s: Lock list for vnode %p:\n", tag, lock->lf_vnode); 2648a365ea5fSDoug Rabson LIST_FOREACH(lf, &lock->lf_vnode->v_lockf->ls_active, lf_link) { 2649d974cf4dSBruce Evans printf("\tlock %p for ",(void *)lf); 2650dfdcada3SDoug Rabson lf_print_owner(lock->lf_owner); 2651a7a00d05SMaxime Henrion printf(", %s, start %jd, end %jd", 265292dc7331SDavid Greenman lf->lf_type == F_RDLCK ? "shared" : 265392dc7331SDavid Greenman lf->lf_type == F_WRLCK ? "exclusive" : 265492dc7331SDavid Greenman lf->lf_type == F_UNLCK ? "unlock" : 2655a7a00d05SMaxime Henrion "unknown", (intmax_t)lf->lf_start, (intmax_t)lf->lf_end); 2656dfdcada3SDoug Rabson LIST_FOREACH(e, &lf->lf_outedges, le_outlink) { 2657dfdcada3SDoug Rabson blk = e->le_to; 2658d974cf4dSBruce Evans printf("\n\t\tlock request %p for ", (void *)blk); 2659dfdcada3SDoug Rabson lf_print_owner(blk->lf_owner); 2660a7a00d05SMaxime Henrion printf(", %s, start %jd, end %jd", 2661996c772fSJohn Dyson blk->lf_type == F_RDLCK ? "shared" : 2662996c772fSJohn Dyson blk->lf_type == F_WRLCK ? "exclusive" : 2663996c772fSJohn Dyson blk->lf_type == F_UNLCK ? "unlock" : 2664a7a00d05SMaxime Henrion "unknown", (intmax_t)blk->lf_start, 2665a7a00d05SMaxime Henrion (intmax_t)blk->lf_end); 2666dfdcada3SDoug Rabson if (!LIST_EMPTY(&blk->lf_inedges)) 2667996c772fSJohn Dyson panic("lf_printlist: bad list"); 2668996c772fSJohn Dyson } 266992dc7331SDavid Greenman printf("\n"); 267092dc7331SDavid Greenman } 267192dc7331SDavid Greenman } 267292dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 2673