diff options
author | David Howells <dhowells@redhat.com> | 2007-05-11 01:22:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-11 11:29:32 -0400 |
commit | 45222b9e02fb282eb0a8007a3d992dd229ec2410 (patch) | |
tree | 2160228a23c700437bda0898d3a700ac499b941d /fs | |
parent | 0f300ca9284caabdd2c07c7f91b90f1f530f614e (diff) |
AFS: implement statfs
Implement the statfs() op for AFS.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/afs/afs.h | 23 | ||||
-rw-r--r-- | fs/afs/afs_fs.h | 3 | ||||
-rw-r--r-- | fs/afs/dir.c | 18 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 298 | ||||
-rw-r--r-- | fs/afs/internal.h | 6 | ||||
-rw-r--r-- | fs/afs/super.c | 41 | ||||
-rw-r--r-- | fs/afs/vnode.c | 52 |
7 files changed, 426 insertions, 15 deletions
diff --git a/fs/afs/afs.h b/fs/afs/afs.h index 52d0752265b8..245257948140 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h | |||
@@ -16,6 +16,9 @@ | |||
16 | 16 | ||
17 | #define AFS_MAXCELLNAME 64 /* maximum length of a cell name */ | 17 | #define AFS_MAXCELLNAME 64 /* maximum length of a cell name */ |
18 | #define AFS_MAXVOLNAME 64 /* maximum length of a volume name */ | 18 | #define AFS_MAXVOLNAME 64 /* maximum length of a volume name */ |
19 | #define AFSNAMEMAX 256 /* maximum length of a filename plus NUL */ | ||
20 | #define AFSPATHMAX 1024 /* maximum length of a pathname plus NUL */ | ||
21 | #define AFSOPAQUEMAX 1024 /* maximum length of an opaque field */ | ||
19 | 22 | ||
20 | typedef unsigned afs_volid_t; | 23 | typedef unsigned afs_volid_t; |
21 | typedef unsigned afs_vnodeid_t; | 24 | typedef unsigned afs_vnodeid_t; |
@@ -143,4 +146,24 @@ struct afs_volsync { | |||
143 | time_t creation; /* volume creation time */ | 146 | time_t creation; /* volume creation time */ |
144 | }; | 147 | }; |
145 | 148 | ||
149 | /* | ||
150 | * AFS volume status record | ||
151 | */ | ||
152 | struct afs_volume_status { | ||
153 | u32 vid; /* volume ID */ | ||
154 | u32 parent_id; /* parent volume ID */ | ||
155 | u8 online; /* true if volume currently online and available */ | ||
156 | u8 in_service; /* true if volume currently in service */ | ||
157 | u8 blessed; /* same as in_service */ | ||
158 | u8 needs_salvage; /* true if consistency checking required */ | ||
159 | u32 type; /* volume type (afs_voltype_t) */ | ||
160 | u32 min_quota; /* minimum space set aside (blocks) */ | ||
161 | u32 max_quota; /* maximum space this volume may occupy (blocks) */ | ||
162 | u32 blocks_in_use; /* space this volume currently occupies (blocks) */ | ||
163 | u32 part_blocks_avail; /* space available in volume's partition */ | ||
164 | u32 part_max_blocks; /* size of volume's partition */ | ||
165 | }; | ||
166 | |||
167 | #define AFS_BLOCK_SIZE 1024 | ||
168 | |||
146 | #endif /* AFS_H */ | 169 | #endif /* AFS_H */ |
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h index d963ef4daee8..a18c374ebe08 100644 --- a/fs/afs/afs_fs.h +++ b/fs/afs/afs_fs.h | |||
@@ -28,7 +28,8 @@ enum AFS_FS_Operations { | |||
28 | FSMAKEDIR = 141, /* AFS Create a directory */ | 28 | FSMAKEDIR = 141, /* AFS Create a directory */ |
29 | FSREMOVEDIR = 142, /* AFS Remove a directory */ | 29 | FSREMOVEDIR = 142, /* AFS Remove a directory */ |
30 | FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */ | 30 | FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */ |
31 | FSGETVOLUMEINFO = 148, /* AFS Get root volume information */ | 31 | FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */ |
32 | FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */ | ||
32 | FSGETROOTVOLUME = 151, /* AFS Get root volume name */ | 33 | FSGETROOTVOLUME = 151, /* AFS Get root volume name */ |
33 | FSLOOKUP = 161, /* AFS lookup file in directory */ | 34 | FSLOOKUP = 161, /* AFS lookup file in directory */ |
34 | FSFETCHDATA64 = 65537, /* AFS Fetch file data */ | 35 | FSFETCHDATA64 = 65537, /* AFS Fetch file data */ |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 2fb31276196b..719af4fb15dc 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -497,7 +497,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
497 | 497 | ||
498 | ASSERTCMP(dentry->d_inode, ==, NULL); | 498 | ASSERTCMP(dentry->d_inode, ==, NULL); |
499 | 499 | ||
500 | if (dentry->d_name.len > 255) { | 500 | if (dentry->d_name.len >= AFSNAMEMAX) { |
501 | _leave(" = -ENAMETOOLONG"); | 501 | _leave(" = -ENAMETOOLONG"); |
502 | return ERR_PTR(-ENAMETOOLONG); | 502 | return ERR_PTR(-ENAMETOOLONG); |
503 | } | 503 | } |
@@ -736,7 +736,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
736 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | 736 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); |
737 | 737 | ||
738 | ret = -ENAMETOOLONG; | 738 | ret = -ENAMETOOLONG; |
739 | if (dentry->d_name.len > 255) | 739 | if (dentry->d_name.len >= AFSNAMEMAX) |
740 | goto error; | 740 | goto error; |
741 | 741 | ||
742 | key = afs_request_key(dvnode->volume->cell); | 742 | key = afs_request_key(dvnode->volume->cell); |
@@ -801,7 +801,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
801 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | 801 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); |
802 | 802 | ||
803 | ret = -ENAMETOOLONG; | 803 | ret = -ENAMETOOLONG; |
804 | if (dentry->d_name.len > 255) | 804 | if (dentry->d_name.len >= AFSNAMEMAX) |
805 | goto error; | 805 | goto error; |
806 | 806 | ||
807 | key = afs_request_key(dvnode->volume->cell); | 807 | key = afs_request_key(dvnode->volume->cell); |
@@ -847,7 +847,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
847 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | 847 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); |
848 | 848 | ||
849 | ret = -ENAMETOOLONG; | 849 | ret = -ENAMETOOLONG; |
850 | if (dentry->d_name.len > 255) | 850 | if (dentry->d_name.len >= AFSNAMEMAX) |
851 | goto error; | 851 | goto error; |
852 | 852 | ||
853 | key = afs_request_key(dvnode->volume->cell); | 853 | key = afs_request_key(dvnode->volume->cell); |
@@ -921,7 +921,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
921 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | 921 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); |
922 | 922 | ||
923 | ret = -ENAMETOOLONG; | 923 | ret = -ENAMETOOLONG; |
924 | if (dentry->d_name.len > 255) | 924 | if (dentry->d_name.len >= AFSNAMEMAX) |
925 | goto error; | 925 | goto error; |
926 | 926 | ||
927 | key = afs_request_key(dvnode->volume->cell); | 927 | key = afs_request_key(dvnode->volume->cell); |
@@ -990,7 +990,7 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
990 | dentry->d_name.name); | 990 | dentry->d_name.name); |
991 | 991 | ||
992 | ret = -ENAMETOOLONG; | 992 | ret = -ENAMETOOLONG; |
993 | if (dentry->d_name.len > 255) | 993 | if (dentry->d_name.len >= AFSNAMEMAX) |
994 | goto error; | 994 | goto error; |
995 | 995 | ||
996 | key = afs_request_key(dvnode->volume->cell); | 996 | key = afs_request_key(dvnode->volume->cell); |
@@ -1038,11 +1038,11 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1038 | content); | 1038 | content); |
1039 | 1039 | ||
1040 | ret = -ENAMETOOLONG; | 1040 | ret = -ENAMETOOLONG; |
1041 | if (dentry->d_name.len > 255) | 1041 | if (dentry->d_name.len >= AFSNAMEMAX) |
1042 | goto error; | 1042 | goto error; |
1043 | 1043 | ||
1044 | ret = -EINVAL; | 1044 | ret = -EINVAL; |
1045 | if (strlen(content) > 1023) | 1045 | if (strlen(content) >= AFSPATHMAX) |
1046 | goto error; | 1046 | goto error; |
1047 | 1047 | ||
1048 | key = afs_request_key(dvnode->volume->cell); | 1048 | key = afs_request_key(dvnode->volume->cell); |
@@ -1112,7 +1112,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1112 | new_dentry->d_name.name); | 1112 | new_dentry->d_name.name); |
1113 | 1113 | ||
1114 | ret = -ENAMETOOLONG; | 1114 | ret = -ENAMETOOLONG; |
1115 | if (new_dentry->d_name.len > 255) | 1115 | if (new_dentry->d_name.len >= AFSNAMEMAX) |
1116 | goto error; | 1116 | goto error; |
1117 | 1117 | ||
1118 | key = afs_request_key(orig_dvnode->volume->cell); | 1118 | key = afs_request_key(orig_dvnode->volume->cell); |
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 56cc0efa2a0c..5dff1308b6f0 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -202,6 +202,29 @@ static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) | |||
202 | } | 202 | } |
203 | 203 | ||
204 | /* | 204 | /* |
205 | * decode an AFSFetchVolumeStatus block | ||
206 | */ | ||
207 | static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, | ||
208 | struct afs_volume_status *vs) | ||
209 | { | ||
210 | const __be32 *bp = *_bp; | ||
211 | |||
212 | vs->vid = ntohl(*bp++); | ||
213 | vs->parent_id = ntohl(*bp++); | ||
214 | vs->online = ntohl(*bp++); | ||
215 | vs->in_service = ntohl(*bp++); | ||
216 | vs->blessed = ntohl(*bp++); | ||
217 | vs->needs_salvage = ntohl(*bp++); | ||
218 | vs->type = ntohl(*bp++); | ||
219 | vs->min_quota = ntohl(*bp++); | ||
220 | vs->max_quota = ntohl(*bp++); | ||
221 | vs->blocks_in_use = ntohl(*bp++); | ||
222 | vs->part_blocks_avail = ntohl(*bp++); | ||
223 | vs->part_max_blocks = ntohl(*bp++); | ||
224 | *_bp = bp; | ||
225 | } | ||
226 | |||
227 | /* | ||
205 | * deliver reply data to an FS.FetchStatus | 228 | * deliver reply data to an FS.FetchStatus |
206 | */ | 229 | */ |
207 | static int afs_deliver_fs_fetch_status(struct afs_call *call, | 230 | static int afs_deliver_fs_fetch_status(struct afs_call *call, |
@@ -1450,3 +1473,278 @@ int afs_fs_setattr(struct afs_server *server, struct key *key, | |||
1450 | 1473 | ||
1451 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 1474 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
1452 | } | 1475 | } |
1476 | |||
1477 | /* | ||
1478 | * deliver reply data to an FS.GetVolumeStatus | ||
1479 | */ | ||
1480 | static int afs_deliver_fs_get_volume_status(struct afs_call *call, | ||
1481 | struct sk_buff *skb, bool last) | ||
1482 | { | ||
1483 | const __be32 *bp; | ||
1484 | char *p; | ||
1485 | int ret; | ||
1486 | |||
1487 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | ||
1488 | |||
1489 | switch (call->unmarshall) { | ||
1490 | case 0: | ||
1491 | call->offset = 0; | ||
1492 | call->unmarshall++; | ||
1493 | |||
1494 | /* extract the returned status record */ | ||
1495 | case 1: | ||
1496 | _debug("extract status"); | ||
1497 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
1498 | 12 * 4); | ||
1499 | switch (ret) { | ||
1500 | case 0: break; | ||
1501 | case -EAGAIN: return 0; | ||
1502 | default: return ret; | ||
1503 | } | ||
1504 | |||
1505 | bp = call->buffer; | ||
1506 | xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2); | ||
1507 | call->offset = 0; | ||
1508 | call->unmarshall++; | ||
1509 | |||
1510 | /* extract the volume name length */ | ||
1511 | case 2: | ||
1512 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
1513 | switch (ret) { | ||
1514 | case 0: break; | ||
1515 | case -EAGAIN: return 0; | ||
1516 | default: return ret; | ||
1517 | } | ||
1518 | |||
1519 | call->count = ntohl(call->tmp); | ||
1520 | _debug("volname length: %u", call->count); | ||
1521 | if (call->count >= AFSNAMEMAX) | ||
1522 | return -EBADMSG; | ||
1523 | call->offset = 0; | ||
1524 | call->unmarshall++; | ||
1525 | |||
1526 | /* extract the volume name */ | ||
1527 | case 3: | ||
1528 | _debug("extract volname"); | ||
1529 | if (call->count > 0) { | ||
1530 | ret = afs_extract_data(call, skb, last, call->reply3, | ||
1531 | call->count); | ||
1532 | switch (ret) { | ||
1533 | case 0: break; | ||
1534 | case -EAGAIN: return 0; | ||
1535 | default: return ret; | ||
1536 | } | ||
1537 | } | ||
1538 | |||
1539 | p = call->reply3; | ||
1540 | p[call->count] = 0; | ||
1541 | _debug("volname '%s'", p); | ||
1542 | |||
1543 | call->offset = 0; | ||
1544 | call->unmarshall++; | ||
1545 | |||
1546 | /* extract the volume name padding */ | ||
1547 | if ((call->count & 3) == 0) { | ||
1548 | call->unmarshall++; | ||
1549 | goto no_volname_padding; | ||
1550 | } | ||
1551 | call->count = 4 - (call->count & 3); | ||
1552 | |||
1553 | case 4: | ||
1554 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
1555 | call->count); | ||
1556 | switch (ret) { | ||
1557 | case 0: break; | ||
1558 | case -EAGAIN: return 0; | ||
1559 | default: return ret; | ||
1560 | } | ||
1561 | |||
1562 | call->offset = 0; | ||
1563 | call->unmarshall++; | ||
1564 | no_volname_padding: | ||
1565 | |||
1566 | /* extract the offline message length */ | ||
1567 | case 5: | ||
1568 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
1569 | switch (ret) { | ||
1570 | case 0: break; | ||
1571 | case -EAGAIN: return 0; | ||
1572 | default: return ret; | ||
1573 | } | ||
1574 | |||
1575 | call->count = ntohl(call->tmp); | ||
1576 | _debug("offline msg length: %u", call->count); | ||
1577 | if (call->count >= AFSNAMEMAX) | ||
1578 | return -EBADMSG; | ||
1579 | call->offset = 0; | ||
1580 | call->unmarshall++; | ||
1581 | |||
1582 | /* extract the offline message */ | ||
1583 | case 6: | ||
1584 | _debug("extract offline"); | ||
1585 | if (call->count > 0) { | ||
1586 | ret = afs_extract_data(call, skb, last, call->reply3, | ||
1587 | call->count); | ||
1588 | switch (ret) { | ||
1589 | case 0: break; | ||
1590 | case -EAGAIN: return 0; | ||
1591 | default: return ret; | ||
1592 | } | ||
1593 | } | ||
1594 | |||
1595 | p = call->reply3; | ||
1596 | p[call->count] = 0; | ||
1597 | _debug("offline '%s'", p); | ||
1598 | |||
1599 | call->offset = 0; | ||
1600 | call->unmarshall++; | ||
1601 | |||
1602 | /* extract the offline message padding */ | ||
1603 | if ((call->count & 3) == 0) { | ||
1604 | call->unmarshall++; | ||
1605 | goto no_offline_padding; | ||
1606 | } | ||
1607 | call->count = 4 - (call->count & 3); | ||
1608 | |||
1609 | case 7: | ||
1610 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
1611 | call->count); | ||
1612 | switch (ret) { | ||
1613 | case 0: break; | ||
1614 | case -EAGAIN: return 0; | ||
1615 | default: return ret; | ||
1616 | } | ||
1617 | |||
1618 | call->offset = 0; | ||
1619 | call->unmarshall++; | ||
1620 | no_offline_padding: | ||
1621 | |||
1622 | /* extract the message of the day length */ | ||
1623 | case 8: | ||
1624 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
1625 | switch (ret) { | ||
1626 | case 0: break; | ||
1627 | case -EAGAIN: return 0; | ||
1628 | default: return ret; | ||
1629 | } | ||
1630 | |||
1631 | call->count = ntohl(call->tmp); | ||
1632 | _debug("motd length: %u", call->count); | ||
1633 | if (call->count >= AFSNAMEMAX) | ||
1634 | return -EBADMSG; | ||
1635 | call->offset = 0; | ||
1636 | call->unmarshall++; | ||
1637 | |||
1638 | /* extract the message of the day */ | ||
1639 | case 9: | ||
1640 | _debug("extract motd"); | ||
1641 | if (call->count > 0) { | ||
1642 | ret = afs_extract_data(call, skb, last, call->reply3, | ||
1643 | call->count); | ||
1644 | switch (ret) { | ||
1645 | case 0: break; | ||
1646 | case -EAGAIN: return 0; | ||
1647 | default: return ret; | ||
1648 | } | ||
1649 | } | ||
1650 | |||
1651 | p = call->reply3; | ||
1652 | p[call->count] = 0; | ||
1653 | _debug("motd '%s'", p); | ||
1654 | |||
1655 | call->offset = 0; | ||
1656 | call->unmarshall++; | ||
1657 | |||
1658 | /* extract the message of the day padding */ | ||
1659 | if ((call->count & 3) == 0) { | ||
1660 | call->unmarshall++; | ||
1661 | goto no_motd_padding; | ||
1662 | } | ||
1663 | call->count = 4 - (call->count & 3); | ||
1664 | |||
1665 | case 10: | ||
1666 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
1667 | call->count); | ||
1668 | switch (ret) { | ||
1669 | case 0: break; | ||
1670 | case -EAGAIN: return 0; | ||
1671 | default: return ret; | ||
1672 | } | ||
1673 | |||
1674 | call->offset = 0; | ||
1675 | call->unmarshall++; | ||
1676 | no_motd_padding: | ||
1677 | |||
1678 | case 11: | ||
1679 | _debug("trailer %d", skb->len); | ||
1680 | if (skb->len != 0) | ||
1681 | return -EBADMSG; | ||
1682 | break; | ||
1683 | } | ||
1684 | |||
1685 | if (!last) | ||
1686 | return 0; | ||
1687 | |||
1688 | _leave(" = 0 [done]"); | ||
1689 | return 0; | ||
1690 | } | ||
1691 | |||
1692 | /* | ||
1693 | * destroy an FS.GetVolumeStatus call | ||
1694 | */ | ||
1695 | static void afs_get_volume_status_call_destructor(struct afs_call *call) | ||
1696 | { | ||
1697 | kfree(call->reply3); | ||
1698 | call->reply3 = NULL; | ||
1699 | afs_flat_call_destructor(call); | ||
1700 | } | ||
1701 | |||
1702 | /* | ||
1703 | * FS.GetVolumeStatus operation type | ||
1704 | */ | ||
1705 | static const struct afs_call_type afs_RXFSGetVolumeStatus = { | ||
1706 | .name = "FS.GetVolumeStatus", | ||
1707 | .deliver = afs_deliver_fs_get_volume_status, | ||
1708 | .abort_to_error = afs_abort_to_error, | ||
1709 | .destructor = afs_get_volume_status_call_destructor, | ||
1710 | }; | ||
1711 | |||
1712 | /* | ||
1713 | * fetch the status of a volume | ||
1714 | */ | ||
1715 | int afs_fs_get_volume_status(struct afs_server *server, | ||
1716 | struct key *key, | ||
1717 | struct afs_vnode *vnode, | ||
1718 | struct afs_volume_status *vs, | ||
1719 | const struct afs_wait_mode *wait_mode) | ||
1720 | { | ||
1721 | struct afs_call *call; | ||
1722 | __be32 *bp; | ||
1723 | void *tmpbuf; | ||
1724 | |||
1725 | _enter(""); | ||
1726 | |||
1727 | tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); | ||
1728 | if (!tmpbuf) | ||
1729 | return -ENOMEM; | ||
1730 | |||
1731 | call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); | ||
1732 | if (!call) { | ||
1733 | kfree(tmpbuf); | ||
1734 | return -ENOMEM; | ||
1735 | } | ||
1736 | |||
1737 | call->key = key; | ||
1738 | call->reply = vnode; | ||
1739 | call->reply2 = vs; | ||
1740 | call->reply3 = tmpbuf; | ||
1741 | call->service_id = FS_SERVICE; | ||
1742 | call->port = htons(AFS_FS_PORT); | ||
1743 | |||
1744 | /* marshall the parameters */ | ||
1745 | bp = call->request; | ||
1746 | bp[0] = htonl(FSGETVOLUMESTATUS); | ||
1747 | bp[1] = htonl(vnode->fid.vid); | ||
1748 | |||
1749 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
1750 | } | ||
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index a30d4fa768e3..4953ba5a6f44 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -506,6 +506,10 @@ extern int afs_fs_store_data(struct afs_server *, struct afs_writeback *, | |||
506 | extern int afs_fs_setattr(struct afs_server *, struct key *, | 506 | extern int afs_fs_setattr(struct afs_server *, struct key *, |
507 | struct afs_vnode *, struct iattr *, | 507 | struct afs_vnode *, struct iattr *, |
508 | const struct afs_wait_mode *); | 508 | const struct afs_wait_mode *); |
509 | extern int afs_fs_get_volume_status(struct afs_server *, struct key *, | ||
510 | struct afs_vnode *, | ||
511 | struct afs_volume_status *, | ||
512 | const struct afs_wait_mode *); | ||
509 | 513 | ||
510 | /* | 514 | /* |
511 | * inode.c | 515 | * inode.c |
@@ -672,6 +676,8 @@ extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *, | |||
672 | extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t, | 676 | extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t, |
673 | unsigned, unsigned); | 677 | unsigned, unsigned); |
674 | extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *); | 678 | extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *); |
679 | extern int afs_vnode_get_volume_status(struct afs_vnode *, struct key *, | ||
680 | struct afs_volume_status *); | ||
675 | 681 | ||
676 | /* | 682 | /* |
677 | * volume.c | 683 | * volume.c |
diff --git a/fs/afs/super.c b/fs/afs/super.c index 422f532b9b62..579af632c8e8 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -21,22 +21,20 @@ | |||
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/pagemap.h> | 22 | #include <linux/pagemap.h> |
23 | #include <linux/parser.h> | 23 | #include <linux/parser.h> |
24 | #include <linux/statfs.h> | ||
24 | #include "internal.h" | 25 | #include "internal.h" |
25 | 26 | ||
26 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ | 27 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ |
27 | 28 | ||
28 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, | 29 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, |
29 | unsigned long flags); | 30 | unsigned long flags); |
30 | |||
31 | static int afs_get_sb(struct file_system_type *fs_type, | 31 | static int afs_get_sb(struct file_system_type *fs_type, |
32 | int flags, const char *dev_name, | 32 | int flags, const char *dev_name, |
33 | void *data, struct vfsmount *mnt); | 33 | void *data, struct vfsmount *mnt); |
34 | |||
35 | static struct inode *afs_alloc_inode(struct super_block *sb); | 34 | static struct inode *afs_alloc_inode(struct super_block *sb); |
36 | |||
37 | static void afs_put_super(struct super_block *sb); | 35 | static void afs_put_super(struct super_block *sb); |
38 | |||
39 | static void afs_destroy_inode(struct inode *inode); | 36 | static void afs_destroy_inode(struct inode *inode); |
37 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); | ||
40 | 38 | ||
41 | struct file_system_type afs_fs_type = { | 39 | struct file_system_type afs_fs_type = { |
42 | .owner = THIS_MODULE, | 40 | .owner = THIS_MODULE, |
@@ -47,7 +45,7 @@ struct file_system_type afs_fs_type = { | |||
47 | }; | 45 | }; |
48 | 46 | ||
49 | static const struct super_operations afs_super_ops = { | 47 | static const struct super_operations afs_super_ops = { |
50 | .statfs = simple_statfs, | 48 | .statfs = afs_statfs, |
51 | .alloc_inode = afs_alloc_inode, | 49 | .alloc_inode = afs_alloc_inode, |
52 | .drop_inode = generic_delete_inode, | 50 | .drop_inode = generic_delete_inode, |
53 | .write_inode = afs_write_inode, | 51 | .write_inode = afs_write_inode, |
@@ -508,3 +506,36 @@ static void afs_destroy_inode(struct inode *inode) | |||
508 | kmem_cache_free(afs_inode_cachep, vnode); | 506 | kmem_cache_free(afs_inode_cachep, vnode); |
509 | atomic_dec(&afs_count_active_inodes); | 507 | atomic_dec(&afs_count_active_inodes); |
510 | } | 508 | } |
509 | |||
510 | /* | ||
511 | * return information about an AFS volume | ||
512 | */ | ||
513 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) | ||
514 | { | ||
515 | struct afs_volume_status vs; | ||
516 | struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); | ||
517 | struct key *key; | ||
518 | int ret; | ||
519 | |||
520 | key = afs_request_key(vnode->volume->cell); | ||
521 | if (IS_ERR(key)) | ||
522 | return PTR_ERR(key); | ||
523 | |||
524 | ret = afs_vnode_get_volume_status(vnode, key, &vs); | ||
525 | key_put(key); | ||
526 | if (ret < 0) { | ||
527 | _leave(" = %d", ret); | ||
528 | return ret; | ||
529 | } | ||
530 | |||
531 | buf->f_type = dentry->d_sb->s_magic; | ||
532 | buf->f_bsize = AFS_BLOCK_SIZE; | ||
533 | buf->f_namelen = AFSNAMEMAX - 1; | ||
534 | |||
535 | if (vs.max_quota == 0) | ||
536 | buf->f_blocks = vs.part_max_blocks; | ||
537 | else | ||
538 | buf->f_blocks = vs.max_quota; | ||
539 | buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use; | ||
540 | return 0; | ||
541 | } | ||
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index bea8bd9e7b2a..c36c98ce2c3c 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c | |||
@@ -869,3 +869,55 @@ no_server: | |||
869 | spin_unlock(&vnode->lock); | 869 | spin_unlock(&vnode->lock); |
870 | return PTR_ERR(server); | 870 | return PTR_ERR(server); |
871 | } | 871 | } |
872 | |||
873 | /* | ||
874 | * get the status of a volume | ||
875 | */ | ||
876 | int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key, | ||
877 | struct afs_volume_status *vs) | ||
878 | { | ||
879 | struct afs_server *server; | ||
880 | int ret; | ||
881 | |||
882 | _enter("%s{%x:%u.%u},%x,", | ||
883 | vnode->volume->vlocation->vldb.name, | ||
884 | vnode->fid.vid, | ||
885 | vnode->fid.vnode, | ||
886 | vnode->fid.unique, | ||
887 | key_serial(key)); | ||
888 | |||
889 | /* this op will fetch the status */ | ||
890 | spin_lock(&vnode->lock); | ||
891 | vnode->update_cnt++; | ||
892 | spin_unlock(&vnode->lock); | ||
893 | |||
894 | do { | ||
895 | /* pick a server to query */ | ||
896 | server = afs_volume_pick_fileserver(vnode); | ||
897 | if (IS_ERR(server)) | ||
898 | goto no_server; | ||
899 | |||
900 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
901 | |||
902 | ret = afs_fs_get_volume_status(server, key, vnode, vs, &afs_sync_call); | ||
903 | |||
904 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
905 | |||
906 | /* adjust the flags */ | ||
907 | if (ret == 0) { | ||
908 | afs_vnode_finalise_status_update(vnode, server); | ||
909 | afs_put_server(server); | ||
910 | } else { | ||
911 | afs_vnode_status_update_failed(vnode, ret); | ||
912 | } | ||
913 | |||
914 | _leave(" = %d", ret); | ||
915 | return ret; | ||
916 | |||
917 | no_server: | ||
918 | spin_lock(&vnode->lock); | ||
919 | vnode->update_cnt--; | ||
920 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
921 | spin_unlock(&vnode->lock); | ||
922 | return PTR_ERR(server); | ||
923 | } | ||