blob: 15532abdac14ffcbef46dc51ac4d238827c91b24 [file] [log] [blame]
Suresh Jayaramanf579cf32010-07-05 18:11:50 +05301/*
2 * fs/cifs/cache.c - CIFS filesystem cache index structure definitions
3 *
4 * Copyright (c) 2010 Novell, Inc.
5 * Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include "fscache.h"
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +053022#include "cifs_debug.h"
Suresh Jayaramanf579cf32010-07-05 18:11:50 +053023
24/*
25 * CIFS filesystem definition for FS-Cache
26 */
27struct fscache_netfs cifs_fscache_netfs = {
28 .name = "cifs",
29 .version = 0,
30};
31
32/*
33 * Register CIFS for caching with FS-Cache
34 */
35int cifs_fscache_register(void)
36{
37 return fscache_register_netfs(&cifs_fscache_netfs);
38}
39
40/*
41 * Unregister CIFS for caching
42 */
43void cifs_fscache_unregister(void)
44{
45 fscache_unregister_netfs(&cifs_fscache_netfs);
46}
47
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +053048/*
49 * Key layout of CIFS server cache index object
50 */
51struct cifs_server_key {
52 uint16_t family; /* address family */
53 uint16_t port; /* IP port */
54 union {
55 struct in_addr ipv4_addr;
56 struct in6_addr ipv6_addr;
57 } addr[0];
58};
59
60/*
61 * Server object keyed by {IPaddress,port,family} tuple
62 */
63static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
64 void *buffer, uint16_t maxbuf)
65{
66 const struct TCP_Server_Info *server = cookie_netfs_data;
67 const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr;
68 struct cifs_server_key *key = buffer;
69 uint16_t key_len = sizeof(struct cifs_server_key);
70
71 memset(key, 0, key_len);
72
73 /*
74 * Should not be a problem as sin_family/sin6_family overlays
75 * sa_family field
76 */
77 switch (sa->sa_family) {
78 case AF_INET:
79 key->family = server->addr.sockAddr.sin_family;
80 key->port = server->addr.sockAddr.sin_port;
81 key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr;
82 key_len += sizeof(key->addr[0].ipv4_addr);
83 break;
84
85 case AF_INET6:
86 key->family = server->addr.sockAddr6.sin6_family;
87 key->port = server->addr.sockAddr6.sin6_port;
88 key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr;
89 key_len += sizeof(key->addr[0].ipv6_addr);
90 break;
91
92 default:
93 cERROR(1, "CIFS: Unknown network family '%d'", sa->sa_family);
94 key_len = 0;
95 break;
96 }
97
98 return key_len;
99}
100
101/*
102 * Server object for FS-Cache
103 */
104const struct fscache_cookie_def cifs_fscache_server_index_def = {
105 .name = "CIFS.server",
106 .type = FSCACHE_COOKIE_TYPE_INDEX,
107 .get_key = cifs_server_get_key,
108};
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530109
110/*
111 * Auxiliary data attached to CIFS superblock within the cache
112 */
113struct cifs_fscache_super_auxdata {
114 u64 resource_id; /* unique server resource id */
115};
116
117static char *extract_sharename(const char *treename)
118{
119 const char *src;
120 char *delim, *dst;
121 int len;
122
123 /* skip double chars at the beginning */
124 src = treename + 2;
125
126 /* share name is always preceded by '\\' now */
127 delim = strchr(src, '\\');
128 if (!delim)
129 return ERR_PTR(-EINVAL);
130 delim++;
131 len = strlen(delim);
132
133 /* caller has to free the memory */
134 dst = kstrndup(delim, len, GFP_KERNEL);
135 if (!dst)
136 return ERR_PTR(-ENOMEM);
137
138 return dst;
139}
140
141/*
142 * Superblock object currently keyed by share name
143 */
144static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer,
145 uint16_t maxbuf)
146{
147 const struct cifsTconInfo *tcon = cookie_netfs_data;
148 char *sharename;
149 uint16_t len;
150
151 sharename = extract_sharename(tcon->treeName);
152 if (IS_ERR(sharename)) {
153 cFYI(1, "CIFS: couldn't extract sharename\n");
154 sharename = NULL;
155 return 0;
156 }
157
158 len = strlen(sharename);
159 if (len > maxbuf)
160 return 0;
161
162 memcpy(buffer, sharename, len);
163
164 kfree(sharename);
165
166 return len;
167}
168
169static uint16_t
170cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer,
171 uint16_t maxbuf)
172{
173 struct cifs_fscache_super_auxdata auxdata;
174 const struct cifsTconInfo *tcon = cookie_netfs_data;
175
176 memset(&auxdata, 0, sizeof(auxdata));
177 auxdata.resource_id = tcon->resource_id;
178
179 if (maxbuf > sizeof(auxdata))
180 maxbuf = sizeof(auxdata);
181
182 memcpy(buffer, &auxdata, maxbuf);
183
184 return maxbuf;
185}
186
187static enum
188fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data,
189 const void *data,
190 uint16_t datalen)
191{
192 struct cifs_fscache_super_auxdata auxdata;
193 const struct cifsTconInfo *tcon = cookie_netfs_data;
194
195 if (datalen != sizeof(auxdata))
196 return FSCACHE_CHECKAUX_OBSOLETE;
197
198 memset(&auxdata, 0, sizeof(auxdata));
199 auxdata.resource_id = tcon->resource_id;
200
201 if (memcmp(data, &auxdata, datalen) != 0)
202 return FSCACHE_CHECKAUX_OBSOLETE;
203
204 return FSCACHE_CHECKAUX_OKAY;
205}
206
207/*
208 * Superblock object for FS-Cache
209 */
210const struct fscache_cookie_def cifs_fscache_super_index_def = {
211 .name = "CIFS.super",
212 .type = FSCACHE_COOKIE_TYPE_INDEX,
213 .get_key = cifs_super_get_key,
214 .get_aux = cifs_fscache_super_get_aux,
215 .check_aux = cifs_fscache_super_check_aux,
216};
217