Home | History | Annotate | Download | only in server
      1 //
      2 // CDDL HEADER START
      3 //
      4 // The contents of this file are subject to the terms of the
      5 // Common Development and Distribution License (the License).
      6 // You may not use this file except in compliance with the License.
      7 //
      8 // You can obtain a copy of the license at usr/src/CDDL.txt
      9 // or http://www.opensolaris.org/os/licensing.
     10 // See the License for the specific language governing permissions
     11 // and limitations under the License.
     12 //
     13 // When distributing Covered Code, include this CDDL HEADER in each
     14 // file and include the License file at usr/src/CDDL.txt.
     15 // If applicable, add the following below this CDDL HEADER, with the
     16 // fields enclosed by brackets [] replaced with your own identifying
     17 // information: Portions Copyright [yyyy] [name of copyright owner]
     18 //
     19 // CDDL HEADER END
     20 //
     21 
     22 //
     23 // Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24 // Use is subject to license terms.
     25 //
     26 
     27 #pragma ident	"@(#)cl_flock.cc	1.8	08/05/20 SMI"
     28 
     29 #include <sys/flock_impl.h>
     30 #include <sys/flock.h>
     31 #include <sys/disp.h>
     32 
     33 #include <sys/list_def.h>
     34 
     35 #include <orb/infrastructure/clusterproc.h>
     36 
     37 #include "../version.h"
     38 #include PXFS_IDL(pxfs)
     39 #include <pxfs/lib/pxfs_debug.h>
     40 #include <pxfs/server/cl_flock.h>
     41 #include <pxfs/server/fobj_impl.h>
     42 #include <pxfs/server/frange_lock.h>
     43 
     44 //lint -e1512
     45 //
     46 // Warning(1512) destructor for base class is not virtual -- In a
     47 // final pass through all the classes, we have found a class that is
     48 // the base class of a derivation and has a destructor but the
     49 // destructor is not virtual. It is conventional for inherited classes
     50 // to have virtual destructors so that is it safe to 'delete' a
     51 // pointer to a base class.
     52 //
     53 
     54 static void cl_flk_handle_waking_locks(void *);
     55 static void cl_flk_state_notify_lock_woken(lock_descriptor_t *);
     56 static fobj_ii *get_fobj_ii(lock_descriptor_t *);
     57 
     58 typedef SList<lock_descriptor_t> locks_list;
     59 
     60 //
     61 // This list stores the previously blocked lock requests that have now been
     62 // granted and await the client being notified.  After this notification is
     63 // delivered, the lock is pushed to the processed_list
     64 //
     65 static locks_list granted_list;
     66 
     67 // Protects the 'granted_list'
     68 static os::mutex_t granted_list_lock;
     69 
     70 //
     71 // The locking order is: graph_lock, granted_list_lock, processed_list_lock
     72 //
     73 
     74 //
     75 // The thread that delivers client notifications sleeps on this cv. Whenever
     76 // a lock is added to the 'granted_list', this cv is prodded
     77 //
     78 static os::condvar_t sleep_cond;
     79 
     80 //
     81 // This procedure is run by a separate thread, and processes all the
     82 // locks that come in the 'granted_list'.  Processing a lock consists of
     83 // notifying its client that it has been woken up, and placing it on the
     84 // 'processed_list'.  When the 'granted_list' is empty, the thread goes
     85 // to sleep, and is signalled awake when a new entry is placed in the
     86 // 'granted_list'.
     87 //
     88 void
     89 cl_flk_handle_waking_locks(void *)
     90 {
     91 	lock_descriptor_t		*lock;
     92 	PXFS_VER::pxfs_llm_callback_ptr	lock_cb;
     93 	PXFS_VER::pxfs_llm_callback_ptr	lock_cb_dup;
     94 	Environment			e;
     95 	lock_context_t			*lock_contextp;
     96 	frange_lock			*fr_lockp;
     97 
     98 	granted_list_lock.lock();
     99 	for (;;) {
    100 
    101 		sleep_cond.wait(&granted_list_lock);
    102 
    103 #ifdef _FAULT_INJECTION
    104 		if (fault_triggered(FAULTNUM_PXFS_GRANTEDLOCK_S_O, NULL,
    105 		    NULL)) {
    106 			granted_list_lock.unlock();
    107 			FAULTPT_PXFS(FAULTNUM_PXFS_GRANTEDLOCK_S_O,
    108 			    FaultFunctions::generic);
    109 			granted_list_lock.lock();
    110 		}
    111 #endif
    112 
    113 		while ((lock = granted_list.reapfirst()) != NULL) {
    114 
    115 			// get the callback object
    116 			lock_contextp = CL_FLK_GET_CONTEXT(lock);
    117 			lock_cb = lock_contextp->cb_obj_v1;
    118 			ASSERT(!CORBA::is_nil(lock_cb));
    119 
    120 			fr_lockp = ((fobj_ii *)(lock_contextp->fobj_abstract_p))
    121 			    ->get_frange_lock();
    122 			ASSERT(fr_lockp != NULL);
    123 
    124 			//
    125 			// Grab the 'processed_list_lock' before dropping the
    126 			// 'granted_list_lock', to handle the race between this
    127 			// procedure and cl_flk_cancel_blocked_request().
    128 			//
    129 			fr_lockp->lock_processed_list();
    130 			granted_list_lock.unlock();
    131 
    132 			fr_lockp->add_to_processed_list(lock);
    133 
    134 			// Duplicate the callback object, and then drop the
    135 			// `processed_list_lock'
    136 			lock_cb_dup =
    137 			    PXFS_VER::pxfs_llm_callback::_duplicate(lock_cb);
    138 
    139 			fr_lockp->unlock_processed_list();
    140 
    141 			// invoke the callback function.
    142 			lock_cb_dup->wakeup(e);
    143 
    144 			// Release the duplicated reference.
    145 			CORBA::release(lock_cb_dup);
    146 
    147 			// We ignore exceptions since there is nothing to do
    148 			// if the client crashed
    149 			e.clear();
    150 
    151 			granted_list_lock.lock();
    152 		}
    153 	}
    154 }
    155 
    156 //
    157 // Remove from the granted list and the LLM all locks associated with
    158 // 'fobj_iip'.
    159 //
    160 void
    161 remove_granted_locks(fobj_ii *fobj_iip)
    162 {
    163 	lock_descriptor_t	*lock;
    164 
    165 	frange_lock		*fr_lockp = fobj_iip->get_frange_lock();
    166 	ASSERT(fr_lockp != NULL);
    167 
    168 	granted_list_lock.lock();
    169 	granted_list.atfirst();
    170 	while ((lock = granted_list.get_current()) != NULL) {
    171 		if (get_fobj_ii(lock) != fobj_iip) {
    172 			granted_list.advance();
    173 			continue;
    174 		}
    175 		(void) granted_list.erase(lock);
    176 		granted_list_lock.unlock();
    177 		PXFS_DBPRINTF(
    178 		    PXFS_TRACE_FLK,
    179 		    PXFS_GREEN,
    180 		    ("(%p) Removing granted lock (%p)\n",
    181 		    fobj_iip, lock));
    182 		(void) fr_lockp->process_pxfs_lock(lock, true);
    183 		granted_list_lock.lock();
    184 		granted_list.atfirst();
    185 	}
    186 	granted_list_lock.unlock();
    187 }
    188 
    189 //
    190 // This function adds the lock provided to the 'granted_list' of locks.
    191 // This routine is called (indirectly) by the local lock manager when a
    192 // blocked PXFS thread is granted.
    193 //
    194 void
    195 cl_flk_state_notify_lock_woken(lock_descriptor_t *lock)
    196 {
    197 	granted_list_lock.lock();
    198 
    199 	// Add the lock to the list
    200 	granted_list.prepend(lock);
    201 
    202 	// Signal awake the thread that makes the callbacks
    203 	sleep_cond.signal();
    204 
    205 	granted_list_lock.unlock();
    206 }
    207 
    208 //
    209 // This routine is invoked when a sleeping PXFS lock is going to be
    210 // deleted.  It checks to see if the lock is already on one of the
    211 // sleeping PXFS lists, and if it is, it wakes it up.
    212 //
    213 void
    214 cl_flk_state_notify_woken_lock_deleted(lock_descriptor_t *lock)
    215 {
    216 	PXFS_VER::pxfs_llm_callback_ptr	lock_cb;
    217 	bool				found;
    218 	lock_context_t			*lock_contextp;
    219 
    220 	frange_lock			*fr_lockp = get_fobj_ii(lock)->
    221 					    get_frange_lock();
    222 	ASSERT(fr_lockp != NULL);
    223 
    224 	//
    225 	// The lock has beed woken up previously - this means that it is on one
    226 	// of the PXFS lists unless this call is made as a result of
    227 	// fobj_ii::remove_all_locks().
    228 	// The order of searching the lists has to be 'granted_list',
    229 	// 'processed_list', because of the implementation of
    230 	// cl_flk_handle_waking_locks()
    231 	//
    232 	granted_list_lock.lock();
    233 	found = granted_list.erase(lock);
    234 	granted_list_lock.unlock();
    235 	if (!found) {
    236 		(void) fr_lockp->remove_from_processed_list(lock);
    237 	}
    238 
    239 	// Relase the CORBA reference
    240 	lock_contextp = CL_FLK_GET_CONTEXT(lock);
    241 	lock_cb = lock_contextp->cb_obj_v1;
    242 
    243 	// A woken-up lock must have a valid callback object associated with it
    244 	ASSERT(!CORBA::is_nil(lock_cb));
    245 
    246 	fr_lockp->remove_cb_object(lock_cb);
    247 
    248 	// Drop the reference to the callback object.
    249 	CORBA::release(lock_cb);
    250 }
    251 
    252 //
    253 // Helper function that returns the fobj that the given PXFS lock belongs to.
    254 //
    255 fobj_ii *
    256 get_fobj_ii(lock_descriptor_t *lock)
    257 {
    258 	lock_context_t *fobj_lock_infop = CL_FLK_GET_CONTEXT(lock);
    259 
    260 	return ((fobj_ii *)fobj_lock_infop->fobj_abstract_p);
    261 }
    262 
    263 //
    264 // This function is called by the local lock manager whenever the
    265 // state of a PXFS lock changes. It dispatches the notifications to the
    266 // appropriate function.
    267 //
    268 void
    269 flk_state_transition_notify(lock_descriptor_t *lock, int old_state,
    270     int new_state)
    271 {
    272 	ASSERT(IS_PXFS(lock));
    273 
    274 	frange_lock	*fr_lockp;
    275 
    276 	PXFS_DBPRINTF(
    277 	    PXFS_TRACE_FLK,
    278 	    PXFS_GREEN,
    279 	    ("(%p) state transition (%d - %d): (%d) (%d, %d)\n",
    280 	    CL_FLK_GET_CONTEXT(lock)->fobj_abstract_p, old_state, new_state,
    281 	    (int)lock->l_type, (int)lock->l_start, (int)lock->l_end));
    282 
    283 	switch (new_state) {
    284 	case FLK_ACTIVE_STATE:
    285 		fr_lockp = get_fobj_ii(lock)->get_frange_lock();
    286 		ASSERT(fr_lockp != NULL);
    287 
    288 		// Lock has become active - notify the fobj
    289 		fr_lockp->lock_active(lock);
    290 		return;
    291 
    292 	case FLK_GRANTED_STATE:
    293 	case FLK_INTERRUPTED_STATE:
    294 	case FLK_CANCELLED_STATE:
    295 		// Lock has been woken up.
    296 		if ((old_state == FLK_GRANTED_STATE) ||
    297 		    (old_state == FLK_CANCELLED_STATE) ||
    298 		    (old_state == FLK_INTERRUPTED_STATE)) {
    299 			// Lock has been woken up before - it is already in the
    300 			// PXFS lists.
    301 			return;
    302 		}
    303 		cl_flk_state_notify_lock_woken(lock);
    304 		return;
    305 
    306 	case FLK_DEAD_STATE:
    307 
    308 		if ((old_state == FLK_GRANTED_STATE) ||
    309 		    (old_state == FLK_CANCELLED_STATE) ||
    310 		    (old_state == FLK_INTERRUPTED_STATE)) {
    311 			// A woken-up lock is being deleted
    312 			cl_flk_state_notify_woken_lock_deleted(lock);
    313 
    314 		} else if (old_state == FLK_ACTIVE_STATE) {
    315 			fr_lockp = get_fobj_ii(lock)->get_frange_lock();
    316 			ASSERT(fr_lockp != NULL);
    317 
    318 			// Active lock has been deleted
    319 			fr_lockp->lock_deleted(lock);
    320 		}
    321 
    322 		// The other cases of a lock transitioning to the 'DEAD' state
    323 		// are not of interest to PXFS
    324 
    325 		return;
    326 
    327 	default:
    328 		break;
    329 	}
    330 }
    331 
    332 //
    333 // Creates the thread that notifies sleeping clients.
    334 //
    335 int
    336 cl_flk_init()
    337 {
    338 	//
    339 	// Create a lwp in the scheduling class SYS.
    340 	//
    341 	if ((clnewlwp(cl_flk_handle_waking_locks, NULL, MINCLSYSPRI,
    342 	    NULL, NULL)) != 0) {
    343 		cmn_err(CE_WARN, "cl_flk_init: cannot create thread");
    344 		return (-1);
    345 	}
    346 	return (0);
    347 }
    348