diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-16 17:33:25 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-29 11:35:49 -0400 |
commit | c654b8a9cba6002aad1c01919e4928a79a4a6dcf (patch) | |
tree | fee411bb42ec86e72a9e843529551e559c1f2749 /fs/nfsd | |
parent | 3352d2c2d0540955a7bbb3421a28330af7f9d79c (diff) |
nfsd: support ext4 i_version
ext4 supports a real NFSv4 change attribute, which is bumped whenever
the ctime would be updated, including times when two updates arrive
within a jiffy of each other. (Note that although ext4 has space for
nanosecond-precision ctime, the real resolution is lower: it actually
uses jiffies as the time-source.) This ensures clients will invalidate
their caches when they need to.
There is some fear that keeping the i_version up-to-date could have
performance drawbacks, so for now it's turned on only by a mount option.
We hope to do something better eventually.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Cc: Theodore Tso <tytso@mit.edu>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 63 |
2 files changed, 43 insertions, 21 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 17d0dd997204..01d4ec1c88e0 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -272,6 +272,7 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
272 | 272 | ||
273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, | 273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, |
274 | &fhp->fh_post_attr); | 274 | &fhp->fh_post_attr); |
275 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; | ||
275 | if (err) | 276 | if (err) |
276 | fhp->fh_post_saved = 0; | 277 | fhp->fh_post_saved = 0; |
277 | else | 278 | else |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4a71fcd3f036..12d36a7361cd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1490,13 +1490,41 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1490 | memcpy(p, ptr, nbytes); \ | 1490 | memcpy(p, ptr, nbytes); \ |
1491 | p += XDR_QUADLEN(nbytes); \ | 1491 | p += XDR_QUADLEN(nbytes); \ |
1492 | }} while (0) | 1492 | }} while (0) |
1493 | #define WRITECINFO(c) do { \ | 1493 | |
1494 | *p++ = htonl(c.atomic); \ | 1494 | static void write32(__be32 **p, u32 n) |
1495 | *p++ = htonl(c.before_ctime_sec); \ | 1495 | { |
1496 | *p++ = htonl(c.before_ctime_nsec); \ | 1496 | *(*p)++ = n; |
1497 | *p++ = htonl(c.after_ctime_sec); \ | 1497 | } |
1498 | *p++ = htonl(c.after_ctime_nsec); \ | 1498 | |
1499 | } while (0) | 1499 | static void write64(__be32 **p, u64 n) |
1500 | { | ||
1501 | write32(p, (u32)(n >> 32)); | ||
1502 | write32(p, (u32)n); | ||
1503 | } | ||
1504 | |||
1505 | static void write_change(__be32 **p, struct kstat *stat, struct inode *inode) | ||
1506 | { | ||
1507 | if (IS_I_VERSION(inode)) { | ||
1508 | write64(p, inode->i_version); | ||
1509 | } else { | ||
1510 | write32(p, stat->ctime.tv_sec); | ||
1511 | write32(p, stat->ctime.tv_nsec); | ||
1512 | } | ||
1513 | } | ||
1514 | |||
1515 | static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) | ||
1516 | { | ||
1517 | write32(p, c->atomic); | ||
1518 | if (c->change_supported) { | ||
1519 | write64(p, c->before_change); | ||
1520 | write64(p, c->after_change); | ||
1521 | } else { | ||
1522 | write32(p, c->before_ctime_sec); | ||
1523 | write32(p, c->before_ctime_nsec); | ||
1524 | write32(p, c->after_ctime_sec); | ||
1525 | write32(p, c->after_ctime_nsec); | ||
1526 | } | ||
1527 | } | ||
1500 | 1528 | ||
1501 | #define RESERVE_SPACE(nbytes) do { \ | 1529 | #define RESERVE_SPACE(nbytes) do { \ |
1502 | p = resp->p; \ | 1530 | p = resp->p; \ |
@@ -1849,16 +1877,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1849 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); | 1877 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); |
1850 | } | 1878 | } |
1851 | if (bmval0 & FATTR4_WORD0_CHANGE) { | 1879 | if (bmval0 & FATTR4_WORD0_CHANGE) { |
1852 | /* | ||
1853 | * Note: This _must_ be consistent with the scheme for writing | ||
1854 | * change_info, so any changes made here must be reflected there | ||
1855 | * as well. (See xdr4.h:set_change_info() and the WRITECINFO() | ||
1856 | * macro above.) | ||
1857 | */ | ||
1858 | if ((buflen -= 8) < 0) | 1880 | if ((buflen -= 8) < 0) |
1859 | goto out_resource; | 1881 | goto out_resource; |
1860 | WRITE32(stat.ctime.tv_sec); | 1882 | write_change(&p, &stat, dentry->d_inode); |
1861 | WRITE32(stat.ctime.tv_nsec); | ||
1862 | } | 1883 | } |
1863 | if (bmval0 & FATTR4_WORD0_SIZE) { | 1884 | if (bmval0 & FATTR4_WORD0_SIZE) { |
1864 | if ((buflen -= 8) < 0) | 1885 | if ((buflen -= 8) < 0) |
@@ -2364,7 +2385,7 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2364 | 2385 | ||
2365 | if (!nfserr) { | 2386 | if (!nfserr) { |
2366 | RESERVE_SPACE(32); | 2387 | RESERVE_SPACE(32); |
2367 | WRITECINFO(create->cr_cinfo); | 2388 | write_cinfo(&p, &create->cr_cinfo); |
2368 | WRITE32(2); | 2389 | WRITE32(2); |
2369 | WRITE32(create->cr_bmval[0]); | 2390 | WRITE32(create->cr_bmval[0]); |
2370 | WRITE32(create->cr_bmval[1]); | 2391 | WRITE32(create->cr_bmval[1]); |
@@ -2475,7 +2496,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li | |||
2475 | 2496 | ||
2476 | if (!nfserr) { | 2497 | if (!nfserr) { |
2477 | RESERVE_SPACE(20); | 2498 | RESERVE_SPACE(20); |
2478 | WRITECINFO(link->li_cinfo); | 2499 | write_cinfo(&p, &link->li_cinfo); |
2479 | ADJUST_ARGS(); | 2500 | ADJUST_ARGS(); |
2480 | } | 2501 | } |
2481 | return nfserr; | 2502 | return nfserr; |
@@ -2493,7 +2514,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op | |||
2493 | 2514 | ||
2494 | nfsd4_encode_stateid(resp, &open->op_stateid); | 2515 | nfsd4_encode_stateid(resp, &open->op_stateid); |
2495 | RESERVE_SPACE(40); | 2516 | RESERVE_SPACE(40); |
2496 | WRITECINFO(open->op_cinfo); | 2517 | write_cinfo(&p, &open->op_cinfo); |
2497 | WRITE32(open->op_rflags); | 2518 | WRITE32(open->op_rflags); |
2498 | WRITE32(2); | 2519 | WRITE32(2); |
2499 | WRITE32(open->op_bmval[0]); | 2520 | WRITE32(open->op_bmval[0]); |
@@ -2771,7 +2792,7 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2771 | 2792 | ||
2772 | if (!nfserr) { | 2793 | if (!nfserr) { |
2773 | RESERVE_SPACE(20); | 2794 | RESERVE_SPACE(20); |
2774 | WRITECINFO(remove->rm_cinfo); | 2795 | write_cinfo(&p, &remove->rm_cinfo); |
2775 | ADJUST_ARGS(); | 2796 | ADJUST_ARGS(); |
2776 | } | 2797 | } |
2777 | return nfserr; | 2798 | return nfserr; |
@@ -2784,8 +2805,8 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2784 | 2805 | ||
2785 | if (!nfserr) { | 2806 | if (!nfserr) { |
2786 | RESERVE_SPACE(40); | 2807 | RESERVE_SPACE(40); |
2787 | WRITECINFO(rename->rn_sinfo); | 2808 | write_cinfo(&p, &rename->rn_sinfo); |
2788 | WRITECINFO(rename->rn_tinfo); | 2809 | write_cinfo(&p, &rename->rn_tinfo); |
2789 | ADJUST_ARGS(); | 2810 | ADJUST_ARGS(); |
2790 | } | 2811 | } |
2791 | return nfserr; | 2812 | return nfserr; |