[PATCH] knfsd: Allow lockd to drop replies as appropriate
[pandora-kernel.git] / fs / afs / callback.c
1 /*
2  * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
3  *
4  * This software may be freely redistributed under the terms of the
5  * GNU General Public License.
6  *
7  * You should have received a copy of the GNU General Public License
8  * along with this program; if not, write to the Free Software
9  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
10  *
11  * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
12  *          David Howells <dhowells@redhat.com>
13  *
14  */
15
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/init.h>
19 #include "server.h"
20 #include "vnode.h"
21 #include "internal.h"
22 #include "cmservice.h"
23
24 /*****************************************************************************/
25 /*
26  * allow the fileserver to request callback state (re-)initialisation
27  */
28 int SRXAFSCM_InitCallBackState(struct afs_server *server)
29 {
30         struct list_head callbacks;
31
32         _enter("%p", server);
33
34         INIT_LIST_HEAD(&callbacks);
35
36         /* transfer the callback list from the server to a temp holding area */
37         spin_lock(&server->cb_lock);
38
39         list_add(&callbacks, &server->cb_promises);
40         list_del_init(&server->cb_promises);
41
42         /* munch our way through the list, grabbing the inode, dropping all the
43          * locks and regetting them in the right order
44          */
45         while (!list_empty(&callbacks)) {
46                 struct afs_vnode *vnode;
47                 struct inode *inode;
48
49                 vnode = list_entry(callbacks.next, struct afs_vnode, cb_link);
50                 list_del_init(&vnode->cb_link);
51
52                 /* try and grab the inode - may fail */
53                 inode = igrab(AFS_VNODE_TO_I(vnode));
54                 if (inode) {
55                         int release = 0;
56
57                         spin_unlock(&server->cb_lock);
58                         spin_lock(&vnode->lock);
59
60                         if (vnode->cb_server == server) {
61                                 vnode->cb_server = NULL;
62                                 afs_kafstimod_del_timer(&vnode->cb_timeout);
63                                 spin_lock(&afs_cb_hash_lock);
64                                 list_del_init(&vnode->cb_hash_link);
65                                 spin_unlock(&afs_cb_hash_lock);
66                                 release = 1;
67                         }
68
69                         spin_unlock(&vnode->lock);
70
71                         iput(inode);
72                         afs_put_server(server);
73
74                         spin_lock(&server->cb_lock);
75                 }
76         }
77
78         spin_unlock(&server->cb_lock);
79
80         _leave(" = 0");
81         return 0;
82 } /* end SRXAFSCM_InitCallBackState() */
83
84 /*****************************************************************************/
85 /*
86  * allow the fileserver to break callback promises
87  */
88 int SRXAFSCM_CallBack(struct afs_server *server, size_t count,
89                       struct afs_callback callbacks[])
90 {
91         _enter("%p,%u,", server, count);
92
93         for (; count > 0; callbacks++, count--) {
94                 struct afs_vnode *vnode = NULL;
95                 struct inode *inode = NULL;
96                 int valid = 0;
97
98                 _debug("- Fid { vl=%08x n=%u u=%u }  CB { v=%u x=%u t=%u }",
99                        callbacks->fid.vid,
100                        callbacks->fid.vnode,
101                        callbacks->fid.unique,
102                        callbacks->version,
103                        callbacks->expiry,
104                        callbacks->type
105                        );
106
107                 /* find the inode for this fid */
108                 spin_lock(&afs_cb_hash_lock);
109
110                 list_for_each_entry(vnode,
111                                     &afs_cb_hash(server, &callbacks->fid),
112                                     cb_hash_link) {
113                         if (memcmp(&vnode->fid, &callbacks->fid,
114                                    sizeof(struct afs_fid)) != 0)
115                                 continue;
116
117                         /* right vnode, but is it same server? */
118                         if (vnode->cb_server != server)
119                                 break; /* no */
120
121                         /* try and nail the inode down */
122                         inode = igrab(AFS_VNODE_TO_I(vnode));
123                         break;
124                 }
125
126                 spin_unlock(&afs_cb_hash_lock);
127
128                 if (inode) {
129                         /* we've found the record for this vnode */
130                         spin_lock(&vnode->lock);
131                         if (vnode->cb_server == server) {
132                                 /* the callback _is_ on the calling server */
133                                 vnode->cb_server = NULL;
134                                 valid = 1;
135
136                                 afs_kafstimod_del_timer(&vnode->cb_timeout);
137                                 vnode->flags |= AFS_VNODE_CHANGED;
138
139                                 spin_lock(&server->cb_lock);
140                                 list_del_init(&vnode->cb_link);
141                                 spin_unlock(&server->cb_lock);
142
143                                 spin_lock(&afs_cb_hash_lock);
144                                 list_del_init(&vnode->cb_hash_link);
145                                 spin_unlock(&afs_cb_hash_lock);
146                         }
147                         spin_unlock(&vnode->lock);
148
149                         if (valid) {
150                                 invalidate_remote_inode(inode);
151                                 afs_put_server(server);
152                         }
153                         iput(inode);
154                 }
155         }
156
157         _leave(" = 0");
158         return 0;
159 } /* end SRXAFSCM_CallBack() */
160
161 /*****************************************************************************/
162 /*
163  * allow the fileserver to see if the cache manager is still alive
164  */
165 int SRXAFSCM_Probe(struct afs_server *server)
166 {
167         _debug("SRXAFSCM_Probe(%p)\n", server);
168         return 0;
169 } /* end SRXAFSCM_Probe() */