| /* |
| * Copyright (c) 2002 Red Hat, Inc. All rights reserved. |
| * |
| * This software may be freely redistributed under the terms of the |
| * GNU General Public License. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| * |
| * Authors: David Woodhouse <dwmw2@cambridge.redhat.com> |
| * David Howells <dhowells@redhat.com> |
| * |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/init.h> |
| #include "server.h" |
| #include "vnode.h" |
| #include "internal.h" |
| #include "cmservice.h" |
| |
| /*****************************************************************************/ |
| /* |
| * allow the fileserver to request callback state (re-)initialisation |
| */ |
| int SRXAFSCM_InitCallBackState(struct afs_server *server) |
| { |
| struct list_head callbacks; |
| |
| _enter("%p", server); |
| |
| INIT_LIST_HEAD(&callbacks); |
| |
| /* transfer the callback list from the server to a temp holding area */ |
| spin_lock(&server->cb_lock); |
| |
| list_add(&callbacks, &server->cb_promises); |
| list_del_init(&server->cb_promises); |
| |
| /* munch our way through the list, grabbing the inode, dropping all the |
| * locks and regetting them in the right order |
| */ |
| while (!list_empty(&callbacks)) { |
| struct afs_vnode *vnode; |
| struct inode *inode; |
| |
| vnode = list_entry(callbacks.next, struct afs_vnode, cb_link); |
| list_del_init(&vnode->cb_link); |
| |
| /* try and grab the inode - may fail */ |
| inode = igrab(AFS_VNODE_TO_I(vnode)); |
| if (inode) { |
| int release = 0; |
| |
| spin_unlock(&server->cb_lock); |
| spin_lock(&vnode->lock); |
| |
| if (vnode->cb_server == server) { |
| vnode->cb_server = NULL; |
| afs_kafstimod_del_timer(&vnode->cb_timeout); |
| spin_lock(&afs_cb_hash_lock); |
| list_del_init(&vnode->cb_hash_link); |
| spin_unlock(&afs_cb_hash_lock); |
| release = 1; |
| } |
| |
| spin_unlock(&vnode->lock); |
| |
| iput(inode); |
| afs_put_server(server); |
| |
| spin_lock(&server->cb_lock); |
| } |
| } |
| |
| spin_unlock(&server->cb_lock); |
| |
| _leave(" = 0"); |
| return 0; |
| } /* end SRXAFSCM_InitCallBackState() */ |
| |
| /*****************************************************************************/ |
| /* |
| * allow the fileserver to break callback promises |
| */ |
| int SRXAFSCM_CallBack(struct afs_server *server, size_t count, |
| struct afs_callback callbacks[]) |
| { |
| _enter("%p,%u,", server, count); |
| |
| for (; count > 0; callbacks++, count--) { |
| struct afs_vnode *vnode = NULL; |
| struct inode *inode = NULL; |
| int valid = 0; |
| |
| _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", |
| callbacks->fid.vid, |
| callbacks->fid.vnode, |
| callbacks->fid.unique, |
| callbacks->version, |
| callbacks->expiry, |
| callbacks->type |
| ); |
| |
| /* find the inode for this fid */ |
| spin_lock(&afs_cb_hash_lock); |
| |
| list_for_each_entry(vnode, |
| &afs_cb_hash(server, &callbacks->fid), |
| cb_hash_link) { |
| if (memcmp(&vnode->fid, &callbacks->fid, |
| sizeof(struct afs_fid)) != 0) |
| continue; |
| |
| /* right vnode, but is it same server? */ |
| if (vnode->cb_server != server) |
| break; /* no */ |
| |
| /* try and nail the inode down */ |
| inode = igrab(AFS_VNODE_TO_I(vnode)); |
| break; |
| } |
| |
| spin_unlock(&afs_cb_hash_lock); |
| |
| if (inode) { |
| /* we've found the record for this vnode */ |
| spin_lock(&vnode->lock); |
| if (vnode->cb_server == server) { |
| /* the callback _is_ on the calling server */ |
| vnode->cb_server = NULL; |
| valid = 1; |
| |
| afs_kafstimod_del_timer(&vnode->cb_timeout); |
| vnode->flags |= AFS_VNODE_CHANGED; |
| |
| spin_lock(&server->cb_lock); |
| list_del_init(&vnode->cb_link); |
| spin_unlock(&server->cb_lock); |
| |
| spin_lock(&afs_cb_hash_lock); |
| list_del_init(&vnode->cb_hash_link); |
| spin_unlock(&afs_cb_hash_lock); |
| } |
| spin_unlock(&vnode->lock); |
| |
| if (valid) { |
| invalidate_remote_inode(inode); |
| afs_put_server(server); |
| } |
| iput(inode); |
| } |
| } |
| |
| _leave(" = 0"); |
| return 0; |
| } /* end SRXAFSCM_CallBack() */ |
| |
| /*****************************************************************************/ |
| /* |
| * allow the fileserver to see if the cache manager is still alive |
| */ |
| int SRXAFSCM_Probe(struct afs_server *server) |
| { |
| _debug("SRXAFSCM_Probe(%p)\n", server); |
| return 0; |
| } /* end SRXAFSCM_Probe() */ |