aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/afs/callback.c28
-rw-r--r--fs/afs/dir.c18
-rw-r--r--fs/afs/file.c2
-rw-r--r--fs/afs/flock.c6
-rw-r--r--fs/afs/fsclient.c2
-rw-r--r--fs/afs/inode.c13
-rw-r--r--fs/afs/internal.h15
-rw-r--r--fs/afs/security.c7
-rw-r--r--fs/afs/super.c2
-rw-r--r--fs/afs/write.c2
10 files changed, 63 insertions, 32 deletions
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index 09332945d322..571437dcb252 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -113,6 +113,7 @@ again:
113 old = vnode->cb_interest; 113 old = vnode->cb_interest;
114 vnode->cb_interest = cbi; 114 vnode->cb_interest = cbi;
115 vnode->cb_s_break = cbi->server->cb_s_break; 115 vnode->cb_s_break = cbi->server->cb_s_break;
116 vnode->cb_v_break = vnode->volume->cb_v_break;
116 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 117 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
117 118
118 write_sequnlock(&vnode->cb_lock); 119 write_sequnlock(&vnode->cb_lock);
@@ -195,13 +196,24 @@ static void afs_break_one_callback(struct afs_server *server,
195 if (cbi->vid != fid->vid) 196 if (cbi->vid != fid->vid)
196 continue; 197 continue;
197 198
198 data.volume = NULL; 199 if (fid->vnode == 0 && fid->unique == 0) {
199 data.fid = *fid; 200 /* The callback break applies to an entire volume. */
200 inode = ilookup5_nowait(cbi->sb, fid->vnode, afs_iget5_test, &data); 201 struct afs_super_info *as = AFS_FS_S(cbi->sb);
201 if (inode) { 202 struct afs_volume *volume = as->volume;
202 vnode = AFS_FS_I(inode); 203
203 afs_break_callback(vnode); 204 write_lock(&volume->cb_break_lock);
204 iput(inode); 205 volume->cb_v_break++;
206 write_unlock(&volume->cb_break_lock);
207 } else {
208 data.volume = NULL;
209 data.fid = *fid;
210 inode = ilookup5_nowait(cbi->sb, fid->vnode,
211 afs_iget5_test, &data);
212 if (inode) {
213 vnode = AFS_FS_I(inode);
214 afs_break_callback(vnode);
215 iput(inode);
216 }
205 } 217 }
206 } 218 }
207 219
@@ -219,6 +231,8 @@ void afs_break_callbacks(struct afs_server *server, size_t count,
219 ASSERT(server != NULL); 231 ASSERT(server != NULL);
220 ASSERTCMP(count, <=, AFSCBMAX); 232 ASSERTCMP(count, <=, AFSCBMAX);
221 233
234 /* TODO: Sort the callback break list by volume ID */
235
222 for (; count > 0; callbacks++, count--) { 236 for (; count > 0; callbacks++, count--) {
223 _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", 237 _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }",
224 callbacks->fid.vid, 238 callbacks->fid.vid,
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 2853acd64482..7d623008157f 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -1141,7 +1141,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1141 ret = -ERESTARTSYS; 1141 ret = -ERESTARTSYS;
1142 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1142 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1143 while (afs_select_fileserver(&fc)) { 1143 while (afs_select_fileserver(&fc)) {
1144 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1144 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
1145 afs_fs_create(&fc, dentry->d_name.name, mode, data_version, 1145 afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
1146 &newfid, &newstatus, &newcb); 1146 &newfid, &newstatus, &newcb);
1147 } 1147 }
@@ -1211,7 +1211,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
1211 ret = -ERESTARTSYS; 1211 ret = -ERESTARTSYS;
1212 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1212 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1213 while (afs_select_fileserver(&fc)) { 1213 while (afs_select_fileserver(&fc)) {
1214 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1214 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
1215 afs_fs_remove(&fc, dentry->d_name.name, true, 1215 afs_fs_remove(&fc, dentry->d_name.name, true,
1216 data_version); 1216 data_version);
1217 } 1217 }
@@ -1314,7 +1314,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1314 ret = -ERESTARTSYS; 1314 ret = -ERESTARTSYS;
1315 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1315 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1316 while (afs_select_fileserver(&fc)) { 1316 while (afs_select_fileserver(&fc)) {
1317 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1317 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
1318 afs_fs_remove(&fc, dentry->d_name.name, false, 1318 afs_fs_remove(&fc, dentry->d_name.name, false,
1319 data_version); 1319 data_version);
1320 } 1320 }
@@ -1371,7 +1371,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
1371 ret = -ERESTARTSYS; 1371 ret = -ERESTARTSYS;
1372 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1372 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1373 while (afs_select_fileserver(&fc)) { 1373 while (afs_select_fileserver(&fc)) {
1374 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1374 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
1375 afs_fs_create(&fc, dentry->d_name.name, mode, data_version, 1375 afs_fs_create(&fc, dentry->d_name.name, mode, data_version,
1376 &newfid, &newstatus, &newcb); 1376 &newfid, &newstatus, &newcb);
1377 } 1377 }
@@ -1441,8 +1441,8 @@ static int afs_link(struct dentry *from, struct inode *dir,
1441 } 1441 }
1442 1442
1443 while (afs_select_fileserver(&fc)) { 1443 while (afs_select_fileserver(&fc)) {
1444 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1444 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
1445 fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break; 1445 fc.cb_break_2 = afs_calc_vnode_cb_break(vnode);
1446 afs_fs_link(&fc, vnode, dentry->d_name.name, data_version); 1446 afs_fs_link(&fc, vnode, dentry->d_name.name, data_version);
1447 } 1447 }
1448 1448
@@ -1510,7 +1510,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
1510 ret = -ERESTARTSYS; 1510 ret = -ERESTARTSYS;
1511 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1511 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1512 while (afs_select_fileserver(&fc)) { 1512 while (afs_select_fileserver(&fc)) {
1513 fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; 1513 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
1514 afs_fs_symlink(&fc, dentry->d_name.name, 1514 afs_fs_symlink(&fc, dentry->d_name.name,
1515 content, data_version, 1515 content, data_version,
1516 &newfid, &newstatus); 1516 &newfid, &newstatus);
@@ -1586,8 +1586,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1586 } 1586 }
1587 } 1587 }
1588 while (afs_select_fileserver(&fc)) { 1588 while (afs_select_fileserver(&fc)) {
1589 fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break; 1589 fc.cb_break = afs_calc_vnode_cb_break(orig_dvnode);
1590 fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break; 1590 fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode);
1591 afs_fs_rename(&fc, old_dentry->d_name.name, 1591 afs_fs_rename(&fc, old_dentry->d_name.name,
1592 new_dvnode, new_dentry->d_name.name, 1592 new_dvnode, new_dentry->d_name.name,
1593 orig_data_version, new_data_version); 1593 orig_data_version, new_data_version);
diff --git a/fs/afs/file.c b/fs/afs/file.c
index c24c08016dd9..7d4f26198573 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -238,7 +238,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
238 ret = -ERESTARTSYS; 238 ret = -ERESTARTSYS;
239 if (afs_begin_vnode_operation(&fc, vnode, key)) { 239 if (afs_begin_vnode_operation(&fc, vnode, key)) {
240 while (afs_select_fileserver(&fc)) { 240 while (afs_select_fileserver(&fc)) {
241 fc.cb_break = vnode->cb_break + vnode->cb_s_break; 241 fc.cb_break = afs_calc_vnode_cb_break(vnode);
242 afs_fs_fetch_data(&fc, desc); 242 afs_fs_fetch_data(&fc, desc);
243 } 243 }
244 244
diff --git a/fs/afs/flock.c b/fs/afs/flock.c
index 7a0e017070ec..dc62d15a964b 100644
--- a/fs/afs/flock.c
+++ b/fs/afs/flock.c
@@ -86,7 +86,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
86 ret = -ERESTARTSYS; 86 ret = -ERESTARTSYS;
87 if (afs_begin_vnode_operation(&fc, vnode, key)) { 87 if (afs_begin_vnode_operation(&fc, vnode, key)) {
88 while (afs_select_fileserver(&fc)) { 88 while (afs_select_fileserver(&fc)) {
89 fc.cb_break = vnode->cb_break + vnode->cb_s_break; 89 fc.cb_break = afs_calc_vnode_cb_break(vnode);
90 afs_fs_set_lock(&fc, type); 90 afs_fs_set_lock(&fc, type);
91 } 91 }
92 92
@@ -117,7 +117,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key)
117 ret = -ERESTARTSYS; 117 ret = -ERESTARTSYS;
118 if (afs_begin_vnode_operation(&fc, vnode, key)) { 118 if (afs_begin_vnode_operation(&fc, vnode, key)) {
119 while (afs_select_current_fileserver(&fc)) { 119 while (afs_select_current_fileserver(&fc)) {
120 fc.cb_break = vnode->cb_break + vnode->cb_s_break; 120 fc.cb_break = afs_calc_vnode_cb_break(vnode);
121 afs_fs_extend_lock(&fc); 121 afs_fs_extend_lock(&fc);
122 } 122 }
123 123
@@ -148,7 +148,7 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key)
148 ret = -ERESTARTSYS; 148 ret = -ERESTARTSYS;
149 if (afs_begin_vnode_operation(&fc, vnode, key)) { 149 if (afs_begin_vnode_operation(&fc, vnode, key)) {
150 while (afs_select_current_fileserver(&fc)) { 150 while (afs_select_current_fileserver(&fc)) {
151 fc.cb_break = vnode->cb_break + vnode->cb_s_break; 151 fc.cb_break = afs_calc_vnode_cb_break(vnode);
152 afs_fs_release_lock(&fc); 152 afs_fs_release_lock(&fc);
153 } 153 }
154 154
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index d16f26c6cdbe..b273e1d60478 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -261,7 +261,7 @@ static void xdr_decode_AFSCallBack(struct afs_call *call,
261 261
262 write_seqlock(&vnode->cb_lock); 262 write_seqlock(&vnode->cb_lock);
263 263
264 if (call->cb_break == (vnode->cb_break + cbi->server->cb_s_break)) { 264 if (call->cb_break == afs_cb_break_sum(vnode, cbi)) {
265 vnode->cb_version = ntohl(*bp++); 265 vnode->cb_version = ntohl(*bp++);
266 cb_expiry = ntohl(*bp++); 266 cb_expiry = ntohl(*bp++);
267 vnode->cb_type = ntohl(*bp++); 267 vnode->cb_type = ntohl(*bp++);
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index e855c6e5cf28..479b7fdda124 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -108,7 +108,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
108 ret = -ERESTARTSYS; 108 ret = -ERESTARTSYS;
109 if (afs_begin_vnode_operation(&fc, vnode, key)) { 109 if (afs_begin_vnode_operation(&fc, vnode, key)) {
110 while (afs_select_fileserver(&fc)) { 110 while (afs_select_fileserver(&fc)) {
111 fc.cb_break = vnode->cb_break + vnode->cb_s_break; 111 fc.cb_break = afs_calc_vnode_cb_break(vnode);
112 afs_fs_fetch_file_status(&fc, NULL, new_inode); 112 afs_fs_fetch_file_status(&fc, NULL, new_inode);
113 } 113 }
114 114
@@ -393,15 +393,18 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
393 read_seqlock_excl(&vnode->cb_lock); 393 read_seqlock_excl(&vnode->cb_lock);
394 394
395 if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 395 if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
396 if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { 396 if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break ||
397 vnode->cb_v_break != vnode->volume->cb_v_break) {
397 vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; 398 vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
399 vnode->cb_v_break = vnode->volume->cb_v_break;
400 valid = false;
398 } else if (vnode->status.type == AFS_FTYPE_DIR && 401 } else if (vnode->status.type == AFS_FTYPE_DIR &&
399 test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) && 402 test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) &&
400 vnode->cb_expires_at - 10 > now) { 403 vnode->cb_expires_at - 10 > now) {
401 valid = true; 404 valid = true;
402 } else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && 405 } else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
403 vnode->cb_expires_at - 10 > now) { 406 vnode->cb_expires_at - 10 > now) {
404 valid = true; 407 valid = true;
405 } 408 }
406 } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 409 } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
407 valid = true; 410 valid = true;
@@ -574,7 +577,7 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
574 ret = -ERESTARTSYS; 577 ret = -ERESTARTSYS;
575 if (afs_begin_vnode_operation(&fc, vnode, key)) { 578 if (afs_begin_vnode_operation(&fc, vnode, key)) {
576 while (afs_select_fileserver(&fc)) { 579 while (afs_select_fileserver(&fc)) {
577 fc.cb_break = vnode->cb_break + vnode->cb_s_break; 580 fc.cb_break = afs_calc_vnode_cb_break(vnode);
578 afs_fs_setattr(&fc, attr); 581 afs_fs_setattr(&fc, attr);
579 } 582 }
580 583
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index e75e57e13320..e3f8a46663db 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -461,6 +461,9 @@ struct afs_volume {
461 rwlock_t servers_lock; /* Lock for ->servers */ 461 rwlock_t servers_lock; /* Lock for ->servers */
462 unsigned int servers_seq; /* Incremented each time ->servers changes */ 462 unsigned int servers_seq; /* Incremented each time ->servers changes */
463 463
464 unsigned cb_v_break; /* Break-everything counter. */
465 rwlock_t cb_break_lock;
466
464 afs_voltype_t type; /* type of volume */ 467 afs_voltype_t type; /* type of volume */
465 short error; 468 short error;
466 char type_force; /* force volume type (suppress R/O -> R/W) */ 469 char type_force; /* force volume type (suppress R/O -> R/W) */
@@ -521,6 +524,7 @@ struct afs_vnode {
521 /* outstanding callback notification on this file */ 524 /* outstanding callback notification on this file */
522 struct afs_cb_interest *cb_interest; /* Server on which this resides */ 525 struct afs_cb_interest *cb_interest; /* Server on which this resides */
523 unsigned int cb_s_break; /* Mass break counter on ->server */ 526 unsigned int cb_s_break; /* Mass break counter on ->server */
527 unsigned int cb_v_break; /* Mass break counter on ->volume */
524 unsigned int cb_break; /* Break counter on vnode */ 528 unsigned int cb_break; /* Break counter on vnode */
525 seqlock_t cb_lock; /* Lock for ->cb_interest, ->status, ->cb_*break */ 529 seqlock_t cb_lock; /* Lock for ->cb_interest, ->status, ->cb_*break */
526 530
@@ -662,6 +666,17 @@ static inline struct afs_cb_interest *afs_get_cb_interest(struct afs_cb_interest
662 return cbi; 666 return cbi;
663} 667}
664 668
669static inline unsigned int afs_calc_vnode_cb_break(struct afs_vnode *vnode)
670{
671 return vnode->cb_break + vnode->cb_s_break + vnode->cb_v_break;
672}
673
674static inline unsigned int afs_cb_break_sum(struct afs_vnode *vnode,
675 struct afs_cb_interest *cbi)
676{
677 return vnode->cb_break + cbi->server->cb_s_break + vnode->volume->cb_v_break;
678}
679
665/* 680/*
666 * cell.c 681 * cell.c
667 */ 682 */
diff --git a/fs/afs/security.c b/fs/afs/security.c
index cea2fff313dc..1992b0ffa543 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -147,8 +147,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
147 break; 147 break;
148 } 148 }
149 149
150 if (cb_break != (vnode->cb_break + 150 if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest)) {
151 vnode->cb_interest->server->cb_s_break)) {
152 changed = true; 151 changed = true;
153 break; 152 break;
154 } 153 }
@@ -178,7 +177,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
178 } 177 }
179 } 178 }
180 179
181 if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break)) 180 if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest))
182 goto someone_else_changed_it; 181 goto someone_else_changed_it;
183 182
184 /* We need a ref on any permits list we want to copy as we'll have to 183 /* We need a ref on any permits list we want to copy as we'll have to
@@ -257,7 +256,7 @@ found:
257 256
258 spin_lock(&vnode->lock); 257 spin_lock(&vnode->lock);
259 zap = rcu_access_pointer(vnode->permit_cache); 258 zap = rcu_access_pointer(vnode->permit_cache);
260 if (cb_break == (vnode->cb_break + vnode->cb_interest->server->cb_s_break) && 259 if (cb_break == afs_cb_break_sum(vnode, vnode->cb_interest) &&
261 zap == permits) 260 zap == permits)
262 rcu_assign_pointer(vnode->permit_cache, replacement); 261 rcu_assign_pointer(vnode->permit_cache, replacement);
263 else 262 else
diff --git a/fs/afs/super.c b/fs/afs/super.c
index b02838cd9525..9e5d7966621c 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -688,7 +688,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
688 if (afs_begin_vnode_operation(&fc, vnode, key)) { 688 if (afs_begin_vnode_operation(&fc, vnode, key)) {
689 fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; 689 fc.flags |= AFS_FS_CURSOR_NO_VSLEEP;
690 while (afs_select_fileserver(&fc)) { 690 while (afs_select_fileserver(&fc)) {
691 fc.cb_break = vnode->cb_break + vnode->cb_s_break; 691 fc.cb_break = afs_calc_vnode_cb_break(vnode);
692 afs_fs_get_volume_status(&fc, &vs); 692 afs_fs_get_volume_status(&fc, &vs);
693 } 693 }
694 694
diff --git a/fs/afs/write.c b/fs/afs/write.c
index c164698dc304..8b39e6ebb40b 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -351,7 +351,7 @@ found_key:
351 ret = -ERESTARTSYS; 351 ret = -ERESTARTSYS;
352 if (afs_begin_vnode_operation(&fc, vnode, wbk->key)) { 352 if (afs_begin_vnode_operation(&fc, vnode, wbk->key)) {
353 while (afs_select_fileserver(&fc)) { 353 while (afs_select_fileserver(&fc)) {
354 fc.cb_break = vnode->cb_break + vnode->cb_s_break; 354 fc.cb_break = afs_calc_vnode_cb_break(vnode);
355 afs_fs_store_data(&fc, mapping, first, last, offset, to); 355 afs_fs_store_data(&fc, mapping, first, last, offset, to);
356 } 356 }
357 357