diff options
Diffstat (limited to 'fs/nfs/fscache.c')
-rw-r--r-- | fs/nfs/fscache.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index c3f056f89477..ab2de2c92b21 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -23,6 +23,9 @@ | |||
23 | 23 | ||
24 | #define NFSDBG_FACILITY NFSDBG_FSCACHE | 24 | #define NFSDBG_FACILITY NFSDBG_FSCACHE |
25 | 25 | ||
26 | static struct rb_root nfs_fscache_keys = RB_ROOT; | ||
27 | static DEFINE_SPINLOCK(nfs_fscache_keys_lock); | ||
28 | |||
26 | /* | 29 | /* |
27 | * Get the per-client index cookie for an NFS client if the appropriate mount | 30 | * Get the per-client index cookie for an NFS client if the appropriate mount |
28 | * flag was set | 31 | * flag was set |
@@ -50,3 +53,116 @@ void nfs_fscache_release_client_cookie(struct nfs_client *clp) | |||
50 | fscache_relinquish_cookie(clp->fscache, 0); | 53 | fscache_relinquish_cookie(clp->fscache, 0); |
51 | clp->fscache = NULL; | 54 | clp->fscache = NULL; |
52 | } | 55 | } |
56 | |||
57 | /* | ||
58 | * Get the cache cookie for an NFS superblock. We have to handle | ||
59 | * uniquification here because the cache doesn't do it for us. | ||
60 | */ | ||
61 | void nfs_fscache_get_super_cookie(struct super_block *sb, | ||
62 | struct nfs_parsed_mount_data *data) | ||
63 | { | ||
64 | struct nfs_fscache_key *key, *xkey; | ||
65 | struct nfs_server *nfss = NFS_SB(sb); | ||
66 | struct rb_node **p, *parent; | ||
67 | const char *uniq = data->fscache_uniq ?: ""; | ||
68 | int diff, ulen; | ||
69 | |||
70 | ulen = strlen(uniq); | ||
71 | key = kzalloc(sizeof(*key) + ulen, GFP_KERNEL); | ||
72 | if (!key) | ||
73 | return; | ||
74 | |||
75 | key->nfs_client = nfss->nfs_client; | ||
76 | key->key.super.s_flags = sb->s_flags & NFS_MS_MASK; | ||
77 | key->key.nfs_server.flags = nfss->flags; | ||
78 | key->key.nfs_server.rsize = nfss->rsize; | ||
79 | key->key.nfs_server.wsize = nfss->wsize; | ||
80 | key->key.nfs_server.acregmin = nfss->acregmin; | ||
81 | key->key.nfs_server.acregmax = nfss->acregmax; | ||
82 | key->key.nfs_server.acdirmin = nfss->acdirmin; | ||
83 | key->key.nfs_server.acdirmax = nfss->acdirmax; | ||
84 | key->key.nfs_server.fsid = nfss->fsid; | ||
85 | key->key.rpc_auth.au_flavor = nfss->client->cl_auth->au_flavor; | ||
86 | |||
87 | key->key.uniq_len = ulen; | ||
88 | memcpy(key->key.uniquifier, uniq, ulen); | ||
89 | |||
90 | spin_lock(&nfs_fscache_keys_lock); | ||
91 | p = &nfs_fscache_keys.rb_node; | ||
92 | parent = NULL; | ||
93 | while (*p) { | ||
94 | parent = *p; | ||
95 | xkey = rb_entry(parent, struct nfs_fscache_key, node); | ||
96 | |||
97 | if (key->nfs_client < xkey->nfs_client) | ||
98 | goto go_left; | ||
99 | if (key->nfs_client > xkey->nfs_client) | ||
100 | goto go_right; | ||
101 | |||
102 | diff = memcmp(&key->key, &xkey->key, sizeof(key->key)); | ||
103 | if (diff < 0) | ||
104 | goto go_left; | ||
105 | if (diff > 0) | ||
106 | goto go_right; | ||
107 | |||
108 | if (key->key.uniq_len == 0) | ||
109 | goto non_unique; | ||
110 | diff = memcmp(key->key.uniquifier, | ||
111 | xkey->key.uniquifier, | ||
112 | key->key.uniq_len); | ||
113 | if (diff < 0) | ||
114 | goto go_left; | ||
115 | if (diff > 0) | ||
116 | goto go_right; | ||
117 | goto non_unique; | ||
118 | |||
119 | go_left: | ||
120 | p = &(*p)->rb_left; | ||
121 | continue; | ||
122 | go_right: | ||
123 | p = &(*p)->rb_right; | ||
124 | } | ||
125 | |||
126 | rb_link_node(&key->node, parent, p); | ||
127 | rb_insert_color(&key->node, &nfs_fscache_keys); | ||
128 | spin_unlock(&nfs_fscache_keys_lock); | ||
129 | nfss->fscache_key = key; | ||
130 | |||
131 | /* create a cache index for looking up filehandles */ | ||
132 | nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache, | ||
133 | &nfs_fscache_super_index_def, | ||
134 | nfss); | ||
135 | dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", | ||
136 | nfss, nfss->fscache); | ||
137 | return; | ||
138 | |||
139 | non_unique: | ||
140 | spin_unlock(&nfs_fscache_keys_lock); | ||
141 | kfree(key); | ||
142 | nfss->fscache_key = NULL; | ||
143 | nfss->fscache = NULL; | ||
144 | printk(KERN_WARNING "NFS:" | ||
145 | " Cache request denied due to non-unique superblock keys\n"); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * release a per-superblock cookie | ||
150 | */ | ||
151 | void nfs_fscache_release_super_cookie(struct super_block *sb) | ||
152 | { | ||
153 | struct nfs_server *nfss = NFS_SB(sb); | ||
154 | |||
155 | dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n", | ||
156 | nfss, nfss->fscache); | ||
157 | |||
158 | fscache_relinquish_cookie(nfss->fscache, 0); | ||
159 | nfss->fscache = NULL; | ||
160 | |||
161 | if (nfss->fscache_key) { | ||
162 | spin_lock(&nfs_fscache_keys_lock); | ||
163 | rb_erase(&nfss->fscache_key->node, &nfs_fscache_keys); | ||
164 | spin_unlock(&nfs_fscache_keys_lock); | ||
165 | kfree(nfss->fscache_key); | ||
166 | nfss->fscache_key = NULL; | ||
167 | } | ||
168 | } | ||