Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

afs: Pass pre-fetch server and volume break counts into afs_iget5_set()

Pass the server and volume break counts from before the status fetch
operation that queried the attributes of a file into afs_iget5_set() so
that the new vnode's break counters can be initialised appropriately.

This allows detection of a volume or server break that happened whilst we
were fetching the status or setting up the vnode.

Fixes: c435ee34551e ("afs: Overhaul the callback handling")
Signed-off-by: David Howells <dhowells@redhat.com>

+78 -49
+38 -20
fs/afs/dir.c
··· 641 641 struct afs_cb_interest *dcbi, *cbi = NULL; 642 642 struct afs_super_info *as = dir->i_sb->s_fs_info; 643 643 struct afs_status_cb *scb; 644 - struct afs_iget_data data; 644 + struct afs_iget_data iget_data; 645 645 struct afs_fs_cursor fc; 646 646 struct afs_server *server; 647 647 struct afs_vnode *dvnode = AFS_FS_I(dir); ··· 684 684 goto out; 685 685 686 686 /* Check to see if we already have an inode for the primary fid. */ 687 - data.volume = dvnode->volume; 688 - data.fid = cookie->fids[0]; 689 - inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, afs_iget5_test, &data); 687 + iget_data.fid = cookie->fids[0]; 688 + iget_data.volume = dvnode->volume; 689 + iget_data.cb_v_break = dvnode->volume->cb_v_break; 690 + iget_data.cb_s_break = 0; 691 + inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, 692 + afs_iget5_test, &iget_data); 690 693 if (inode) 691 694 goto out; 692 695 ··· 716 713 fc.ac.error = -ECONNABORTED; 717 714 break; 718 715 } 716 + iget_data.cb_v_break = dvnode->volume->cb_v_break; 717 + iget_data.cb_s_break = fc.cbi->server->cb_s_break; 719 718 afs_fs_inline_bulk_status(&fc, 720 719 afs_v2net(dvnode), 721 720 cookie->fids, ··· 746 741 inode = ERR_PTR(-ERESTARTSYS); 747 742 if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { 748 743 while (afs_select_fileserver(&fc)) { 744 + iget_data.cb_v_break = dvnode->volume->cb_v_break; 745 + iget_data.cb_s_break = fc.cbi->server->cb_s_break; 749 746 scb = &cookie->statuses[0]; 750 747 afs_fs_fetch_status(&fc, 751 748 afs_v2net(dvnode), ··· 782 775 if (scb->status.abort_code != 0) 783 776 continue; 784 777 785 - ti = afs_iget(dir->i_sb, key, &cookie->fids[i], 786 - scb, cbi, dvnode); 778 + iget_data.fid = cookie->fids[i]; 779 + ti = afs_iget(dir->i_sb, key, &iget_data, scb, cbi, dvnode); 787 780 if (i == 0) { 788 781 inode = ti; 789 782 } else { ··· 1119 1112 */ 1120 1113 static void afs_vnode_new_inode(struct afs_fs_cursor *fc, 1121 1114 struct dentry *new_dentry, 1122 - struct afs_fid *newfid, 1115 + struct afs_iget_data *new_data, 1123 1116 struct afs_status_cb *new_scb) 1124 1117 { 1125 1118 struct afs_vnode *vnode; ··· 1129 1122 return; 1130 1123 1131 1124 inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key, 1132 - newfid, new_scb, fc->cbi, fc->vnode); 1125 + new_data, new_scb, fc->cbi, fc->vnode); 1133 1126 if (IS_ERR(inode)) { 1134 1127 /* ENOMEM or EINTR at a really inconvenient time - just abandon 1135 1128 * the new directory on the server. ··· 1145 1138 d_instantiate(new_dentry, inode); 1146 1139 } 1147 1140 1141 + static void afs_prep_for_new_inode(struct afs_fs_cursor *fc, 1142 + struct afs_iget_data *iget_data) 1143 + { 1144 + iget_data->volume = fc->vnode->volume; 1145 + iget_data->cb_v_break = fc->vnode->volume->cb_v_break; 1146 + iget_data->cb_s_break = fc->cbi->server->cb_s_break; 1147 + } 1148 + 1148 1149 /* 1149 1150 * create a directory on an AFS filesystem 1150 1151 */ 1151 1152 static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 1152 1153 { 1154 + struct afs_iget_data iget_data; 1153 1155 struct afs_status_cb *scb; 1154 1156 struct afs_fs_cursor fc; 1155 1157 struct afs_vnode *dvnode = AFS_FS_I(dir); 1156 - struct afs_fid newfid; 1157 1158 struct key *key; 1158 1159 int ret; 1159 1160 ··· 1187 1172 1188 1173 while (afs_select_fileserver(&fc)) { 1189 1174 fc.cb_break = afs_calc_vnode_cb_break(dvnode); 1175 + afs_prep_for_new_inode(&fc, &iget_data); 1190 1176 afs_fs_create(&fc, dentry->d_name.name, mode, 1191 - &scb[0], &newfid, &scb[1]); 1177 + &scb[0], &iget_data.fid, &scb[1]); 1192 1178 } 1193 1179 1194 1180 afs_check_for_remote_deletion(&fc, dvnode); 1195 1181 afs_vnode_commit_status(&fc, dvnode, fc.cb_break, 1196 1182 &data_version, &scb[0]); 1197 - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); 1183 + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); 1198 1184 ret = afs_end_vnode_operation(&fc); 1199 1185 if (ret < 0) 1200 1186 goto error_key; ··· 1205 1189 1206 1190 if (ret == 0 && 1207 1191 test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 1208 - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, 1192 + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, 1209 1193 afs_edit_dir_for_create); 1210 1194 1211 1195 key_put(key); ··· 1455 1439 static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 1456 1440 bool excl) 1457 1441 { 1442 + struct afs_iget_data iget_data; 1458 1443 struct afs_fs_cursor fc; 1459 1444 struct afs_status_cb *scb; 1460 1445 struct afs_vnode *dvnode = AFS_FS_I(dir); 1461 - struct afs_fid newfid; 1462 1446 struct key *key; 1463 1447 int ret; 1464 1448 ··· 1488 1472 1489 1473 while (afs_select_fileserver(&fc)) { 1490 1474 fc.cb_break = afs_calc_vnode_cb_break(dvnode); 1475 + afs_prep_for_new_inode(&fc, &iget_data); 1491 1476 afs_fs_create(&fc, dentry->d_name.name, mode, 1492 - &scb[0], &newfid, &scb[1]); 1477 + &scb[0], &iget_data.fid, &scb[1]); 1493 1478 } 1494 1479 1495 1480 afs_check_for_remote_deletion(&fc, dvnode); 1496 1481 afs_vnode_commit_status(&fc, dvnode, fc.cb_break, 1497 1482 &data_version, &scb[0]); 1498 - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); 1483 + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); 1499 1484 ret = afs_end_vnode_operation(&fc); 1500 1485 if (ret < 0) 1501 1486 goto error_key; ··· 1505 1488 } 1506 1489 1507 1490 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 1508 - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, 1491 + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, 1509 1492 afs_edit_dir_for_create); 1510 1493 1511 1494 kfree(scb); ··· 1612 1595 static int afs_symlink(struct inode *dir, struct dentry *dentry, 1613 1596 const char *content) 1614 1597 { 1598 + struct afs_iget_data iget_data; 1615 1599 struct afs_fs_cursor fc; 1616 1600 struct afs_status_cb *scb; 1617 1601 struct afs_vnode *dvnode = AFS_FS_I(dir); 1618 - struct afs_fid newfid; 1619 1602 struct key *key; 1620 1603 int ret; 1621 1604 ··· 1648 1631 1649 1632 while (afs_select_fileserver(&fc)) { 1650 1633 fc.cb_break = afs_calc_vnode_cb_break(dvnode); 1634 + afs_prep_for_new_inode(&fc, &iget_data); 1651 1635 afs_fs_symlink(&fc, dentry->d_name.name, content, 1652 - &scb[0], &newfid, &scb[1]); 1636 + &scb[0], &iget_data.fid, &scb[1]); 1653 1637 } 1654 1638 1655 1639 afs_check_for_remote_deletion(&fc, dvnode); 1656 1640 afs_vnode_commit_status(&fc, dvnode, fc.cb_break, 1657 1641 &data_version, &scb[0]); 1658 - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); 1642 + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); 1659 1643 ret = afs_end_vnode_operation(&fc); 1660 1644 if (ret < 0) 1661 1645 goto error_key; ··· 1665 1647 } 1666 1648 1667 1649 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 1668 - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, 1650 + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, 1669 1651 afs_edit_dir_for_symlink); 1670 1652 1671 1653 key_put(key);
+29 -22
fs/afs/inode.c
··· 347 347 */ 348 348 int afs_iget5_test(struct inode *inode, void *opaque) 349 349 { 350 - struct afs_iget_data *data = opaque; 350 + struct afs_iget_data *iget_data = opaque; 351 351 struct afs_vnode *vnode = AFS_FS_I(inode); 352 352 353 - return memcmp(&vnode->fid, &data->fid, sizeof(data->fid)) == 0; 353 + return memcmp(&vnode->fid, &iget_data->fid, sizeof(iget_data->fid)) == 0; 354 354 } 355 355 356 356 /* ··· 368 368 */ 369 369 static int afs_iget5_set(struct inode *inode, void *opaque) 370 370 { 371 - struct afs_iget_data *data = opaque; 371 + struct afs_iget_data *iget_data = opaque; 372 372 struct afs_vnode *vnode = AFS_FS_I(inode); 373 373 374 - vnode->fid = data->fid; 375 - vnode->volume = data->volume; 374 + vnode->fid = iget_data->fid; 375 + vnode->volume = iget_data->volume; 376 + vnode->cb_v_break = iget_data->cb_v_break; 377 + vnode->cb_s_break = iget_data->cb_s_break; 376 378 377 379 /* YFS supports 96-bit vnode IDs, but Linux only supports 378 380 * 64-bit inode numbers. 379 381 */ 380 - inode->i_ino = data->fid.vnode; 381 - inode->i_generation = data->fid.unique; 382 + inode->i_ino = iget_data->fid.vnode; 383 + inode->i_generation = iget_data->fid.unique; 382 384 return 0; 383 385 } 384 386 ··· 390 388 */ 391 389 struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) 392 390 { 393 - struct afs_iget_data data; 394 391 struct afs_super_info *as; 395 392 struct afs_vnode *vnode; 396 393 struct inode *inode; 397 394 static atomic_t afs_autocell_ino; 398 395 396 + struct afs_iget_data iget_data = { 397 + .cb_v_break = 0, 398 + .cb_s_break = 0, 399 + }; 400 + 399 401 _enter(""); 400 402 401 403 as = sb->s_fs_info; 402 404 if (as->volume) { 403 - data.volume = as->volume; 404 - data.fid.vid = as->volume->vid; 405 + iget_data.volume = as->volume; 406 + iget_data.fid.vid = as->volume->vid; 405 407 } 406 408 if (root) { 407 - data.fid.vnode = 1; 408 - data.fid.unique = 1; 409 + iget_data.fid.vnode = 1; 410 + iget_data.fid.unique = 1; 409 411 } else { 410 - data.fid.vnode = atomic_inc_return(&afs_autocell_ino); 411 - data.fid.unique = 0; 412 + iget_data.fid.vnode = atomic_inc_return(&afs_autocell_ino); 413 + iget_data.fid.unique = 0; 412 414 } 413 415 414 - inode = iget5_locked(sb, data.fid.vnode, 416 + inode = iget5_locked(sb, iget_data.fid.vnode, 415 417 afs_iget5_pseudo_dir_test, afs_iget5_set, 416 - &data); 418 + &iget_data); 417 419 if (!inode) { 418 420 _leave(" = -ENOMEM"); 419 421 return ERR_PTR(-ENOMEM); 420 422 } 421 423 422 424 _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }", 423 - inode, inode->i_ino, data.fid.vid, data.fid.vnode, 424 - data.fid.unique); 425 + inode, inode->i_ino, iget_data.fid.vid, iget_data.fid.vnode, 426 + iget_data.fid.unique); 425 427 426 428 vnode = AFS_FS_I(inode); 427 429 ··· 496 490 * inode retrieval 497 491 */ 498 492 struct inode *afs_iget(struct super_block *sb, struct key *key, 499 - struct afs_fid *fid, struct afs_status_cb *scb, 493 + struct afs_iget_data *iget_data, 494 + struct afs_status_cb *scb, 500 495 struct afs_cb_interest *cbi, 501 496 struct afs_vnode *parent_vnode) 502 497 { 503 - struct afs_iget_data data = { .fid = *fid }; 504 498 struct afs_super_info *as; 505 499 struct afs_vnode *vnode; 500 + struct afs_fid *fid = &iget_data->fid; 506 501 struct inode *inode; 507 502 int ret; 508 503 509 504 _enter(",{%llx:%llu.%u},,", fid->vid, fid->vnode, fid->unique); 510 505 511 506 as = sb->s_fs_info; 512 - data.volume = as->volume; 507 + iget_data->volume = as->volume; 513 508 514 509 inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set, 515 - &data); 510 + iget_data); 516 511 if (!inode) { 517 512 _leave(" = -ENOMEM"); 518 513 return ERR_PTR(-ENOMEM);
+3 -1
fs/afs/internal.h
··· 66 66 struct afs_iget_data { 67 67 struct afs_fid fid; 68 68 struct afs_volume *volume; /* volume on which resides */ 69 + unsigned int cb_v_break; /* Pre-fetch volume break count */ 70 + unsigned int cb_s_break; /* Pre-fetch server break count */ 69 71 }; 70 72 71 73 enum afs_call_state { ··· 1025 1023 extern int afs_iget5_test(struct inode *, void *); 1026 1024 extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool); 1027 1025 extern struct inode *afs_iget(struct super_block *, struct key *, 1028 - struct afs_fid *, struct afs_status_cb *, 1026 + struct afs_iget_data *, struct afs_status_cb *, 1029 1027 struct afs_cb_interest *, 1030 1028 struct afs_vnode *); 1031 1029 extern void afs_zap_data(struct afs_vnode *);
+8 -6
fs/afs/super.c
··· 426 426 static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) 427 427 { 428 428 struct afs_super_info *as = AFS_FS_S(sb); 429 - struct afs_fid fid; 429 + struct afs_iget_data iget_data; 430 430 struct inode *inode = NULL; 431 431 int ret; 432 432 ··· 451 451 } else { 452 452 sprintf(sb->s_id, "%llu", as->volume->vid); 453 453 afs_activate_volume(as->volume); 454 - fid.vid = as->volume->vid; 455 - fid.vnode = 1; 456 - fid.vnode_hi = 0; 457 - fid.unique = 1; 458 - inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL); 454 + iget_data.fid.vid = as->volume->vid; 455 + iget_data.fid.vnode = 1; 456 + iget_data.fid.vnode_hi = 0; 457 + iget_data.fid.unique = 1; 458 + iget_data.cb_v_break = as->volume->cb_v_break; 459 + iget_data.cb_s_break = 0; 460 + inode = afs_iget(sb, ctx->key, &iget_data, NULL, NULL, NULL); 459 461 } 460 462 461 463 if (IS_ERR(inode))