nfs4_srv_deleg.c revision d216dff54a0e6b02eb6eafa0c066af37fdc22d5f
1N/A * The contents of this file are subject to the terms of the 1N/A * Common Development and Distribution License (the "License"). 1N/A * You may not use this file except in compliance with the License. 1N/A * See the License for the specific language governing permissions 1N/A * and limitations under the License. 1N/A * When distributing Covered Code, include this CDDL HEADER in each 1N/A * If applicable, add the following below this CDDL HEADER, with the 1N/A * fields enclosed by brackets "[]" replaced with your own identifying 1N/A * information: Portions Copyright [yyyy] [name of copyright owner] 1N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 1N/A * Use is subject to license terms. 1N/A * Convert a universal address to an transport specific 1N/A * address using inet_pton. 1N/A for (i =
len-
1; i >= 0; i--) {
1N/A * We use k to remember were to stick '.' back, since 1N/A * ua was kmem_allocateded from the pool len+1. 1N/A }
else if (
ua[j] >=
'0' &&
1N/A /* reset to network order */ 1N/A * Update the delegation policy with the 1N/A * value of "new_policy" 1N/A * This free function is to be used when the client struct is being 1N/A * released and nothing at all is needed of the callback info any 1N/A /* Free old address if any */ 1N/A * The server uses this to check the callback path supplied by the 1N/A * client. The callback connection is marked "in progress" while this 1N/A * work is going on and then eventually marked either OK or FAILED. 1N/A * This work can be done as part of a separate thread and at the end 1N/A * of this the thread will exit or it may be done such that the caller 1N/A * will continue with other work. 1N/A /* If another thread is doing CB_NULL RPC then return */ 1N/A /* Mark the cbinfo as having a thread in the NULL callback */ 1N/A * Are there other threads still using the cbinfo client 1N/A * handles? If so, this thread must wait before going and 1N/A * mucking aroiund with the callback information 1N/A * This thread itself may find that new callback info has 1N/A * arrived and is set up to handle this case and redrive the 1N/A * call to the client's callback server. 1N/A * Free the old stuff if it exists; may be the first 1N/A * time through this path 1N/A /* Get the program number */ 1N/A /* Don't forget the protocol's "cb_ident" field */ 1N/A /* get rid of the old client handles that may exist */ 1N/A /* mark rfs4_client_t as CALLBACK NULL in progress */ 1N/A /* Check to see if the client has specified new callback info */ 1N/A goto retry;
/* give the CB_NULL another chance */ 1N/A * Given a client struct, inspect the callback info to see if the 1N/A * callback path is up and available. 1N/A * If new callback path is available and no one has set it up then 1N/A * try to set it up. If setup is not successful after 5 tries (5 secs) 1N/A * then gives up and returns NULL. 1N/A * If callback path is being initialized, then wait for the CB_NULL RPC 1N/A * Looks like a new callback path may be available and 1N/A * noone has set it up. 1N/A * If callback path is no longer new, or it's being setup 1N/A * then stop and wait for it to be done. 1N/A /* Is there a thread working on doing the CB_NULL RPC? */ 1N/A /* If the callback path is not okay (up and running), just quit */ 1N/A /* Let someone know we are using the current callback info */ 1N/A * The caller is done with the callback info. It may be that the 1N/A * caller's RPC failed and the NFSv4 client has actually provided new 1N/A * callback information. If so, let the caller know so they can 1N/A * advantage of this and maybe retry the RPC that originally failed. 1N/A /* The caller gets a chance to mark the callback info as bad */ 1N/A * A thread may be waiting on this one to finish and if so, 1N/A * let it know that it is okay to do the CB_NULL to the 1N/A * client's callback server. 1N/A * If this is the last thread to use the callback info and 1N/A * there is new callback information to try and no thread is 1N/A * there ready to do the CB_NULL, then return true to teh 1N/A * caller so they can do the CB_NULL 1N/A * Given the information in the callback info struct, create a client 1N/A * handle that can be used by the server for its callback path. 1N/A }
else /* AF_INET6 */ {
/* turn off reserved port usage */ * Iterate over the client handle cache and * Return a client handle, either from a the small * rfs4_client_t cache or one that we just created. /* none free so make it now */ * Return the client handle to the small cache or * cache maxed out of free entries, obliterate * this client handle, destroy it, throw it away. * With the supplied callback information - initialize the client * callback data. If there is a callback in progress, save the * callback info so that a thread can pick it up in the future. /* Set the call back for the client */ /* ready to save the new information but first free old, if exists */ * The server uses this when processing SETCLIENTID_CONFIRM. Callback * information may have been provided on SETCLIENTID and this call * marks that information as confirmed and then starts a thread to * test the callback path. * First free any special args alloc'd for specific ops. * General callback routine for the server to the client. /* start with this in case cb_getch() fails */ /* get a client handle */ * reset the cb_ident since it may have changed in * If the rele says that there may be new callback info then * retry this sequence and it may succeed as a result of the * Used by the NFSv4 server to get attributes for a file while * handling the case where a file has been write delegated. For the * time being, VOP_GETATTR() is called and CB_GETATTR processing is * not undertaken. This call site is maintained in case the server is * updated in the future to handle write delegation space guarantees. * This is used everywhere in the v2/v3 server to allow the * integration of all NFS versions and the support of delegation. For * now, just call the VOP_GETATTR(). If the NFSv4 server is enhanced * in the future to provide space guarantees for write delegations * then this call site should be expanded to interact with the client. * Place the actual cb_recall otw call to client. * set up the compound args numops =
1;
/* CB_RECALL only */ /* cb4_args.callback_ident is set in rfs4_do_callback() */ * fill in the args struct /* Keep track of when we did this for observability */ * Set up the timeout for the callback and make the actual call. * Timeout will be 80% of the lease period for this server. * It is possible that before this thread starts * the client has send us a return_delegation, and * if that is the case we do not need to send the * Recall count may go negative if the parent thread that is * creating the individual callback threads does not modify * the recall_count field before the callback thread actually * gets a response from the CB_RECALL /* Recall already in progress ? */ * if this delegation state * is being reaped skip it /* hold for receiving thread */ * Recall count may go negative if the parent thread that is * creating the individual callback threads does not modify * the recall_count field before the callback thread actually * gets a response from the CB_RECALL * Mark the time we started the recall processing. * If it has been previously recalled, do not reset the * timer since this is used for the revocation decision. /* Client causing recall not always available */ /* First check to see if a revocation should occur */ * Next check to see if a recall should be done again * rfs4_check_recall is called from rfs4_do_open to determine if the current * open conflicts with the delegation. * Return true if we need recall otherwise false. * Assumes entry locks for sp and sp->rs_finfo are held. /* Not currently delegated so there is nothing to do */ * If the access is only asking for READ then there is * no conflict and nothing to do. If it is asking * for write, then there will be conflict and the read * delegation should be recalled. /* Check to see if this client has the delegation */ * Return the "best" allowable delegation available given the current * delegation type and the desired access and deny modes on the file. * At the point that this routine is called we know that the access and * deny modes are consistent with the file modes. * Determine if more than just this OPEN have the file * open and if so, no delegation may be provided to * If the client is going to write, or if the client * has exclusive access, return a write delegation. * If we don't want to write or we've haven't denied read * access to others, return a read delegation. * If the file is delegated for read but we wan't to * write or deny others to read then we can't delegate * the file. We shouldn't get here since the delegation should * have been recalled already. * Given the desired delegation type and the "history" of the file * determine the actual delegation type to return. * no further checks for a delegation race need to be done. * However if a recall has occurred, then check to see if a * client has caused its own delegation recall to occur. If * not, then has a delegation for this file been returned * recently? If so, then do not assign a new delegation to * avoid a "delegation race" between the original client and /* Limit the number of read grants */ * Should consider limiting total number of read/write * delegations the server will permit. * Try and grant a delegation for an open give the state. The routine * returns the delegation type granted. This could be OPEN_DELEGATE_NONE. * The state and associate file entry must be locked /* Is the server even providing delegations? */ /* Check to see if delegations have been temporarily disabled */ /* Don't grant a delegation if a deletion is impending. */ * Don't grant a delegation if there are any lock manager * (NFSv2/v3) locks for the file. This is a bit of a hack (e.g., * if there are only read locks we should be able to grant a * read-only delegation), but it's good enough for now. * MT safety: the lock manager checks for conflicting delegations * before processing a lock request. That check will block until * we are done here. So if the lock manager acquires a lock after * we decide to grant the delegation, the delegation will get * immediately recalled (if there's a conflict), so we're safe. * Based on the type of delegation request passed in, take the * appropriate action (DELEG_NONE is handled above) * The server "must" grant the delegation in this case. * Client is using open previous * If a valid callback path does not exist, no delegation may * If the original operation which caused time_rm_delayed * to be set hasn't been retried and completed for one * full lease period, clear it and allow delegations to * If we are waiting for a delegation to be returned then * don't delegate this file. We do this for correctness as * well as if the file is being recalled we would likely * recall this file again. /* Get the "best" delegation candidate */ * Based on policy and the history of the file get the /* set the delegation for the state */ * We need to allocate a new copy of the who string. * this string will be freed by the rfs4_op_open dis_resfree * routine. We need to do this allocation since replays will * be allocated and rfs4_compound can't tell the difference from * a replay and an inital open. N.B. if an ace is passed in, it * the caller's responsibility to free it. * Default is to deny all access, the client will have * to contact the server. XXX Do we want to actually * set a deny for every one, or do we simply want to * construct an entity that will match no one? * Check if the file is delegated via the provided file struct. * Return TRUE if it is delegated. This is intended for use by * the v4 server. The v2/v3 server code should use rfs4_check_delegated(). * Note that if the file is found to have a delegation, it is * recalled, unless the clientid of the caller matches the clientid of the * delegation. If the caller has specified, there is a slight delay * inserted in the hopes that the delegation will be returned quickly. /* Is delegation enabled? */ /* do we have a delegation on this file? */ * do we have a write delegation on this file or are we * requesting write access to a file with any type of existing * Does the requestor already own the delegation? * Check if the file is delegated in the case of a v2 or v3 access. * Return TRUE if it is delegated which in turn means that v2 should * drop the request and in the case of v3 JUKEBOX should be returned. /* Is delegation enabled? */ * Release a hold on the hold_grant counter which * prevents delegation from being granted while a remove * or a rename is in progress. * State support for delegation. * Set the state delegation type for this state; * This routine is called from open via rfs4_grant_delegation and the entry * locks on sp and sp->rs_finfo are assumed. /* Unlock to avoid deadlock */ * It is possible that since we dropped the lock * in order to call finddeleg, the rfs4_file_t * was marked such that we should not grant a * delegation, if so bail out. * Check that this file has not been delegated to another /* vnevent_support returns 0 if file system supports vnevents */ /* Calculate the fflags for this OPEN. */ * Before granting a delegation we need to know if anyone else has * opened the file in a conflicting mode. However, first we need to * know how we opened the file to check the counts properly. * Because a client can hold onto a delegation after the * file has been closed, we need to keep track of the * access to this file. Otherwise the CIFS server would * not know about the client accessing the file and could * inappropriately grant an OPLOCK. * fem_install() returns EBUSY when asked to install a * OPUNIQ monitor more than once. Therefore, check the * return code because we only want this done once. * Because a client can hold onto a delegation after the * file has been closed, we need to keep track of the * access to this file. Otherwise the CIFS server would * not know about the client accessing the file and could * inappropriately grant an OPLOCK. * fem_install() returns EBUSY when asked to install a * OPUNIQ monitor more than once. Therefore, check the * return code because we only want this done once. /* Place on delegation list for file */ /* Update delegation stats for this file */ /* reset since this is a new delegation */ * State routine for the server when a delegation is returned. /* nothing to do if no longer on list */ /* Remove state from recall list */ /* if file system was unshared, the vp will be NULL */ * Once a delegation is no longer held by any client, * the monitor is uninstalled. At this point, the * client must send OPEN otw, so we don't need the * reference on the vnode anymore. The open * downgrade removes the reference put on earlier. /* used in the policy decision */ * reset the time_recalled field so future delegations are not * The lock for rfs4_file_t must be held when traversing the * delegation list but that lock needs to be released to call * A delegation is assumed to be present on the file associated with * "sp". Check to see if the delegation matches is associated with * the same client as referenced by "sp". If it is not, TRUE is * returned. If the delegation DOES match the client (or no * delegation is present), return FALSE. * Assume the state entry and file entry are locked.