Commit 58df095b authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Allow entries in the idmap cache to expire

 If someone changes the uid/gid mapping in userland, then we do eventually
 want those changes to be propagated to the kernel. Currently the kernel
 assumes that it may cache entries forever.

 Add an expiration time + garbage collector for idmap entries.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 0065db32
...@@ -914,6 +914,10 @@ running once the system is up. ...@@ -914,6 +914,10 @@ running once the system is up.
[NFS] set the TCP port on which the NFSv4 callback [NFS] set the TCP port on which the NFSv4 callback
channel should listen. channel should listen.
nfs.idmap_cache_timeout=
[NFS] set the maximum lifetime for idmapper cache
entries.
nmi_watchdog= [KNL,BUGS=IA-32] Debugging features for SMP kernels nmi_watchdog= [KNL,BUGS=IA-32] Debugging features for SMP kernels
no387 [BUGS=IA-32] Tells the kernel to use the 387 maths no387 [BUGS=IA-32] Tells the kernel to use the 387 maths
......
...@@ -54,7 +54,11 @@ ...@@ -54,7 +54,11 @@
#define IDMAP_HASH_SZ 128 #define IDMAP_HASH_SZ 128
/* Default cache timeout is 10 minutes */
unsigned int nfs_idmap_cache_timeout = 600 * HZ;
struct idmap_hashent { struct idmap_hashent {
unsigned long ih_expires;
__u32 ih_id; __u32 ih_id;
int ih_namelen; int ih_namelen;
char ih_name[IDMAP_NAMESZ]; char ih_name[IDMAP_NAMESZ];
...@@ -149,6 +153,8 @@ idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len) ...@@ -149,6 +153,8 @@ idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
return NULL; return NULL;
if (time_after(jiffies, he->ih_expires))
return NULL;
return he; return he;
} }
...@@ -164,6 +170,8 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id) ...@@ -164,6 +170,8 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
struct idmap_hashent *he = idmap_id_hash(h, id); struct idmap_hashent *he = idmap_id_hash(h, id);
if (he->ih_id != id || he->ih_namelen == 0) if (he->ih_id != id || he->ih_namelen == 0)
return NULL; return NULL;
if (time_after(jiffies, he->ih_expires))
return NULL;
return he; return he;
} }
...@@ -192,6 +200,7 @@ idmap_update_entry(struct idmap_hashent *he, const char *name, ...@@ -192,6 +200,7 @@ idmap_update_entry(struct idmap_hashent *he, const char *name,
memcpy(he->ih_name, name, namelen); memcpy(he->ih_name, name, namelen);
he->ih_name[namelen] = '\0'; he->ih_name[namelen] = '\0';
he->ih_namelen = namelen; he->ih_namelen = namelen;
he->ih_expires = jiffies + nfs_idmap_cache_timeout;
} }
/* /*
......
...@@ -2050,6 +2050,20 @@ static int param_set_port(const char *val, struct kernel_param *kp) ...@@ -2050,6 +2050,20 @@ static int param_set_port(const char *val, struct kernel_param *kp)
module_param_call(callback_tcpport, param_set_port, param_get_int, module_param_call(callback_tcpport, param_set_port, param_get_int,
&nfs_callback_set_tcpport, 0644); &nfs_callback_set_tcpport, 0644);
static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
{
char *endp;
int num = simple_strtol(val, &endp, 0);
int jif = num * HZ;
if (endp == val || *endp || num < 0 || jif < num)
return -EINVAL;
*((int *)kp->arg) = jif;
return 0;
}
module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
&nfs_idmap_cache_timeout, 0644);
#define nfs4_init_once(nfsi) \ #define nfs4_init_once(nfsi) \
do { \ do { \
INIT_LIST_HEAD(&(nfsi)->open_states); \ INIT_LIST_HEAD(&(nfsi)->open_states); \
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/nfs4.h> #include <linux/nfs4.h>
#include <linux/nfs_idmap.h>
#include "callback.h" #include "callback.h"
...@@ -35,6 +36,15 @@ static ctl_table nfs_cb_sysctls[] = { ...@@ -35,6 +36,15 @@ static ctl_table nfs_cb_sysctls[] = {
.extra1 = (int *)&nfs_set_port_min, .extra1 = (int *)&nfs_set_port_min,
.extra2 = (int *)&nfs_set_port_max, .extra2 = (int *)&nfs_set_port_max,
}, },
{
.ctl_name = CTL_UNNUMBERED,
.procname = "idmap_cache_timeout",
.data = &nfs_idmap_cache_timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
#endif #endif
{ .ctl_name = 0 } { .ctl_name = 0 }
}; };
......
...@@ -71,6 +71,8 @@ int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *); ...@@ -71,6 +71,8 @@ int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *);
int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *); int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *);
int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *); int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *);
int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *); int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *);
extern unsigned int nfs_idmap_cache_timeout;
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* NFS_IDMAP_H */ #endif /* NFS_IDMAP_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment