@@ -55,6 +55,7 @@
#define LOOKUP_JUMPED 0x1000
#define LOOKUP_ROOT 0x2000
#define LOOKUP_EMPTY 0x4000
+#define LOOKUP_WRITE 0x8000
extern int user_path_at(int, const char __user *, unsigned, struct path *);
extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
@@ -124,6 +124,7 @@
unsigned int acregmax;
unsigned int acdirmin;
unsigned int acdirmax;
+ unsigned int sloppycto;
unsigned int namelen;
unsigned int options; /* extra options enabled by mount */
#define NFS_OPTION_FSCACHE 0x00000001 /* - local caching enabled */
@@ -779,6 +779,7 @@
server->acregmax = data->acregmax * HZ;
server->acdirmin = data->acdirmin * HZ;
server->acdirmax = data->acdirmax * HZ;
+ server->sloppycto = data->sloppycto * HZ;
/* Start lockd here, before we might error out */
error = nfs_start_lockd(server);
@@ -859,6 +860,7 @@
if (server->flags & NFS_MOUNT_NOAC) {
server->acregmin = server->acregmax = 0;
server->acdirmin = server->acdirmax = 0;
+ server->sloppycto = 0;
}
server->maxfilesize = fsinfo->maxfilesize;
@@ -926,6 +928,7 @@
target->acregmax = source->acregmax;
target->acdirmin = source->acdirmin;
target->acdirmax = source->acdirmax;
+ target->sloppycto = source->sloppycto;
target->caps = source->caps;
target->options = source->options;
}
@@ -972,6 +972,22 @@
}
/*
+ * See if we allow sloppy close-to-open consistency.
+ */
+static inline
+int sloppycto(struct inode *inode, int flags)
+{
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_inode *nfsi = NFS_I(inode);
+
+ return S_ISREG(inode->i_mode) &&
+ !(flags & LOOKUP_WRITE) &&
+ server->sloppycto &&
+ time_in_range_open(jiffies, nfsi->attrtimeo_timestamp,
+ nfsi->attrtimeo_timestamp + server->sloppycto);
+}
+
+/*
* Inode and filehandle revalidation for lookups.
*
* We force revalidation in the cases where the VFS sets LOOKUP_REVAL,
@@ -991,7 +1007,8 @@
if (flags & LOOKUP_REVAL)
goto out_force;
/* This is an open(2) */
- if ((flags & LOOKUP_OPEN) && !(server->flags & NFS_MOUNT_NOCTO) &&
+ if ((flags & LOOKUP_OPEN) &&
+ !(server->flags & NFS_MOUNT_NOCTO) && !sloppycto(inode, flags) &&
(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
goto out_force;
out:
@@ -89,6 +89,7 @@
key->key.nfs_server.acregmax = nfss->acregmax;
key->key.nfs_server.acdirmin = nfss->acdirmin;
key->key.nfs_server.acdirmax = nfss->acdirmax;
+ key->key.nfs_server.sloppycto = nfss->sloppycto;
key->key.nfs_server.fsid = nfss->fsid;
key->key.rpc_auth.au_flavor = nfss->client->cl_auth->au_flavor;
@@ -43,6 +43,7 @@
unsigned int acregmax;
unsigned int acdirmin;
unsigned int acdirmax;
+ unsigned int sloppycto;
} nfs_server;
struct {
@@ -82,6 +82,7 @@
int flags;
unsigned int rsize, wsize;
unsigned int timeo, retrans;
+ unsigned int sloppycto;
unsigned int acregmin, acregmax,
acdirmin, acdirmax;
unsigned int namlen;
@@ -795,6 +795,7 @@
server->acregmax = data->acregmax * HZ;
server->acdirmin = data->acdirmin * HZ;
server->acdirmax = data->acdirmax * HZ;
+ server->sloppycto = data->sloppycto * HZ;
server->port = data->nfs_server.port;
@@ -98,6 +98,7 @@
Opt_timeo, Opt_retrans,
Opt_acregmin, Opt_acregmax,
Opt_acdirmin, Opt_acdirmax,
+ Opt_sloppycto,
Opt_actimeo,
Opt_namelen,
Opt_mountport,
@@ -163,6 +164,7 @@
{ Opt_acregmax, "acregmax=%s" },
{ Opt_acdirmin, "acdirmin=%s" },
{ Opt_acdirmax, "acdirmax=%s" },
+ { Opt_sloppycto, "sloppycto=%s" },
{ Opt_actimeo, "actimeo=%s" },
{ Opt_namelen, "namlen=%s" },
{ Opt_mountport, "mountport=%s" },
@@ -656,6 +658,8 @@
seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ);
if (nfss->acdirmax != NFS_DEF_ACDIRMAX*HZ || showdefaults)
seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ);
+ if (nfss->sloppycto != 0)
+ seq_printf(m, ",sloppycto=%u", nfss->sloppycto/HZ);
for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
if (nfss->flags & nfs_infop->flag)
seq_puts(m, nfs_infop->str);
@@ -1316,6 +1320,11 @@
goto out_invalid_value;
mnt->acdirmax = option;
break;
+ case Opt_sloppycto:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->sloppycto = option;
+ break;
case Opt_actimeo:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
@@ -2074,6 +2083,7 @@
data->acregmax != nfss->acregmax / HZ ||
data->acdirmin != nfss->acdirmin / HZ ||
data->acdirmax != nfss->acdirmax / HZ ||
+ data->sloppycto != nfss->sloppycto / HZ ||
data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
data->nfs_server.port != nfss->port ||
data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
@@ -2245,6 +2255,8 @@
goto Ebusy;
if (a->acdirmax != b->acdirmax)
goto Ebusy;
+ if (a->sloppycto != b->sloppycto)
+ goto Ebusy;
if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
goto Ebusy;
return 1;
@@ -899,6 +899,8 @@
if (flags & O_EXCL)
op->intent |= LOOKUP_EXCL;
}
+ if (flags & (O_RDWR|O_WRONLY|O_CREAT))
+ op->intent |= LOOKUP_WRITE;
if (flags & O_DIRECTORY)
lookup_flags |= LOOKUP_DIRECTORY;