aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfsproc.c')
-rw-r--r--fs/nfsd/nfsproc.c50
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
59nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, 59nfsd_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);
114done:
69 return nfsd_return_attrs(nfserr, resp); 115 return nfsd_return_attrs(nfserr, resp);
70} 116}
71 117