 f96637be08
			
		
	
	
	f96637be08
	
	
	
		
			
			It's not obvious from reading the macro names that these macros are for debugging. Convert the names to a single more typical kernel style cifs_dbg macro. cERROR(1, ...) -> cifs_dbg(VFS, ...) cFYI(1, ...) -> cifs_dbg(FYI, ...) cFYI(DBG2, ...) -> cifs_dbg(NOISY, ...) Move the terminating format newline from the macro to the call site. Add CONFIG_CIFS_DEBUG function cifs_vfs_err to emit the "CIFS VFS: " prefix for VFS messages. Size is reduced ~ 1% when CONFIG_CIFS_DEBUG is set (default y) $ size fs/cifs/cifs.ko* text data bss dec hex filename 265245 2525 132 267902 4167e fs/cifs/cifs.ko.new 268359 2525 132 271016 422a8 fs/cifs/cifs.ko.old Other miscellaneous changes around these conversions: o Miscellaneous typo fixes o Add terminating \n's to almost all formats and remove them from the macros to be more kernel style like. A few formats previously had defective \n's o Remove unnecessary OOM messages as kmalloc() calls dump_stack o Coalesce formats to make grep easier, added missing spaces when coalescing formats o Use %s, __func__ instead of embedded function name o Removed unnecessary "cifs: " prefixes o Convert kzalloc with multiply to kcalloc o Remove unused cifswarn macro Signed-off-by: Joe Perches <joe@perches.com> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com>
		
			
				
	
	
		
			333 lines
		
	
	
	
		
			8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			333 lines
		
	
	
	
		
			8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *   fs/cifs/cache.c - CIFS filesystem cache index structure definitions
 | |
|  *
 | |
|  *   Copyright (c) 2010 Novell, Inc.
 | |
|  *   Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
 | |
|  *
 | |
|  *   This library is free software; you can redistribute it and/or modify
 | |
|  *   it under the terms of the GNU Lesser General Public License as published
 | |
|  *   by the Free Software Foundation; either version 2.1 of the License, or
 | |
|  *   (at your option) any later version.
 | |
|  *
 | |
|  *   This library is distributed in the hope that it will be useful,
 | |
|  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 | |
|  *   the GNU Lesser General Public License for more details.
 | |
|  *
 | |
|  *   You should have received a copy of the GNU Lesser General Public License
 | |
|  *   along with this library; if not, write to the Free Software
 | |
|  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | |
|  */
 | |
| #include "fscache.h"
 | |
| #include "cifs_debug.h"
 | |
| 
 | |
| /*
 | |
|  * CIFS filesystem definition for FS-Cache
 | |
|  */
 | |
