2 * fs/cifs/cache.c - CIFS filesystem cache index structure definitions
4 * Copyright (c) 2010 Novell, Inc.
5 * Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
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.
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.
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
22 #include "cifs_debug.h"
25 * CIFS filesystem definition for FS-Cache
27 struct fscache_netfs cifs_fscache_netfs
= {
33 * Register CIFS for caching with FS-Cache
35 int cifs_fscache_register(void)
37 return fscache_register_netfs(&cifs_fscache_netfs
);
41 * Unregister CIFS for caching
43 void cifs_fscache_unregister(void)
45 fscache_unregister_netfs(&cifs_fscache_netfs
);
49 * Key layout of CIFS server cache index object
51 struct cifs_server_key
{
52 uint16_t family
; /* address family */
53 uint16_t port
; /* IP port */
55 struct in_addr ipv4_addr
;
56 struct in6_addr ipv6_addr
;
61 * Server object keyed by {IPaddress,port,family} tuple
63 static uint16_t cifs_server_get_key(const void *cookie_netfs_data
,
64 void *buffer
, uint16_t maxbuf
)
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
);
71 memset(key
, 0, key_len
);
74 * Should not be a problem as sin_family/sin6_family overlays
77 switch (sa
->sa_family
) {
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
);
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
);
93 cERROR(1, "CIFS: Unknown network family '%d'", sa
->sa_family
);
102 * Server object for FS-Cache
104 const 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
,
111 * Auxiliary data attached to CIFS superblock within the cache
113 struct cifs_fscache_super_auxdata
{
114 u64 resource_id
; /* unique server resource id */
117 static char *extract_sharename(const char *treename
)
123 /* skip double chars at the beginning */
126 /* share name is always preceded by '\\' now */
127 delim
= strchr(src
, '\\');
129 return ERR_PTR(-EINVAL
);
133 /* caller has to free the memory */
134 dst
= kstrndup(delim
, len
, GFP_KERNEL
);
136 return ERR_PTR(-ENOMEM
);
142 * Superblock object currently keyed by share name
144 static uint16_t cifs_super_get_key(const void *cookie_netfs_data
, void *buffer
,
147 const struct cifsTconInfo
*tcon
= cookie_netfs_data
;
151 sharename
= extract_sharename(tcon
->treeName
);
152 if (IS_ERR(sharename
)) {
153 cFYI(1, "CIFS: couldn't extract sharename\n");
158 len
= strlen(sharename
);
162 memcpy(buffer
, sharename
, len
);
170 cifs_fscache_super_get_aux(const void *cookie_netfs_data
, void *buffer
,
173 struct cifs_fscache_super_auxdata auxdata
;
174 const struct cifsTconInfo
*tcon
= cookie_netfs_data
;
176 memset(&auxdata
, 0, sizeof(auxdata
));
177 auxdata
.resource_id
= tcon
->resource_id
;
179 if (maxbuf
> sizeof(auxdata
))
180 maxbuf
= sizeof(auxdata
);
182 memcpy(buffer
, &auxdata
, maxbuf
);
188 fscache_checkaux
cifs_fscache_super_check_aux(void *cookie_netfs_data
,
192 struct cifs_fscache_super_auxdata auxdata
;
193 const struct cifsTconInfo
*tcon
= cookie_netfs_data
;
195 if (datalen
!= sizeof(auxdata
))
196 return FSCACHE_CHECKAUX_OBSOLETE
;
198 memset(&auxdata
, 0, sizeof(auxdata
));
199 auxdata
.resource_id
= tcon
->resource_id
;
201 if (memcmp(data
, &auxdata
, datalen
) != 0)
202 return FSCACHE_CHECKAUX_OBSOLETE
;
204 return FSCACHE_CHECKAUX_OKAY
;
208 * Superblock object for FS-Cache
210 const 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
,
219 * Auxiliary data attached to CIFS inode within the cache
221 struct cifs_fscache_inode_auxdata
{
222 struct timespec last_write_time
;
223 struct timespec last_change_time
;
227 static uint16_t cifs_fscache_inode_get_key(const void *cookie_netfs_data
,
228 void *buffer
, uint16_t maxbuf
)
230 const struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
233 /* use the UniqueId as the key */
234 keylen
= sizeof(cifsi
->uniqueid
);
238 memcpy(buffer
, &cifsi
->uniqueid
, keylen
);
244 cifs_fscache_inode_get_attr(const void *cookie_netfs_data
, uint64_t *size
)
246 const struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
248 *size
= cifsi
->vfs_inode
.i_size
;
252 cifs_fscache_inode_get_aux(const void *cookie_netfs_data
, void *buffer
,
255 struct cifs_fscache_inode_auxdata auxdata
;
256 const struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
258 memset(&auxdata
, 0, sizeof(auxdata
));
259 auxdata
.eof
= cifsi
->server_eof
;
260 auxdata
.last_write_time
= cifsi
->vfs_inode
.i_mtime
;
261 auxdata
.last_change_time
= cifsi
->vfs_inode
.i_ctime
;
263 if (maxbuf
> sizeof(auxdata
))
264 maxbuf
= sizeof(auxdata
);
266 memcpy(buffer
, &auxdata
, maxbuf
);
272 fscache_checkaux
cifs_fscache_inode_check_aux(void *cookie_netfs_data
,
276 struct cifs_fscache_inode_auxdata auxdata
;
277 struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
279 if (datalen
!= sizeof(auxdata
))
280 return FSCACHE_CHECKAUX_OBSOLETE
;
282 memset(&auxdata
, 0, sizeof(auxdata
));
283 auxdata
.eof
= cifsi
->server_eof
;
284 auxdata
.last_write_time
= cifsi
->vfs_inode
.i_mtime
;
285 auxdata
.last_change_time
= cifsi
->vfs_inode
.i_ctime
;
287 if (memcmp(data
, &auxdata
, datalen
) != 0)
288 return FSCACHE_CHECKAUX_OBSOLETE
;
290 return FSCACHE_CHECKAUX_OKAY
;
293 static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data
)
295 struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
300 pagevec_init(&pvec
, 0);
303 cFYI(1, "cifs inode 0x%p now uncached", cifsi
);
306 nr_pages
= pagevec_lookup(&pvec
,
307 cifsi
->vfs_inode
.i_mapping
, first
,
308 PAGEVEC_SIZE
- pagevec_count(&pvec
));
312 for (loop
= 0; loop
< nr_pages
; loop
++)
313 ClearPageFsCache(pvec
.pages
[loop
]);
315 first
= pvec
.pages
[nr_pages
- 1]->index
+ 1;
318 pagevec_release(&pvec
);
323 const struct fscache_cookie_def cifs_fscache_inode_object_def
= {
324 .name
= "CIFS.uniqueid",
325 .type
= FSCACHE_COOKIE_TYPE_DATAFILE
,
326 .get_key
= cifs_fscache_inode_get_key
,
327 .get_attr
= cifs_fscache_inode_get_attr
,
328 .get_aux
= cifs_fscache_inode_get_aux
,
329 .check_aux
= cifs_fscache_inode_check_aux
,
330 .now_uncached
= cifs_fscache_inode_now_uncached
,