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 __be16 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
->dstaddr
;
68 const struct sockaddr_in
*addr
= (struct sockaddr_in
*) sa
;
69 const struct sockaddr_in6
*addr6
= (struct sockaddr_in6
*) sa
;
70 struct cifs_server_key
*key
= buffer
;
71 uint16_t key_len
= sizeof(struct cifs_server_key
);
73 memset(key
, 0, key_len
);
76 * Should not be a problem as sin_family/sin6_family overlays
79 switch (sa
->sa_family
) {
81 key
->family
= sa
->sa_family
;
82 key
->port
= addr
->sin_port
;
83 key
->addr
[0].ipv4_addr
= addr
->sin_addr
;
84 key_len
+= sizeof(key
->addr
[0].ipv4_addr
);
88 key
->family
= sa
->sa_family
;
89 key
->port
= addr6
->sin6_port
;
90 key
->addr
[0].ipv6_addr
= addr6
->sin6_addr
;
91 key_len
+= sizeof(key
->addr
[0].ipv6_addr
);
95 cERROR(1, "Unknown network family '%d'", sa
->sa_family
);
104 * Server object for FS-Cache
106 const struct fscache_cookie_def cifs_fscache_server_index_def
= {
107 .name
= "CIFS.server",
108 .type
= FSCACHE_COOKIE_TYPE_INDEX
,
109 .get_key
= cifs_server_get_key
,
113 * Auxiliary data attached to CIFS superblock within the cache
115 struct cifs_fscache_super_auxdata
{
116 u64 resource_id
; /* unique server resource id */
119 static char *extract_sharename(const char *treename
)
125 /* skip double chars at the beginning */
128 /* share name is always preceded by '\\' now */
129 delim
= strchr(src
, '\\');
131 return ERR_PTR(-EINVAL
);
135 /* caller has to free the memory */
136 dst
= kstrndup(delim
, len
, GFP_KERNEL
);
138 return ERR_PTR(-ENOMEM
);
144 * Superblock object currently keyed by share name
146 static uint16_t cifs_super_get_key(const void *cookie_netfs_data
, void *buffer
,
149 const struct cifs_tcon
*tcon
= cookie_netfs_data
;
153 sharename
= extract_sharename(tcon
->treeName
);
154 if (IS_ERR(sharename
)) {
155 cFYI(1, "%s: couldn't extract sharename\n", __func__
);
160 len
= strlen(sharename
);
164 memcpy(buffer
, sharename
, len
);
172 cifs_fscache_super_get_aux(const void *cookie_netfs_data
, void *buffer
,
175 struct cifs_fscache_super_auxdata auxdata
;
176 const struct cifs_tcon
*tcon
= cookie_netfs_data
;
178 memset(&auxdata
, 0, sizeof(auxdata
));
179 auxdata
.resource_id
= tcon
->resource_id
;
181 if (maxbuf
> sizeof(auxdata
))
182 maxbuf
= sizeof(auxdata
);
184 memcpy(buffer
, &auxdata
, maxbuf
);
190 fscache_checkaux
cifs_fscache_super_check_aux(void *cookie_netfs_data
,
194 struct cifs_fscache_super_auxdata auxdata
;
195 const struct cifs_tcon
*tcon
= cookie_netfs_data
;
197 if (datalen
!= sizeof(auxdata
))
198 return FSCACHE_CHECKAUX_OBSOLETE
;
200 memset(&auxdata
, 0, sizeof(auxdata
));
201 auxdata
.resource_id
= tcon
->resource_id
;
203 if (memcmp(data
, &auxdata
, datalen
) != 0)
204 return FSCACHE_CHECKAUX_OBSOLETE
;
206 return FSCACHE_CHECKAUX_OKAY
;
210 * Superblock object for FS-Cache
212 const struct fscache_cookie_def cifs_fscache_super_index_def
= {
213 .name
= "CIFS.super",
214 .type
= FSCACHE_COOKIE_TYPE_INDEX
,
215 .get_key
= cifs_super_get_key
,
216 .get_aux
= cifs_fscache_super_get_aux
,
217 .check_aux
= cifs_fscache_super_check_aux
,
221 * Auxiliary data attached to CIFS inode within the cache
223 struct cifs_fscache_inode_auxdata
{
224 struct timespec last_write_time
;
225 struct timespec last_change_time
;
229 static uint16_t cifs_fscache_inode_get_key(const void *cookie_netfs_data
,
230 void *buffer
, uint16_t maxbuf
)
232 const struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
235 /* use the UniqueId as the key */
236 keylen
= sizeof(cifsi
->uniqueid
);
240 memcpy(buffer
, &cifsi
->uniqueid
, keylen
);
246 cifs_fscache_inode_get_attr(const void *cookie_netfs_data
, uint64_t *size
)
248 const struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
250 *size
= cifsi
->vfs_inode
.i_size
;
254 cifs_fscache_inode_get_aux(const void *cookie_netfs_data
, void *buffer
,
257 struct cifs_fscache_inode_auxdata auxdata
;
258 const struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
260 memset(&auxdata
, 0, sizeof(auxdata
));
261 auxdata
.eof
= cifsi
->server_eof
;
262 auxdata
.last_write_time
= cifsi
->vfs_inode
.i_mtime
;
263 auxdata
.last_change_time
= cifsi
->vfs_inode
.i_ctime
;
265 if (maxbuf
> sizeof(auxdata
))
266 maxbuf
= sizeof(auxdata
);
268 memcpy(buffer
, &auxdata
, maxbuf
);
274 fscache_checkaux
cifs_fscache_inode_check_aux(void *cookie_netfs_data
,
278 struct cifs_fscache_inode_auxdata auxdata
;
279 struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
281 if (datalen
!= sizeof(auxdata
))
282 return FSCACHE_CHECKAUX_OBSOLETE
;
284 memset(&auxdata
, 0, sizeof(auxdata
));
285 auxdata
.eof
= cifsi
->server_eof
;
286 auxdata
.last_write_time
= cifsi
->vfs_inode
.i_mtime
;
287 auxdata
.last_change_time
= cifsi
->vfs_inode
.i_ctime
;
289 if (memcmp(data
, &auxdata
, datalen
) != 0)
290 return FSCACHE_CHECKAUX_OBSOLETE
;
292 return FSCACHE_CHECKAUX_OKAY
;
295 static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data
)
297 struct cifsInodeInfo
*cifsi
= cookie_netfs_data
;
302 pagevec_init(&pvec
, 0);
305 cFYI(1, "%s: cifs inode 0x%p now uncached", __func__
, cifsi
);
308 nr_pages
= pagevec_lookup(&pvec
,
309 cifsi
->vfs_inode
.i_mapping
, first
,
310 PAGEVEC_SIZE
- pagevec_count(&pvec
));
314 for (loop
= 0; loop
< nr_pages
; loop
++)
315 ClearPageFsCache(pvec
.pages
[loop
]);
317 first
= pvec
.pages
[nr_pages
- 1]->index
+ 1;
320 pagevec_release(&pvec
);
325 const struct fscache_cookie_def cifs_fscache_inode_object_def
= {
326 .name
= "CIFS.uniqueid",
327 .type
= FSCACHE_COOKIE_TYPE_DATAFILE
,
328 .get_key
= cifs_fscache_inode_get_key
,
329 .get_attr
= cifs_fscache_inode_get_attr
,
330 .get_aux
= cifs_fscache_inode_get_aux
,
331 .check_aux
= cifs_fscache_inode_check_aux
,
332 .now_uncached
= cifs_fscache_inode_now_uncached
,