2 * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved.
4 * This software may be freely redistributed under the terms of the
5 * GNU General Public License.
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.
11 * Authors: David Woodhouse <dwmw2@infradead.org>
12 * David Howells <dhowells@redhat.com>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/init.h>
19 #include <linux/circ_buf.h>
20 #include <linux/sched.h>
24 * Set up an interest-in-callbacks record for a volume on a server and
25 * register it with the server.
26 * - Called with volume->server_sem held.
28 int afs_register_server_cb_interest(struct afs_vnode
*vnode
,
29 struct afs_server_entry
*entry
)
31 struct afs_cb_interest
*cbi
= entry
->cb_interest
, *vcbi
, *new, *x
;
32 struct afs_server
*server
= entry
->server
;
35 vcbi
= vnode
->cb_interest
;
40 if (cbi
&& vcbi
->server
== cbi
->server
) {
41 write_seqlock(&vnode
->cb_lock
);
42 vnode
->cb_interest
= afs_get_cb_interest(cbi
);
43 write_sequnlock(&vnode
->cb_lock
);
44 afs_put_cb_interest(afs_v2net(vnode
), cbi
);
48 if (!cbi
&& vcbi
->server
== server
) {
49 afs_get_cb_interest(vcbi
);
50 x
= cmpxchg(&entry
->cb_interest
, cbi
, vcbi
);
53 afs_put_cb_interest(afs_v2net(vnode
), vcbi
);
61 new = kzalloc(sizeof(struct afs_cb_interest
), GFP_KERNEL
);
65 refcount_set(&new->usage
, 1);
66 new->sb
= vnode
->vfs_inode
.i_sb
;
67 new->vid
= vnode
->volume
->vid
;
68 new->server
= afs_get_server(server
);
69 INIT_LIST_HEAD(&new->cb_link
);
71 write_lock(&server
->cb_break_lock
);
72 list_add_tail(&new->cb_link
, &server
->cb_interests
);
73 write_unlock(&server
->cb_break_lock
);
75 x
= cmpxchg(&entry
->cb_interest
, cbi
, new);
80 afs_put_cb_interest(afs_v2net(vnode
), new);
86 /* Change the server the vnode is using. This entails scrubbing any
87 * interest the vnode had in the previous server it was using.
89 write_seqlock(&vnode
->cb_lock
);
91 vnode
->cb_interest
= afs_get_cb_interest(cbi
);
92 vnode
->cb_s_break
= cbi
->server
->cb_s_break
;
93 clear_bit(AFS_VNODE_CB_PROMISED
, &vnode
->flags
);
95 write_sequnlock(&vnode
->cb_lock
);
100 * Set a vnode's interest on a server.
102 void afs_set_cb_interest(struct afs_vnode
*vnode
, struct afs_cb_interest
*cbi
)
104 struct afs_cb_interest
*old_cbi
= NULL
;
106 if (vnode
->cb_interest
== cbi
)
109 write_seqlock(&vnode
->cb_lock
);
110 if (vnode
->cb_interest
!= cbi
) {
111 afs_get_cb_interest(cbi
);
112 old_cbi
= vnode
->cb_interest
;
113 vnode
->cb_interest
= cbi
;
115 write_sequnlock(&vnode
->cb_lock
);
116 afs_put_cb_interest(afs_v2net(vnode
), cbi
);
120 * Remove an interest on a server.
122 void afs_put_cb_interest(struct afs_net
*net
, struct afs_cb_interest
*cbi
)
124 if (cbi
&& refcount_dec_and_test(&cbi
->usage
)) {
125 if (!list_empty(&cbi
->cb_link
)) {
126 write_lock(&cbi
->server
->cb_break_lock
);
127 list_del_init(&cbi
->cb_link
);
128 write_unlock(&cbi
->server
->cb_break_lock
);
129 afs_put_server(net
, cbi
->server
);
136 * allow the fileserver to request callback state (re-)initialisation
138 void afs_init_callback_state(struct afs_server
*server
)
140 if (!test_and_clear_bit(AFS_SERVER_FL_NEW
, &server
->flags
))
141 server
->cb_s_break
++;
145 * actually break a callback
147 void afs_break_callback(struct afs_vnode
*vnode
)
151 write_seqlock(&vnode
->cb_lock
);
153 if (test_and_clear_bit(AFS_VNODE_CB_PROMISED
, &vnode
->flags
)) {
155 afs_clear_permits(vnode
);
157 spin_lock(&vnode
->lock
);
159 _debug("break callback");
161 if (list_empty(&vnode
->granted_locks
) &&
162 !list_empty(&vnode
->pending_locks
))
163 afs_lock_may_be_available(vnode
);
164 spin_unlock(&vnode
->lock
);
167 write_sequnlock(&vnode
->cb_lock
);
171 * allow the fileserver to explicitly break one callback
173 * - the backing file is changed
174 * - a lock is released
176 static void afs_break_one_callback(struct afs_server
*server
,
179 struct afs_cb_interest
*cbi
;
180 struct afs_iget_data data
;
181 struct afs_vnode
*vnode
;
184 read_lock(&server
->cb_break_lock
);
186 /* Step through all interested superblocks. There may be more than one
187 * because of cell aliasing.
189 list_for_each_entry(cbi
, &server
->cb_interests
, cb_link
) {
190 if (cbi
->vid
!= fid
->vid
)
195 inode
= ilookup5_nowait(cbi
->sb
, fid
->vnode
, afs_iget5_test
, &data
);
197 vnode
= AFS_FS_I(inode
);
198 afs_break_callback(vnode
);
203 read_unlock(&server
->cb_break_lock
);
207 * allow the fileserver to break callback promises
209 void afs_break_callbacks(struct afs_server
*server
, size_t count
,
210 struct afs_callback callbacks
[])
212 _enter("%p,%zu,", server
, count
);
214 ASSERT(server
!= NULL
);
215 ASSERTCMP(count
, <=, AFSCBMAX
);
217 for (; count
> 0; callbacks
++, count
--) {
218 _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }",
220 callbacks
->fid
.vnode
,
221 callbacks
->fid
.unique
,
226 afs_break_one_callback(server
, &callbacks
->fid
);
234 * Clear the callback interests in a server list.
236 void afs_clear_callback_interests(struct afs_net
*net
, struct afs_server_list
*slist
)
240 for (i
= 0; i
< slist
->nr_servers
; i
++) {
241 afs_put_cb_interest(net
, slist
->servers
[i
].cb_interest
);
242 slist
->servers
[i
].cb_interest
= NULL
;