diff options
Diffstat (limited to 'fs/nfsd/nfsproc.c')
-rw-r--r-- | fs/nfsd/nfsproc.c | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index aecbcd34d336..44f6f4f5eee0 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -59,13 +59,59 @@ static __be32 | |||
59 | nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, | 59 | nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, |
60 | struct nfsd_attrstat *resp) | 60 | struct nfsd_attrstat *resp) |
61 | { | 61 | { |
62 | struct iattr *iap = &argp->attrs; | ||
63 | struct svc_fh *fhp; | ||
62 | __be32 nfserr; | 64 | __be32 nfserr; |
65 | |||
63 | dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", | 66 | dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", |
64 | SVCFH_fmt(&argp->fh), | 67 | SVCFH_fmt(&argp->fh), |
65 | argp->attrs.ia_valid, (long) argp->attrs.ia_size); | 68 | argp->attrs.ia_valid, (long) argp->attrs.ia_size); |
66 | 69 | ||
67 | fh_copy(&resp->fh, &argp->fh); | 70 | fhp = fh_copy(&resp->fh, &argp->fh); |
68 | nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0); | 71 | |
72 | /* | ||
73 | * NFSv2 does not differentiate between "set-[ac]time-to-now" | ||
74 | * which only requires access, and "set-[ac]time-to-X" which | ||
75 | * requires ownership. | ||
76 | * So if it looks like it might be "set both to the same time which | ||
77 | * is close to now", and if setattr_prepare fails, then we | ||
78 | * convert to "set to now" instead of "set to explicit time" | ||
79 | * | ||
80 | * We only call setattr_prepare as the last test as technically | ||
81 | * it is not an interface that we should be using. | ||
82 | */ | ||
83 | #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) | ||
84 | #define MAX_TOUCH_TIME_ERROR (30*60) | ||
85 | if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && | ||
86 | iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { | ||
87 | /* | ||
88 | * Looks probable. | ||
89 | * | ||
90 | * Now just make sure time is in the right ballpark. | ||
91 | * Solaris, at least, doesn't seem to care what the time | ||
92 | * request is. We require it be within 30 minutes of now. | ||
93 | */ | ||
94 | time_t delta = iap->ia_atime.tv_sec - get_seconds(); | ||
95 | |||
96 | nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); | ||
97 | if (nfserr) | ||
98 | goto done; | ||
99 | |||
100 | if (delta < 0) | ||
101 | delta = -delta; | ||
102 | if (delta < MAX_TOUCH_TIME_ERROR && | ||
103 | setattr_prepare(fhp->fh_dentry, iap) != 0) { | ||
104 | /* | ||
105 | * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. | ||
106 | * This will cause notify_change to set these times | ||
107 | * to "now" | ||
108 | */ | ||
109 | iap->ia_valid &= ~BOTH_TIME_SET; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | nfserr = nfsd_setattr(rqstp, fhp, iap, 0, (time_t)0); | ||
114 | done: | ||
69 | return nfsd_return_attrs(nfserr, resp); | 115 | return nfsd_return_attrs(nfserr, resp); |
70 | } | 116 | } |
71 | 117 | ||