Home | History | Annotate | Download | only in mount
      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	"@(#)mount_replica_impl.cc	1.45	08/05/20 SMI"
     28 
     29 #include <sys/vm_util.h>
     30 #include <orb/infrastructure/orb_conf.h>
     31 #include <nslib/ns.h>
     32 #include <pxfs/common/pxfslib.h>
     33 #include <pxfs/mount/mount_replica_impl.h>
     34 #include <pxfs/mount/mount_server_impl.h>
     35 #include <pxfs/mount/mount_debug.h>
     36 
     37 //
     38 // The struct  has an entry for each IDL interface which is being versioned. For
     39 // a given VP major and minor version, we get the IDL version of those
     40 // interfaces.
     41 //
     42 mount_ver_map_t mount_vp_to_idl[MOUNT_VP_MAX_MAJOR + 1][MOUNT_VP_MAX_MINOR +1] =
     43 {
     44 	{   { 0, 0 },		// VP Version 0.0 defined for indexing
     45 	    { 0, 0 },		// VP Version 0.1   "      "     "
     46 	    { 0, 0 }  },	// VP Version 0.2   "      "     "
     47 	{   { 0, 0 },		// VP Version 1.0
     48 	    { 1, 1 },		// VP Version 1.1
     49 	    { 1, 1 }  },	// VP Version 1.2
     50 	{   { 2, 2 },		// VP Version 2.0 Object Consolidation
     51 	    { 2, 2},		// VP Version 2.1 currently unused
     52 	    { 2, 2 }  }		// VP Version 2.2 currently unused
     53 };
     54 
     55 //
     56 // Create a mount_replica_impl object.
     57 //
     58 mount_replica_impl::mount_replica_impl(const char *id) :
     59 	repl_server<repl_pxfs::mount_replica>("mount", id),
     60 	_ckpt_proxy(NULL)
     61 {
     62 	mount_serverp = NULL;
     63 
     64 	//
     65 	// We initialize the current version to an invalid version.
     66 	// mount_replica_impl::startup()  will query the version manager
     67 	// for the correct values.
     68 	//
     69 	current_version.major_num = 0;
     70 	current_version.minor_num = 0;
     71 	pending_version.major_num = 0;
     72 	pending_version.minor_num = 0;
     73 }
     74 
     75 mount_replica_impl::~mount_replica_impl()
     76 {
     77 	mount_serverp = NULL;
     78 	_ckpt_proxy = NULL;
     79 }
     80 
     81 repl_pxfs::mount_replica_ptr
     82 mount_replica_impl::get_checkpoint_mount_replica()
     83 {
     84 	ASSERT(!CORBA::is_nil(_ckpt_proxy));
     85 	return (_ckpt_proxy);
     86 }
     87 
     88 //
     89 // Become the primary.
     90 // Note that previously we might have been newly created or
     91 // a secondary that is switching to primary.
     92 //
     93 void
     94 mount_replica_impl::become_primary(const replica::repl_name_seq &,
     95     Environment &_environment)
     96 {
     97 	//
     98 	// The following environment is for checkpointing to the secondary
     99 	// We use a different environment for checkpointing because
    100 	// mount_server_impl::upgrade_client_reference() clears the
    101 	// environment context passed to it.
    102 	//
    103 	Environment		ckpt_environment;
    104 
    105 	//
    106 	// Create a primary context so the provider can send
    107 	// checkpoints while the service is frozen.
    108 	// XXX change the primary_ctx::invoke_env type.
    109 	//
    110 	primary_ctx ctx(NULL, primary_ctx::ADD_SECONDARY_CKPT,
    111 	    ckpt_environment);
    112 
    113 	// First, initialize the checkpoint proxy.
    114 	version_lock.wrlock();
    115 
    116 	// Callback may have occured when this replica was a secondary
    117 	if (pending_version.major_num != 0) {
    118 		current_version = pending_version;
    119 	}
    120 	CORBA::type_info_t	*typ = repl_pxfs::mount_replica::_get_type_info(
    121 	    mount_vp_to_idl[current_version.major_num]
    122 		[current_version.minor_num].ms_ckpt);
    123 	replica::checkpoint_var		tmp_ckpt_v = set_checkpoint(typ);
    124 	_ckpt_proxy = repl_pxfs::mount_replica::_narrow(tmp_ckpt_v);
    125 
    126 	ASSERT(!CORBA::is_nil(_ckpt_proxy));
    127 
    128 	//
    129 	// If we were a secondary.
    130 	//
    131 	if (mount_serverp != NULL) {
    132 		//
    133 		// If there was an unprocessed upgrade callback pending,
    134 		// finish the work and send a checkpoint to notify the
    135 		// other secondaries.
    136 		//
    137 		if (pending_version.major_num != 0) {
    138 			pending_version.major_num = 0;
    139 
    140 			// Update the server reference.
    141 			typ = fs::mount_server::_get_type_info(
    142 			    mount_vp_to_idl[current_version.major_num]
    143 				[current_version.minor_num].ms);
    144 			mount_server_v = mount_serverp->get_objref(typ);
    145 
    146 			// Update the client reference in the mount_server_impl
    147 			mount_serverp->upgrade_client_reference(_environment);
    148 
    149 			// Checkpoint current version.
    150 			_ckpt_proxy->ckpt_service_version(
    151 			    current_version.major_num,
    152 			    current_version.minor_num, ckpt_environment);
    153 			ckpt_environment.clear();
    154 		}
    155 		version_lock.unlock();
    156 
    157 		mount_serverp->convert_to_primary();
    158 
    159 		//
    160 		// Show that the context is no longer there,
    161 		// so that the destructor will see that everything is clean.
    162 		//
    163 		ckpt_environment.trans_ctxp = NULL;
    164 
    165 		return;
    166 	}
    167 
    168 	//
    169 	// Create a new mount server implementation object.
    170 	//
    171 	mount_serverp = new mount_server_impl(this);
    172 	typ = fs::mount_server::_get_type_info(
    173 	    mount_vp_to_idl[current_version.major_num]
    174 		[current_version.minor_num].ms);
    175 	mount_server_v = mount_serverp->get_objref(typ);
    176 
    177 	// Checkpoint the creation of the first mount server object.
    178 	mount_serverp->get_checkpoint()->ckpt_new_server(mount_server_v,
    179 	    ckpt_environment);
    180 	ckpt_environment.clear();
    181 
    182 	//
    183 	// If an old primary failed while an upgrade callback was in
    184 	// progress and before the service version was checkpointed, we
    185 	// do the service version checkpointing now.
    186 	//
    187 	if (pending_version.major_num != 0) {
    188 		pending_version.major_num = 0;
    189 		_ckpt_proxy->ckpt_service_version(
    190 		    current_version.major_num,
    191 		    current_version.minor_num, ckpt_environment);
    192 	}
    193 	version_lock.unlock();
    194 
    195 	//
    196 	// Show that the context is no longer there,
    197 	// so that the destructor will see that everything is clean.
    198 	//
    199 	ckpt_environment.trans_ctxp = NULL;
    200 }
    201 
    202 //
    203 // Become the secondary.
    204 //
    205 void
    206 mount_replica_impl::become_secondary(Environment &)
    207 {
    208 	ASSERT(mount_serverp != NULL);
    209 	mount_serverp->convert_to_secondary();
    210 
    211 	version_lock.wrlock();
    212 	ASSERT(!CORBA::is_nil(_ckpt_proxy));
    213 
    214 	// Release the reference to the multi_ckpt_handler.
    215 	CORBA::release(_ckpt_proxy);
    216 	_ckpt_proxy = nil;
    217 	version_lock.unlock();
    218 }
    219 
    220 void
    221 mount_replica_impl::add_secondary(replica::checkpoint_ptr sec_chkpt,
    222     const char *, Environment &_environment)
    223 {
    224 	ASSERT(mount_serverp != NULL);
    225 
    226 	repl_pxfs::mount_replica_var ckpt =
    227 		repl_pxfs::mount_replica::_narrow(sec_chkpt);
    228 	ASSERT(!CORBA::is_nil(ckpt));
    229 
    230 	// dump current state to the new secondary
    231 	mount_serverp->dump_state(ckpt, _environment);
    232 	if (_environment.exception()) {
    233 		MOUNT_DBPRINTF(
    234 		    MOUNT_TRACE_REPLICA,
    235 		    MOUNT_RED,
    236 		    ("replica:exception '%s' in dump_state() \n",
    237 		    _environment.exception()->_name()));
    238 	}
    239 	_environment.clear();
    240 }
    241 
    242 void
    243 mount_replica_impl::remove_secondary(const char *, Environment &)
    244 {
    245 }
    246 
    247 void
    248 mount_replica_impl::freeze_primary_prepare(Environment &)
    249 {
    250 }
    251 
    252 void
    253 mount_replica_impl::freeze_primary(Environment &)
    254 {
    255 	//
    256 	// Start freezing. The situation we are trying to prevent is
    257 	// where a call to devlock() is waiting for the lock and
    258 	// then a swithover is requested. The switchover won't complete
    259 	// until the devlock() returns but that can't happen since the
    260 	// devunlock() is blocked until the switchover completes.
    261 	//
    262 	if (mount_serverp != NULL) {
    263 		mount_serverp->freeze_primary();
    264 	}
    265 }
    266 
    267 void
    268 mount_replica_impl::unfreeze_primary(Environment &)
    269 {
    270 	if (mount_serverp != NULL) {
    271 		mount_serverp->unfreeze_primary();
    272 	}
    273 }
    274 
    275 void
    276 mount_replica_impl::become_spare(Environment &)
    277 {
    278 	if (mount_serverp != NULL) {
    279 		// Drop our reference to the object before doing a delete.
    280 		mount_server_v = fs::mount_server::_nil();
    281 		mount_serverp->convert_to_spare();
    282 		//
    283 		// mount_serverp is cleaned up in convert_to_spare(),
    284 		// so the next line is not a memory leak.
    285 		//lint -e423
    286 		mount_serverp = NULL;
    287 		//lint +e423
    288 	}
    289 }
    290 
    291 //
    292 // This is called on the primary when the service is requested to shutdown.
    293 //
    294 void
    295 mount_replica_impl::shutdown(Environment &_environment)
    296 {
    297 	// We should never shut down.
    298 	_environment.exception(new replica::service_busy);
    299 
    300 	//
    301 	// Since we are returning an exception, we will remain primary,
    302 	// so don't release _ckpt_proxy.
    303 	//
    304 }
    305 
    306 //
    307 // This is called on the primary to return a reference to the root
    308 // HA object (in this case, fs::mount_server).
    309 //
    310 CORBA::Object_ptr
    311 mount_replica_impl::get_root_obj(Environment &)
    312 {
    313 	ASSERT(mount_serverp != NULL);
    314 	version_lock.wrlock();
    315 	CORBA::type_info_t *typ = fs::mount_server::_get_type_info(
    316 	    mount_vp_to_idl[current_version.major_num]
    317 		[current_version.minor_num].ms);
    318 	version_lock.unlock();
    319 	return (mount_serverp->get_objref(typ));
    320 }
    321 
    322 //
    323 // Process an upgrade callback from the version manager.
    324 // This call can happen before the HA replica is registered with the
    325 // replica manager (i.e., the HA sevice is not started yet or is a spare),
    326 // or as primary or secondary. The callback is not synchronized with
    327 // calls to become_primary(), become_secondary(), etc. and failovers can
    328 // happen while the service is frozen so we need to make sure that the
    329 // "upgrade work" is done if there are node failures.
    330 // If this replica is the primary, we do the work and send a checkpoint
    331 // to indicate the work is complete. If this replica is a secondary and
    332 // the callback happens before we get the checkpoint from the primary,
    333 // we record that the callback happened so that become_primary() can
    334 // do the "upgrade work" and send the checkpoint. If this replica is a
    335 // secondary and the callback happens after the checkpoint is received,
    336 // we ignore the callback. The checkpoint routine on the secondary clears
    337 // the "flag" that the callback sets so no extra work is done in
    338 // become_primary() if the old primary fails after completing the upgrade
    339 // callback work.
    340 //
    341 void
    342 mount_replica_impl::upgrade_callback(
    343     const version_manager::vp_version_t &version, Environment &e)
    344 {
    345 	CORBA::type_info_t *typ;
    346 
    347 	//
    348 	// Note that upgrade callbacks are not synchronized with
    349 	// calls to become_primary(), add_secondary(), etc.
    350 	// Getting this lock makes sure the replica state doesn't change.
    351 	//
    352 	version_lock.wrlock();
    353 	if (current_version.major_num > version.major_num ||
    354 	    (current_version.major_num == version.major_num &&
    355 	    current_version.minor_num >= version.minor_num)) {
    356 		// Version isn't changing so just return.
    357 		version_lock.unlock();
    358 		return;
    359 	}
    360 
    361 	//
    362 	// If this replica is not the primary, set the pending version
    363 	// to be used if there is a failover before the primary checkpoints
    364 	// a new version.
    365 	//
    366 	if (CORBA::is_nil(_ckpt_proxy)) {
    367 		// If this replica is a secondary, set the pending version.
    368 		if (mount_serverp != NULL) {
    369 			pending_version = version;
    370 		} else {
    371 			// Replica must be a spare.
    372 			current_version = version;
    373 		}
    374 		version_lock.unlock();
    375 		return;
    376 	}
    377 
    378 	// We are the primary and the version has changed.
    379 	current_version = version;
    380 	MOUNT_DBPRINTF(
    381 	    MOUNT_TRACE_REPLICA,
    382 	    MOUNT_GREEN,
    383 	    ("replica:upgrade_callback major = %d minor = %d ",
    384 	    current_version.major_num, current_version.minor_num));
    385 
    386 	//
    387 	// Switch the checkpoint interface to the new protocol. Save
    388 	// the current _ckpt_proxy and release it after we get a new one
    389 	//
    390 	repl_pxfs::mount_replica_ptr old_ckpt_p = _ckpt_proxy;
    391 
    392 	typ = repl_pxfs::mount_replica::_get_type_info(
    393 	    mount_vp_to_idl[current_version.major_num]
    394 		[current_version.minor_num].ms_ckpt);
    395 
    396 	MOUNT_DBPRINTF(
    397 	    MOUNT_TRACE_REPLICA,
    398 	    MOUNT_GREEN,
    399 	    ("replica:upgrade_callback type_info_t ptr = %x",
    400 	    typ));
    401 
    402 	replica::checkpoint_var tmp_ckpt_v = set_checkpoint(typ);
    403 	_ckpt_proxy = repl_pxfs::mount_replica::_narrow(tmp_ckpt_v);
    404 	ASSERT(!CORBA::is_nil(_ckpt_proxy));
    405 
    406 	CORBA::release(old_ckpt_p);
    407 
    408 	// Update the server reference.
    409 	typ = fs::mount_server::_get_type_info(
    410 	    mount_vp_to_idl[current_version.major_num]
    411 		[current_version.minor_num].ms);
    412 	mount_server_v = mount_serverp->get_objref(typ);
    413 
    414 	// Update the client reference in the mount_server_impl
    415 	mount_serverp->upgrade_client_reference(e);
    416 
    417 	//
    418 	// Create and add a primary context so the provider can send
    419 	// checkpoints while the service is frozen.
    420 	// XXX change the primary_ctx::invoke_env type.
    421 	//
    422 	primary_ctx ctx(NULL, primary_ctx::ADD_SECONDARY_CKPT, e);
    423 
    424 	// Checkpoint the current version number.
    425 	_ckpt_proxy->ckpt_service_version(
    426 	    current_version.major_num,
    427 	    current_version.minor_num, e);
    428 
    429 	e.trans_ctxp = NULL;
    430 
    431 	version_lock.unlock();
    432 }
    433 
    434 //
    435 // Checkpoint the creation of a new mount server.
    436 //
    437 void
    438 mount_replica_impl::ckpt_new_server(fs::mount_server_ptr server,
    439     Environment &)
    440 {
    441 	//
    442 	// Create a new mount server (we are a secondary).
    443 	//
    444 	if (mount_serverp == NULL) {
    445 		//lint -e423
    446 		mount_serverp = new mount_server_impl(this, server);
    447 		mount_server_v = fs::mount_server::_duplicate(server);
    448 		//lint +e423
    449 	}
    450 }
    451 
    452 //
    453 // Checkpoint the addition of a new mount client.
    454 //
    455 void
    456 mount_replica_impl::ckpt_add_client(fs::mount_client_died_ptr clobj,
    457     fs::mount_client_ptr client, sol::nodeid_t nodeid, bool is_shutdown,
    458     Environment &)
    459 {
    460 	ASSERT(mount_serverp != NULL);
    461 	mount_serverp->ckpt_add_client(clobj, client, nodeid, is_shutdown);
    462 }
    463 
    464 //
    465 // Checkpoint the removal of a mount_client.
    466 //
    467 void
    468 mount_replica_impl::ckpt_remove_client(fs::mount_client_ptr client,
    469     Environment &)
    470 {
    471 	ASSERT(mount_serverp != NULL);
    472 	mount_serverp->ckpt_remove_client(client);
    473 }
    474 
    475 //
    476 // Checkpoint the start of a mount or remount.
    477 //
    478 void
    479 mount_replica_impl::ckpt_mount_start(const sol::mounta &ma,
    480     fs::mount_client_ptr client, Environment &_environment)
    481 {
    482 	CL_PANIC(0);
    483 }
    484 
    485 //
    486 // Checkpoint the start of a mount or remount.
    487 //
    488 void
    489 mount_replica_impl::ckpt_mount_start_v1(const sol::mounta &ma,
    490     fs::mount_client_ptr client, Environment &_environment)
    491 {
    492 	ASSERT(mount_serverp != NULL);
    493 	mount_serverp->ckpt_mount_start_v1(ma, client, _environment);
    494 }
    495 
    496 //
    497 // Checkpoint a mount error.
    498 // This is used to complete a ckpt_mount_start().
    499 //
    500 void
    501 mount_replica_impl::ckpt_mount_err(sol::error_t error,
    502     Environment &_environment)
    503 {
    504 	ASSERT(mount_serverp != NULL);
    505 	mount_serverp->ckpt_mount_err(error, _environment);
    506 }
    507 
    508 //
    509 // Checkpoint the addition of a new file system (mount).
    510 // This is used to dump state to a newly joining secondary.
    511 //
    512 void
    513 mount_replica_impl::ckpt_mount(fs::filesystem_ptr fsptr,
    514     const fs::fs_info &fsinfo, const sol::mounta &ma, const char *mntoptions,
    515     bool dev_is_ha, const char *dev_name,
    516     const sol::nodeid_seq_t &dev_nids, Environment &)
    517 {
    518 	CL_PANIC(0);
    519 }
    520 
    521 //
    522 // Checkpoint the addition of a new file system (mount).
    523 // This is used to dump state to a newly joining secondary.
    524 //
    525 void
    526 mount_replica_impl::ckpt_mount_v1(pxfs_v1::filesystem_ptr fsptr,
    527     const pxfs_v1::fs_info &fsinfo, const sol::mounta &ma,
    528     const char *mntoptions, bool dev_is_ha, const char *dev_name,
    529     const sol::nodeid_seq_t &dev_nids, Environment &)
    530 {
    531 	ASSERT(mount_serverp != NULL);
    532 	mount_serverp->ckpt_mount_v1(fsptr, fsinfo, ma, mntoptions, dev_is_ha,
    533 	    dev_name, dev_nids);
    534 }
    535 
    536 //
    537 // Checkpoint the creation of a new file system object.
    538 //
    539 void
    540 mount_replica_impl::ckpt_mount_middle(fs::filesystem_ptr fsptr,
    541     const fs::fs_info &fsinfo, const char *mntoptions, bool dev_is_ha,
    542     const char *dev_name, const sol::nodeid_seq_t &dev_nids,
    543     Environment &_environment)
    544 {
    545 	CL_PANIC(0);
    546 }
    547 
    548 //
    549 // Checkpoint the creation of a new file system object.
    550 //
    551 void
    552 mount_replica_impl::ckpt_mount_middle_v1(pxfs_v1::filesystem_ptr fsptr,
    553     const pxfs_v1::fs_info &fsinfo, const char *mntoptions, bool dev_is_ha,
    554     const char *dev_name, const sol::nodeid_seq_t &dev_nids,
    555     Environment &_environment)
    556 {
    557 	ASSERT(mount_serverp != NULL);
    558 	mount_serverp->ckpt_mount_middle_v1(fsptr, fsinfo, mntoptions,
    559 	    dev_is_ha, dev_name, dev_nids, _environment);
    560 }
    561 
    562 //
    563 // Checkpoint the changes to vfs_flag and /etc/mnttab due to a remount.
    564 //
    565 void
    566 mount_replica_impl::ckpt_remount_middle(fs::filesystem_ptr fsptr,
    567     uint32_t vfsflags, const char *mntoptions, Environment &_environment)
    568 {
    569 	CL_PANIC(0);
    570 }
    571 
    572 //
    573 // Checkpoint the changes to vfs_flag and /etc/mnttab due to a remount.
    574 //
    575 void
    576 mount_replica_impl::ckpt_remount_middle_v1(pxfs_v1::filesystem_ptr fsptr,
    577     uint32_t vfsflags, const char *mntoptions, Environment &_environment)
    578 {
    579 	ASSERT(mount_serverp != NULL);
    580 	mount_serverp->ckpt_remount_middle_v1(fsptr, vfsflags, mntoptions,
    581 	    _environment);
    582 }
    583 
    584 //
    585 // Checkpoint the start of an unmount.
    586 //
    587 void
    588 mount_replica_impl::ckpt_unmount_start(fs::filesystem_ptr fsptr,
    589     solobj::cred_ptr credobj, fs::mount_client_ptr client,
    590     bool is_shutdown, Environment &_environment)
    591 {
    592 	CL_PANIC(0);
    593 }
    594 
    595 //
    596 // Checkpoint the start of an unmount.
    597 //
    598 // mount_replica_impl(repl_pxfs::mount_replica::ckpt_unmount_start)
    599 void
    600 mount_replica_impl::ckpt_unmount_start_1(fs::filesystem_ptr fsptr,
    601     int32_t flags, solobj::cred_ptr credobj, fs::mount_client_ptr client,
    602     bool is_shutdown, Environment &_environment)
    603 {
    604 	CL_PANIC(0);
    605 }
    606 
    607 //
    608 // Checkpoint the start of an unmount.
    609 //
    610 void
    611 mount_replica_impl::ckpt_unmount_start_v1(pxfs_v1::filesystem_ptr fsptr,
    612     int32_t flags, solobj::cred_ptr credobj, fs::mount_client_ptr client,
    613     bool is_shutdown, Environment &_environment)
    614 {
    615 	ASSERT(mount_serverp != NULL);
    616 	mount_serverp->ckpt_unmount_start_v1(fsptr, flags,
    617 	    credobj, client, is_shutdown, _environment);
    618 }
    619 
    620 //
    621 // Checkpoint that the mount points have been locked
    622 // and the file system has been unmounted but the
    623 // client nodes haven't been notified yet.
    624 //
    625 void
    626 mount_replica_impl::ckpt_unmount_middle(sol::error_t error,
    627     Environment &_environment)
    628 {
    629 	ASSERT(mount_serverp != NULL);
    630 	mount_serverp->ckpt_unmount_middle(error, _environment);
    631 }
    632 
    633 //
    634 // Checkpoint that all the client nodes have been
    635 // notified (if there was no unmount error) before shutting
    636 // down the file system service.
    637 //
    638 void
    639 mount_replica_impl::ckpt_unmount_notified(Environment &_environment)
    640 {
    641 	ASSERT(mount_serverp != NULL);
    642 	mount_serverp->ckpt_unmount_notified(_environment);
    643 }
    644 
    645 //
    646 // Checkpoint that all the client nodes have been notified
    647 // (if there was an unmount error) or the file system
    648 // service has been shut down. We can't use a commit() call
    649 // since this may be called more than once when unmounting
    650 // multiple file systems.
    651 //
    652 void
    653 mount_replica_impl::ckpt_unmount_end(Environment &_environment)
    654 {
    655 	ASSERT(mount_serverp != NULL);
    656 	mount_serverp->ckpt_unmount_end(_environment);
    657 }
    658 
    659 //
    660 // Checkpoint a node being shut down as part of unmount().
    661 //
    662 void
    663 mount_replica_impl::ckpt_unmount_shutdown(fs::mount_client_ptr client,
    664     Environment &)
    665 {
    666 	ASSERT(mount_serverp != NULL);
    667 	mount_serverp->ckpt_unmount_shutdown(client);
    668 }
    669 
    670 //
    671 // Checkpoint a new device lock.
    672 //
    673 void
    674 mount_replica_impl::ckpt_devlock(fs::mount_client_ptr client,
    675     sol::nodeid_t nodeid, const char *dev_name, Environment &)
    676 {
    677 	ASSERT(mount_serverp != NULL);
    678 	mount_serverp->ckpt_devlock(client, nodeid, dev_name);
    679 }
    680 
    681 //
    682 // Checkpoint a device unlock.
    683 //
    684 void
    685 mount_replica_impl::ckpt_devunlock(const char *dev_name, Environment &)
    686 {
    687 	ASSERT(mount_serverp != NULL);
    688 	mount_serverp->ckpt_devunlock(dev_name);
    689 }
    690 
    691 //
    692 // Checkpoint the creation of a dc_callback object.
    693 //
    694 void
    695 mount_replica_impl::ckpt_get_dc_callback(fs::dc_callback_ptr cb,
    696     Environment &)
    697 {
    698 	ASSERT(mount_serverp != NULL);
    699 	mount_serverp->ckpt_get_dc_callback(cb);
    700 }
    701 
    702 //
    703 // Checkpoint a change in the disk connection list.
    704 //
    705 void
    706 mount_replica_impl::ckpt_notify_change(sol::dev_t gdev,
    707     const sol::nodeid_seq_t &dev_nids, Environment &)
    708 {
    709 	ASSERT(mount_serverp != NULL);
    710 	mount_serverp->ckpt_notify_change(gdev, dev_nids);
    711 }
    712 
    713 //
    714 // Checkpoint a new service version
    715 //
    716 void
    717 mount_replica_impl::ckpt_service_version(unsigned short new_major,
    718     unsigned short new_minor, Environment &)
    719 {
    720 	version_lock.wrlock();
    721 	current_version.major_num = new_major;
    722 	current_version.minor_num = new_minor;
    723 	pending_version.major_num = 0;
    724 	version_lock.unlock();
    725 }
    726 
    727 //
    728 // Checkpoint the upgrade of a mount_client in client list.
    729 //
    730 void
    731 mount_replica_impl::ckpt_upgrade_client_list(fs::mount_client_ptr client,
    732     sol::nodeid_t nodeid, Environment &)
    733 {
    734 	ASSERT(mount_serverp != NULL);
    735 	mount_serverp->ckpt_upgrade_client_list(client, nodeid);
    736 }
    737 
    738 //
    739 // Checkpoint the upgrade of a mount_client in devlock list.
    740 //
    741 void
    742 mount_replica_impl::ckpt_upgrade_devlock_list(const char *dev_name,
    743     fs::mount_client_ptr client, Environment &)
    744 {
    745 	ASSERT(mount_serverp != NULL);
    746 	mount_serverp->ckpt_upgrade_devlock_list(dev_name, client);
    747 }
    748 
    749 //
    750 // Start up the mount service.  We create a replica on every node
    751 // so that the service is always available.
    752 //
    753 int
    754 mount_replica_impl::startup()
    755 {
    756 	Environment e;
    757 	char *svc_desc = "mount";
    758 	char *vpname = "px_mount";
    759 
    760 	// Create a new mount replica for This node.
    761 	char id[20];
    762 	os::sprintf(id, "%u", orb_conf::node_number());
    763 	mount_replica_impl *repl = new mount_replica_impl(id);
    764 
    765 	// Get a pointer to the local version manager
    766 	version_manager::vm_admin_var vmgr_v = vm_util::get_vm(NODEID_UNKNOWN);
    767 
    768 	// Build a UCC for support of version upgrade callbacks
    769 	version_manager::ucc_seq_t ucc_seq(1, 1);
    770 	ucc_seq[0].ucc_name = os::strdup(svc_desc);
    771 	ucc_seq[0].vp_name = os::strdup(vpname);
    772 	version_manager::string_seq_t fseq(1, 1);
    773 	fseq[0] = os::strdup(svc_desc);
    774 	ucc_seq[0].freeze = fseq;
    775 
    776 	// Create a version upgrade callback object for this mount replica.
    777 	version_manager::vp_version_t		callback_limit;
    778 	version_manager::vp_version_t		cur_version;
    779 	version_manager::upgrade_callback_var	cbobj =
    780 	    (new mount_version_callback_impl(*repl))->get_objref();
    781 
    782 	//
    783 	// Register the callback object with the Version Manager. The
    784 	// tmp_version will be returned.  The version lock is not held
    785 	// since the replica is not yet registered with the HA framework
    786 	// so there can not be a call to become_primary. The current version
    787 	// is returned regardless.
    788 	//
    789 	// If the running version is less than the callback_limit
    790 	// a callback will be registerd, otherwise a callback is not
    791 	// registered (currently no way to tell).  The current running
    792 	// version is returned regardless.
    793 	//
    794 	callback_limit.major_num = 2;
    795 	callback_limit.minor_num = 0;
    796 	vmgr_v->register_upgrade_callbacks(ucc_seq, cbobj, callback_limit,
    797 	    cur_version, e);
    798 	if (e.exception()) {
    799 		MOUNT_DBPRINTF(
    800 		    MOUNT_TRACE_REPLICA,
    801 		    MOUNT_RED,
    802 		    ("replica:startup: version exception"
    803 		    "on attemping to register for upgrade callback, id %s",
    804 		    id));
    805 		return (1);
    806 	}
    807 
    808 	// establish the current version in the provider
    809 	repl->set_version(cur_version);
    810 
    811 	repl->register_with_rm(1, true, e);
    812 	if (e.exception()) {
    813 		MOUNT_DBPRINTF(
    814 		    MOUNT_TRACE_REPLICA,
    815 		    MOUNT_RED,
    816 		    ("replica:startup exception register with RM id %s\n",
    817 		    id));
    818 		e.clear();
    819 		return (EIO);
    820 	}
    821 	return (0);
    822 }
    823 
    824 int
    825 mount_replica_impl::shutdown()
    826 {
    827 	return (0);
    828 }
    829 
    830 //
    831 // Set the initial version number.
    832 //
    833 void
    834 mount_replica_impl::set_version(const version_manager::vp_version_t &version)
    835 {
    836 	//
    837 	// We could have had a callback between the time that we called
    838 	// register_upgrade_callbacks() and the time that it returned and
    839 	// set tmp_version. The callback may have set a newer version than
    840 	// current version, so don't clobber it.
    841 	//
    842 	version_lock.wrlock();
    843 	if (current_version.major_num < version.major_num ||
    844 	    (current_version.major_num == version.major_num &&
    845 	    current_version.minor_num < version.minor_num)) {
    846 		current_version = version;
    847 	}
    848 	version_lock.unlock();
    849 }
    850 
    851 
    852 
    853 mount_version_callback_impl::mount_version_callback_impl(
    854     mount_replica_impl &mount_replica) :
    855 	prov(mount_replica)
    856 {
    857 }
    858 
    859 mount_version_callback_impl::~mount_version_callback_impl()
    860 {
    861 }
    862 
    863 void
    864 mount_version_callback_impl::_unreferenced(unref_t arg)
    865 {
    866 	if (!_last_unref(arg)) {
    867 		// _last_unref() should always be true since we don't use 0->1.
    868 		ASSERT(0);
    869 		return;
    870 	}
    871 	delete this;
    872 }
    873 
    874 void
    875 mount_version_callback_impl::do_callback(const char *,
    876     const version_manager::vp_version_t &current_version, Environment &e)
    877 {
    878 	// Call the provider to update the version and checkpoint it.
    879 	prov.upgrade_callback(current_version, e);
    880 }
    881