diff options
| -rw-r--r-- | fs/ceph/mds_client.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 79743d146be6..0c1d91756528 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
| @@ -1438,12 +1438,15 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, | |||
| 1438 | struct dentry *temp; | 1438 | struct dentry *temp; |
| 1439 | char *path; | 1439 | char *path; |
| 1440 | int len, pos; | 1440 | int len, pos; |
| 1441 | unsigned seq; | ||
| 1441 | 1442 | ||
| 1442 | if (dentry == NULL) | 1443 | if (dentry == NULL) |
| 1443 | return ERR_PTR(-EINVAL); | 1444 | return ERR_PTR(-EINVAL); |
| 1444 | 1445 | ||
| 1445 | retry: | 1446 | retry: |
| 1446 | len = 0; | 1447 | len = 0; |
| 1448 | seq = read_seqbegin(&rename_lock); | ||
| 1449 | rcu_read_lock(); | ||
| 1447 | for (temp = dentry; !IS_ROOT(temp);) { | 1450 | for (temp = dentry; !IS_ROOT(temp);) { |
| 1448 | struct inode *inode = temp->d_inode; | 1451 | struct inode *inode = temp->d_inode; |
| 1449 | if (inode && ceph_snap(inode) == CEPH_SNAPDIR) | 1452 | if (inode && ceph_snap(inode) == CEPH_SNAPDIR) |
| @@ -1455,10 +1458,12 @@ retry: | |||
| 1455 | len += 1 + temp->d_name.len; | 1458 | len += 1 + temp->d_name.len; |
| 1456 | temp = temp->d_parent; | 1459 | temp = temp->d_parent; |
| 1457 | if (temp == NULL) { | 1460 | if (temp == NULL) { |
| 1461 | rcu_read_unlock(); | ||
| 1458 | pr_err("build_path corrupt dentry %p\n", dentry); | 1462 | pr_err("build_path corrupt dentry %p\n", dentry); |
| 1459 | return ERR_PTR(-EINVAL); | 1463 | return ERR_PTR(-EINVAL); |
| 1460 | } | 1464 | } |
| 1461 | } | 1465 | } |
| 1466 | rcu_read_unlock(); | ||
| 1462 | if (len) | 1467 | if (len) |
| 1463 | len--; /* no leading '/' */ | 1468 | len--; /* no leading '/' */ |
| 1464 | 1469 | ||
| @@ -1467,9 +1472,12 @@ retry: | |||
| 1467 | return ERR_PTR(-ENOMEM); | 1472 | return ERR_PTR(-ENOMEM); |
| 1468 | pos = len; | 1473 | pos = len; |
| 1469 | path[pos] = 0; /* trailing null */ | 1474 | path[pos] = 0; /* trailing null */ |
| 1475 | rcu_read_lock(); | ||
| 1470 | for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) { | 1476 | for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) { |
| 1471 | struct inode *inode = temp->d_inode; | 1477 | struct inode *inode; |
| 1472 | 1478 | ||
| 1479 | spin_lock(&temp->d_lock); | ||
| 1480 | inode = temp->d_inode; | ||
| 1473 | if (inode && ceph_snap(inode) == CEPH_SNAPDIR) { | 1481 | if (inode && ceph_snap(inode) == CEPH_SNAPDIR) { |
| 1474 | dout("build_path path+%d: %p SNAPDIR\n", | 1482 | dout("build_path path+%d: %p SNAPDIR\n", |
| 1475 | pos, temp); | 1483 | pos, temp); |
| @@ -1478,21 +1486,26 @@ retry: | |||
| 1478 | break; | 1486 | break; |
| 1479 | } else { | 1487 | } else { |
| 1480 | pos -= temp->d_name.len; | 1488 | pos -= temp->d_name.len; |
| 1481 | if (pos < 0) | 1489 | if (pos < 0) { |
| 1490 | spin_unlock(&temp->d_lock); | ||
| 1482 | break; | 1491 | break; |
| 1492 | } | ||
| 1483 | strncpy(path + pos, temp->d_name.name, | 1493 | strncpy(path + pos, temp->d_name.name, |
| 1484 | temp->d_name.len); | 1494 | temp->d_name.len); |
| 1485 | } | 1495 | } |
| 1496 | spin_unlock(&temp->d_lock); | ||
| 1486 | if (pos) | 1497 | if (pos) |
| 1487 | path[--pos] = '/'; | 1498 | path[--pos] = '/'; |
| 1488 | temp = temp->d_parent; | 1499 | temp = temp->d_parent; |
| 1489 | if (temp == NULL) { | 1500 | if (temp == NULL) { |
| 1501 | rcu_read_unlock(); | ||
| 1490 | pr_err("build_path corrupt dentry\n"); | 1502 | pr_err("build_path corrupt dentry\n"); |
| 1491 | kfree(path); | 1503 | kfree(path); |
| 1492 | return ERR_PTR(-EINVAL); | 1504 | return ERR_PTR(-EINVAL); |
| 1493 | } | 1505 | } |
| 1494 | } | 1506 | } |
| 1495 | if (pos != 0) { | 1507 | rcu_read_unlock(); |
| 1508 | if (pos != 0 || read_seqretry(&rename_lock, seq)) { | ||
| 1496 | pr_err("build_path did not end path lookup where " | 1509 | pr_err("build_path did not end path lookup where " |
| 1497 | "expected, namelen is %d, pos is %d\n", len, pos); | 1510 | "expected, namelen is %d, pos is %d\n", len, pos); |
| 1498 | /* presumably this is only possible if racing with a | 1511 | /* presumably this is only possible if racing with a |