| struct fscache_netfs cifs_fscache_netfs = {
 | |
| 	.name = "cifs",
 | |
| 	.version = 0,
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Register CIFS for caching with FS-Cache
 | |
|  */
 | |
| int cifs_fscache_register(void)
 | |
| {
 | |
| 	return fscache_register_netfs(&cifs_fscache_netfs);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Unregister CIFS for caching
 | |
|  */
 | |
| void cifs_fscache_unregister(void)
 | |
| {
 | |
| 	fscache_unregister_netfs(&cifs_fscache_netfs);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Key layout of CIFS server cache index object
 | |
|  */
 | |
| struct cifs_server_key {
 | |
| 	uint16_t	family;		/* address family */
 | |
| 	__be16		port;		/* IP port */
 | |
| 	union {
 | |
| 		struct in_addr	ipv4_addr;
 | |
| 		struct in6_addr	ipv6_addr;
 | |
| 	} addr[0];
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Server object keyed by {IPaddress,port,family} tuple
 | |
|  */
 | |
| static uint16_t cifs_server_get_key(const void *cookie_netfs_data,
 | |
| 				   void *buffer, uint16_t maxbuf)
 | |
| {
 | |
| 	const struct TCP_Server_Info *server = cookie_netfs_data;
 | |
| 	const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr;
 | |
| 	const struct sockaddr_in *addr = (struct sockaddr_in *) sa;
 | |
| 	const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa;
 | |
| 	struct cifs_server_key *key = buffer;
 | |
| 	uint16_t key_len = sizeof(struct cifs_server_key);
 | |
| 
 | |
| 	memset(key, 0, key_len);
 | |
| 
 | |
| 	/*
 | |
| 	 * Should not be a problem as sin_family/sin6_family overlays
 | |
| 	 * sa_family field
 | |
| 	 */
 | |
| 	switch (sa->sa_family) {
 | |
| 	case AF_INET:
 | |
| 		key->family = sa->sa_family;
 | |
| 		key->port = addr->sin_port;
 | |
| 		key->addr[0].ipv4_addr = addr->sin_addr;
 | |
| 		key_len += sizeof(key->addr[0].ipv4_addr);
 | |
| 		break;
 | |
| 
 | |
| 	case AF_INET6:
 | |
| 		key->family = sa->sa_family;
 | |
| 		key->port = addr6->sin6_port;
 | |
| 		key->addr[0].ipv6_addr = addr6->sin6_addr;
 | |
| 		key_len += sizeof(key->addr[0].ipv6_addr);
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family);
 | |
| 		key_len = 0;
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	return key_len;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Server object for FS-Cache
 | |
|  */
 | |
| const struct fscache_cookie_def cifs_fscache_server_index_def = {
 | |
| 	.name = "CIFS.server",
 | |
| 	.type = FSCACHE_COOKIE_TYPE_INDEX,
 | |
| 	.get_key = cifs_server_get_key,
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Auxiliary data attached to CIFS superblock within the cache
 | |
|  */
 | |
| struct cifs_fscache_super_auxdata {
 | |
| 	u64	resource_id;		/* unique server resource id */
 | |
| };
 | |
| 
 | |
| static char *extract_sharename(const char *treename)
 | |
| {
 | |
| 	const char *src;
 | |
| 	char *delim, *dst;
 | |
| 	int len;
 | |
| 
 | |
| 	/* skip double chars at the beginning */
 | |
| 	src = treename + 2;
 | |
| 
 | |
| 	/* share name is always preceded by '\\' now */
 | |
| 	delim = strchr(src, '\\');
 | |
| 	if (!delim)
 | |
| 		return ERR_PTR(-EINVAL);
 | |
| 	delim++;
 | |
| 	len = strlen(delim);
 | |
| 
 | |
| 	/* caller has to free the memory */
 | |
| 	dst = kstrndup(delim, len, GFP_KERNEL);
 | |
| 	if (!dst)
 | |
| 		return ERR_PTR(-ENOMEM);
 | |
| 
 | |
| 	return dst;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Superblock object currently keyed by share name
 | |
|  */
 | |
| static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer,
 | |
| 				   uint16_t maxbuf)
 | |
| {
 | |
| 	const struct cifs_tcon *tcon = cookie_netfs_data;
 | |
| 	char *sharename;
 | |
| 	uint16_t len;
 | |
| 
 | |
| 	sharename = extract_sharename(tcon->treeName);
 | |
| 	if (IS_ERR(sharename)) {
 | |
| 		cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__);
 | |
| 		sharename = NULL;
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	len = strlen(sharename);
 | |
| 	if (len > maxbuf)
 | |
| 		return 0;
 | |
| 
 | |
| 	memcpy(buffer, sharename, len);
 | |
| 
 | |
| 	kfree(sharename);
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| static uint16_t
 | |
| cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer,
 | |
| 			   uint16_t maxbuf)
 | |
| {
 | |
| 	struct cifs_fscache_super_auxdata auxdata;
 | |
| 	const struct cifs_tcon *tcon = cookie_netfs_data;
 | |
| 
 | |
| 	memset(&auxdata, 0, sizeof(auxdata));
 | |
| 	auxdata.resource_id = tcon->resource_id;
 | |
| 
 | |
| 	if (maxbuf > sizeof(auxdata))
 | |
| 		maxbuf = sizeof(auxdata);
 | |
| 
 | |
| 	memcpy(buffer, &auxdata, maxbuf);
 | |
| 
 | |
| 	return maxbuf;
 | |
| }
 | |
| 
 | |
| static enum
 | |
| fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data,
 | |
| 					      const void *data,
 | |
| 					      uint16_t datalen)
 | |
| {
 | |
| 	struct cifs_fscache_super_auxdata auxdata;
 | |
| 	const struct cifs_tcon *tcon = cookie_netfs_data;
 | |
| 
 | |
| 	if (datalen != sizeof(auxdata))
 | |
| 		return FSCACHE_CHECKAUX_OBSOLETE;
 | |
| 
 | |
| 	memset(&auxdata, 0, sizeof(auxdata));
 | |
| 	auxdata.resource_id = tcon->resource_id;
 | |
| 
 | |
| 	if (memcmp(data, &auxdata, datalen) != 0)
 | |
| 		return FSCACHE_CHECKAUX_OBSOLETE;
 | |
| 
 | |
| 	return FSCACHE_CHECKAUX_OKAY;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Superblock object for FS-Cache
 | |
|  */
 | |
| const struct fscache_cookie_def cifs_fscache_super_index_def = {
 | |
| 	.name = "CIFS.super",
 | |
| 	.type = FSCACHE_COOKIE_TYPE_INDEX,
 | |
| 	.get_key = cifs_super_get_key,
 | |
| 	.get_aux = cifs_fscache_super_get_aux,
 | |
| 	.check_aux = cifs_fscache_super_check_aux,
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Auxiliary data attached to CIFS inode within the cache
 | |
|  */
 | |
| struct cifs_fscache_inode_auxdata {
 | |
| 	struct timespec	last_write_time;
 | |
| 	struct timespec	last_change_time;
 | |
| 	u64		eof;
 | |
| };
 | |
| 
 | |
| static uint16_t cifs_fscache_inode_get_key(const void *cookie_netfs_data,
 | |
| 					   void *buffer, uint16_t maxbuf)
 | |
| {
 | |
| 	const struct cifsInodeInfo *cifsi = cookie_netfs_data;
 | |
| 	uint16_t keylen;
 | |
| 
 | |
| 	/* use the UniqueId as the key */
 | |
| 	keylen = sizeof(cifsi->uniqueid);
 | |
| 	if (keylen > maxbuf)
 | |
| 		keylen = 0;
 | |
| 	else
 | |
| 		memcpy(buffer, &cifsi->uniqueid, keylen);
 | |
| 
 | |
| 	return keylen;
 | |
| }
 | |
| 
 | |
| static void
 | |
| cifs_fscache_inode_get_attr(const void *cookie_netfs_data, uint64_t *size)
 | |
| {
 | |
| 	const struct cifsInodeInfo *cifsi = cookie_netfs_data;
 | |
| 
 | |
| 	*size = cifsi->vfs_inode.i_size;
 | |
| }
 | |
| 
 | |
| static uint16_t
 | |
| cifs_fscache_inode_get_aux(const void *cookie_netfs_data, void *buffer,
 | |
| 			   uint16_t maxbuf)
 | |
| {
 | |
| 	struct cifs_fscache_inode_auxdata auxdata;
 | |
| 	const struct cifsInodeInfo *cifsi = cookie_netfs_data;
 | |
| 
 | |
| 	memset(&auxdata, 0, sizeof(auxdata));
 | |
| 	auxdata.eof = cifsi->server_eof;
 | |
| 	auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
 | |
| 	auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
 | |
| 
 | |
| 	if (maxbuf > sizeof(auxdata))
 | |
| 		maxbuf = sizeof(auxdata);
 | |
| 
 | |
| 	memcpy(buffer, &auxdata, maxbuf);
 | |
| 
 | |
| 	return maxbuf;
 | |
| }
 | |
| 
 | |
| static enum
 | |
| fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data,
 | |
| 					      const void *data,
 | |
| 					      uint16_t datalen)
 | |
| {
 | |
| 	struct cifs_fscache_inode_auxdata auxdata;
 | |
| 	struct cifsInodeInfo *cifsi = cookie_netfs_data;
 | |
| 
 | |
| 	if (datalen != sizeof(auxdata))
 | |
| 		return FSCACHE_CHECKAUX_OBSOLETE;
 | |
| 
 | |
| 	memset(&auxdata, 0, sizeof(auxdata));
 | |
| 	auxdata.eof = cifsi->server_eof;
 | |
| 	auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
 | |
| 	auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
 | |
| 
 | |
| 	if (memcmp(data, &auxdata, datalen) != 0)
 | |
| 		return FSCACHE_CHECKAUX_OBSOLETE;
 | |
| 
 | |
| 	return FSCACHE_CHECKAUX_OKAY;
 | |
| }
 | |
| 
 | |
| static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data)
 | |
| {
 | |
| 	struct cifsInodeInfo *cifsi = cookie_netfs_data;
 | |
| 	struct pagevec pvec;
 | |
| 	pgoff_t first;
 | |
| 	int loop, nr_pages;
 | |
| 
 | |
| 	pagevec_init(&pvec, 0);
 | |
| 	first = 0;
 | |
| 
 | |
| 	cifs_dbg(FYI, "%s: cifs inode 0x%p now uncached\n", __func__, cifsi);
 | |
| 
 | |
| 	for (;;) {
 | |
| 		nr_pages = pagevec_lookup(&pvec,
 | |
| 					  cifsi->vfs_inode.i_mapping, first,
 | |
| 					  PAGEVEC_SIZE - pagevec_count(&pvec));
 | |
| 		if (!nr_pages)
 | |
| 			break;
 | |
| 
 | |
| 		for (loop = 0; loop < nr_pages; loop++)
 | |
| 			ClearPageFsCache(pvec.pages[loop]);
 | |
| 
 | |
| 		first = pvec.pages[nr_pages - 1]->index + 1;
 | |
| 
 | |
| 		pvec.nr = nr_pages;
 | |
| 		pagevec_release(&pvec);
 | |
| 		cond_resched();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| const struct fscache_cookie_def cifs_fscache_inode_object_def = {
 | |
| 	.name		= "CIFS.uniqueid",
 | |
| 	.type		= FSCACHE_COOKIE_TYPE_DATAFILE,
 | |
| 	.get_key	= cifs_fscache_inode_get_key,
 | |
| 	.get_attr	= cifs_fscache_inode_get_attr,
 | |
| 	.get_aux	= cifs_fscache_inode_get_aux,
 | |
| 	.check_aux	= cifs_fscache_inode_check_aux,
 | |
| 	.now_uncached	= cifs_fscache_inode_now_uncached,
 | |
| };
 |