Commit 54161df1 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (29 commits)
  cifs: fsc should not default to "on"
  [CIFS] remove redundant path walking in dfs_do_refmount
  cifs: ignore the "mand", "nomand" and "_netdev" mount options
  cifs: map NT_STATUS_ERROR_WRITE_PROTECTED to -EROFS
  cifs: don't allow cifs_iget to match inodes of the wrong type
  [CIFS] relinquish fscache cookie before freeing CIFSTconInfo
  cifs: add separate cred_uid field to sesInfo
  fs: cifs: check kmalloc() result
  [CIFS] Missing ifdef
  [CIFS] Missing line from previous commit
  [CIFS] Fix build break when CONFIG_CIFS_FSCACHE disabled
  cifs: add mount option to enable local caching
  cifs: read pages from FS-Cache
  cifs: store pages into local cache
  cifs: FS-Cache page management
  cifs: define inode-level cache object and register them
  cifs: define superblock-level cache index objects and register them
  cifs: remove unused cifsUidInfo struct
  cifs: clean up cifs_find_smb_ses (try #2)
  cifs: match secType when searching for existing tcp session
  ...
parents be82ae02 cb76d5e2
...@@ -131,6 +131,15 @@ config CIFS_DFS_UPCALL ...@@ -131,6 +131,15 @@ config CIFS_DFS_UPCALL
IP addresses) which is needed for implicit mounts of DFS junction IP addresses) which is needed for implicit mounts of DFS junction
points. If unsure, say N. points. If unsure, say N.
config CIFS_FSCACHE
bool "Provide CIFS client caching support (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y
help
Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
to be cached locally on disk through the general filesystem cache
manager. If unsure, say N.
config CIFS_EXPERIMENTAL config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)" bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS && EXPERIMENTAL depends on CIFS && EXPERIMENTAL
......
...@@ -11,3 +11,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ ...@@ -11,3 +11,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
/*
* 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 */
uint16_t 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->addr.sockAddr;
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 = server->addr.sockAddr.sin_family;
key->port = server->addr.sockAddr.sin_port;
key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr;
key_len += sizeof(key->addr[0].ipv4_addr);
break;
case AF_INET6:
key->family = server->addr.sockAddr6.sin6_family;
key->port = server->addr.sockAddr6.sin6_port;
key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr;
key_len += sizeof(key->addr[0].ipv6_addr);
break;
default:
cERROR(1, "CIFS: Unknown network family '%d'", 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 cifsTconInfo *tcon = cookie_netfs_data;
char *sharename;
uint16_t len;
sharename = extract_sharename(tcon->treeName);
if (IS_ERR(sharename)) {
cFYI(1, "CIFS: couldn't extract sharename\n");
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 cifsTconInfo *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 cifsTconInfo *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;
cFYI(1, "cifs inode 0x%p now uncached", 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,
};
...@@ -230,28 +230,22 @@ char *cifs_compose_mount_options(const char *sb_mountdata, ...@@ -230,28 +230,22 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
goto compose_mount_options_out; goto compose_mount_options_out;
} }
/**
static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, * cifs_dfs_do_refmount - mounts specified path using provided refferal
struct dentry *dentry, const struct dfs_info3_param *ref) * @cifs_sb: parent/root superblock
* @fullpath: full path in UNC format
* @ref: server's referral
*/
static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
const char *fullpath, const struct dfs_info3_param *ref)
{ {
struct cifs_sb_info *cifs_sb;
struct vfsmount *mnt; struct vfsmount *mnt;
char *mountdata; char *mountdata;
char *devname = NULL; char *devname = NULL;
char *fullpath;
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
/*
* this function gives us a path with a double backslash prefix. We
* require a single backslash for DFS.
*/
fullpath = build_path_from_dentry(dentry);
if (!fullpath)
return ERR_PTR(-ENOMEM);
/* strip first '\' from fullpath */
mountdata = cifs_compose_mount_options(cifs_sb->mountdata, mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
fullpath + 1, ref, &devname); fullpath + 1, ref, &devname);
kfree(fullpath);
if (IS_ERR(mountdata)) if (IS_ERR(mountdata))
return (struct vfsmount *)mountdata; return (struct vfsmount *)mountdata;
...@@ -357,8 +351,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -357,8 +351,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
rc = -EINVAL; rc = -EINVAL;
goto out_err; goto out_err;
} }
mnt = cifs_dfs_do_refmount(nd->path.mnt, mnt = cifs_dfs_do_refmount(cifs_sb,
nd->path.dentry, referrals + i); full_path, referrals + i);
cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__,
referrals[i].node_name, mnt); referrals[i].node_name, mnt);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ #define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */
#define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/
#define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */
struct cifs_sb_info { struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */
......
...@@ -143,6 +143,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) ...@@ -143,6 +143,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
dp = description + strlen(description); dp = description + strlen(description);
sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); sprintf(dp, ";uid=0x%x", sesInfo->linux_uid);
dp = description + strlen(description);
sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid);
dp = description + strlen(description); dp = description + strlen(description);
sprintf(dp, ";user=%s", sesInfo->userName); sprintf(dp, ";user=%s", sesInfo->userName);
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <linux/key-type.h> #include <linux/key-type.h>
#include "dns_resolve.h" #include "dns_resolve.h"
#include "cifs_spnego.h" #include "cifs_spnego.h"
#include "fscache.h"
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
int cifsFYI = 0; int cifsFYI = 0;
...@@ -328,6 +329,12 @@ cifs_destroy_inode(struct inode *inode) ...@@ -328,6 +329,12 @@ cifs_destroy_inode(struct inode *inode)
kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
} }
static void
cifs_clear_inode(struct inode *inode)
{
cifs_fscache_release_inode_cookie(inode);
}
static void static void
cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
{ {
...@@ -489,6 +496,7 @@ static const struct super_operations cifs_super_ops = { ...@@ -489,6 +496,7 @@ static const struct super_operations cifs_super_ops = {
.alloc_inode = cifs_alloc_inode, .alloc_inode = cifs_alloc_inode,
.destroy_inode = cifs_destroy_inode, .destroy_inode = cifs_destroy_inode,
.drop_inode = cifs_drop_inode, .drop_inode = cifs_drop_inode,
.clear_inode = cifs_clear_inode,
/* .delete_inode = cifs_delete_inode, */ /* Do not need above /* .delete_inode = cifs_delete_inode, */ /* Do not need above
function unless later we add lazy close of inodes or unless the function unless later we add lazy close of inodes or unless the
kernel forgets to call us with the same number of releases (closes) kernel forgets to call us with the same number of releases (closes)
...@@ -902,6 +910,10 @@ init_cifs(void) ...@@ -902,6 +910,10 @@ init_cifs(void)
cFYI(1, "cifs_max_pending set to max of 256"); cFYI(1, "cifs_max_pending set to max of 256");
} }
rc = cifs_fscache_register();
if (rc)
goto out;
rc = cifs_init_inodecache(); rc = cifs_init_inodecache();
if (rc) if (rc)
goto out_clean_proc; goto out_clean_proc;
...@@ -951,6 +963,8 @@ init_cifs(void) ...@@ -951,6 +963,8 @@ init_cifs(void)
cifs_destroy_inodecache(); cifs_destroy_inodecache();
out_clean_proc: out_clean_proc:
cifs_proc_clean(); cifs_proc_clean();
cifs_fscache_unregister();
out:
return rc; return rc;
} }
...@@ -959,6 +973,7 @@ exit_cifs(void) ...@@ -959,6 +973,7 @@ exit_cifs(void)
{ {
cFYI(DBG2, "exit_cifs"); cFYI(DBG2, "exit_cifs");
cifs_proc_clean(); cifs_proc_clean();
cifs_fscache_unregister();
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
cifs_dfs_release_automount_timer(); cifs_dfs_release_automount_timer();
cifs_exit_dns_resolver(); cifs_exit_dns_resolver();
......
...@@ -114,5 +114,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ...@@ -114,5 +114,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */ #endif /* EXPERIMENTAL */
#define CIFS_VERSION "1.64" #define CIFS_VERSION "1.65"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
* the GNU Lesser General Public License for more details. * the GNU Lesser General Public License for more details.
* *
*/ */
#ifndef _CIFS_GLOB_H
#define _CIFS_GLOB_H
#include <linux/in.h> #include <linux/in.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -34,7 +37,7 @@ ...@@ -34,7 +37,7 @@
#define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */
#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null
termination then *2 for unicode versions */ termination then *2 for unicode versions */
#define MAX_PASSWORD_SIZE 16 #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */
#define CIFS_MIN_RCV_POOL 4 #define CIFS_MIN_RCV_POOL 4
...@@ -80,8 +83,7 @@ enum statusEnum { ...@@ -80,8 +83,7 @@ enum statusEnum {
}; };
enum securityEnum { enum securityEnum {
PLAINTXT = 0, /* Legacy with Plaintext passwords */ LANMAN = 0, /* Legacy LANMAN auth */
LANMAN, /* Legacy LANMAN auth */
NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLM, /* Legacy NTLM012 auth with NTLM hash */
NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */
RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */
...@@ -142,7 +144,6 @@ struct TCP_Server_Info { ...@@ -142,7 +144,6 @@ struct TCP_Server_Info {
struct list_head pending_mid_q; struct list_head pending_mid_q;
void *Server_NlsInfo; /* BB - placeholder for future NLS info */ void *Server_NlsInfo; /* BB - placeholder for future NLS info */
unsigned short server_codepage; /* codepage for the server */ unsigned short server_codepage; /* codepage for the server */
unsigned long ip_address; /* IP addr for the server if known */
enum protocolEnum protocolType; enum protocolEnum protocolType;
char versionMajor; char versionMajor;
char versionMinor; char versionMinor;
...@@ -190,19 +191,9 @@ struct TCP_Server_Info { ...@@ -190,19 +191,9 @@ struct TCP_Server_Info {
bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */
bool sec_kerberosu2u; /* supports U2U Kerberos */ bool sec_kerberosu2u; /* supports U2U Kerberos */
bool sec_ntlmssp; /* supports NTLMSSP */ bool sec_ntlmssp; /* supports NTLMSSP */
}; #ifdef CONFIG_CIFS_FSCACHE
struct fscache_cookie *fscache; /* client index cache cookie */
/* #endif
* The following is our shortcut to user information. We surface the uid,
* and name. We always get the password on the fly in case it
* has changed. We also hang a list of sessions owned by this user off here.
*/
struct cifsUidInfo {
struct list_head userList;
struct list_head sessionList; /* SMB sessions for this user */
uid_t linux_uid;
char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */
/* BB may need ptr or callback for PAM or WinBind info */
}; };
/* /*
...@@ -212,9 +203,6 @@ struct cifsSesInfo { ...@@ -212,9 +203,6 @@ struct cifsSesInfo {
struct list_head smb_ses_list; struct list_head smb_ses_list;
struct list_head tcon_list; struct list_head tcon_list;
struct mutex session_mutex; struct mutex session_mutex;
#if 0
struct cifsUidInfo *uidInfo; /* pointer to user info */
#endif
struct TCP_Server_Info *server; /* pointer to server info */ struct TCP_Server_Info *server; /* pointer to server info */
int ses_count; /* reference counter */ int ses_count; /* reference counter */
enum statusEnum status; enum statusEnum status;
...@@ -226,7 +214,8 @@ struct cifsSesInfo { ...@@ -226,7 +214,8 @@ struct cifsSesInfo {
char *serverNOS; /* name of network operating system of server */ char *serverNOS; /* name of network operating system of server */
char *serverDomain; /* security realm of server */ char *serverDomain; /* security realm of server */
int Suid; /* remote smb uid */ int Suid; /* remote smb uid */
uid_t linux_uid; /* local Linux uid */ uid_t linux_uid; /* overriding owner of files on the mount */
uid_t cred_uid; /* owner of credentials */
int capabilities; int capabilities;
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
TCP names - will ipv6 and sctp addresses fit? */ TCP names - will ipv6 and sctp addresses fit? */
...@@ -311,6 +300,10 @@ struct cifsTconInfo { ...@@ -311,6 +300,10 @@ struct cifsTconInfo {
bool local_lease:1; /* check leases (only) on local system not remote */ bool local_lease:1; /* check leases (only) on local system not remote */
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
bool need_reconnect:1; /* connection reset, tid now invalid */ bool need_reconnect:1; /* connection reset, tid now invalid */
#ifdef CONFIG_CIFS_FSCACHE
u64 resource_id; /* server resource id */
struct fscache_cookie *fscache; /* cookie for share */
#endif
/* BB add field for back pointer to sb struct(s)? */ /* BB add field for back pointer to sb struct(s)? */
}; };
...@@ -398,6 +391,9 @@ struct cifsInodeInfo { ...@@ -398,6 +391,9 @@ struct cifsInodeInfo {
bool invalid_mapping:1; /* pagecache is invalid */ bool invalid_mapping:1; /* pagecache is invalid */
u64 server_eof; /* current file size on server */ u64 server_eof; /* current file size on server */
u64 uniqueid; /* server inode number */ u64 uniqueid; /* server inode number */
#ifdef CONFIG_CIFS_FSCACHE
struct fscache_cookie *fscache;
#endif
struct inode vfs_inode; struct inode vfs_inode;
}; };
...@@ -733,3 +729,5 @@ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ ...@@ -733,3 +729,5 @@ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
extern const struct slow_work_ops cifs_oplock_break_ops; extern const struct slow_work_ops cifs_oplock_break_ops;
#endif /* _CIFS_GLOB_H */
...@@ -86,7 +86,9 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr); ...@@ -86,7 +86,9 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
extern int decode_negTokenInit(unsigned char *security_blob, int length, extern int decode_negTokenInit(unsigned char *security_blob, int length,
struct TCP_Server_Info *server); struct TCP_Server_Info *server);
extern int cifs_convert_address(char *src, void *dst); extern int cifs_convert_address(struct sockaddr *dst, char *src);
extern int cifs_fill_sockaddr(struct sockaddr *dst, char *src,
unsigned short int port);
extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
extern void header_assemble(struct smb_hdr *, char /* command */ , extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int /* length of const struct cifsTconInfo *, int /* length of
......
This diff is collapsed.
...@@ -130,12 +130,6 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -130,12 +130,6 @@ build_path_from_dentry(struct dentry *direntry)
return full_path; return full_path;
} }
/*
* When called with struct file pointer set to NULL, there is no way we could
* update file->private_data, but getting it stuck on openFileList provides a
* way to access it from cifs_fill_filedata and thereby set file->private_data
* from cifs_open.
*/
struct cifsFileInfo * struct cifsFileInfo *
cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
struct file *file, struct vfsmount *mnt, unsigned int oflags) struct file *file, struct vfsmount *mnt, unsigned int oflags)
......
...@@ -44,7 +44,7 @@ is_ip(char *name) ...@@ -44,7 +44,7 @@ is_ip(char *name)
{ {
struct sockaddr_storage ss; struct sockaddr_storage ss;
return cifs_convert_address(name, &ss); return cifs_convert_address((struct sockaddr *)&ss, name);
} }
static int static int
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
#include "fscache.h"
static inline int cifs_convert_flags(unsigned int flags) static inline int cifs_convert_flags(unsigned int flags)
{ {
...@@ -282,6 +283,9 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -282,6 +283,9 @@ int cifs_open(struct inode *inode, struct file *file)
CIFSSMBClose(xid, tcon, netfid); CIFSSMBClose(xid, tcon, netfid);
rc = -ENOMEM; rc = -ENOMEM;
} }
cifs_fscache_set_inode_cookie(inode, file);
goto out; goto out;
} else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
if (tcon->ses->serverNOS) if (tcon->ses->serverNOS)
...@@ -373,6 +377,8 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -373,6 +377,8 @@ int cifs_open(struct inode *inode, struct file *file)
goto out; goto out;
} }
cifs_fscache_set_inode_cookie(inode, file);
if (oplock & CIFS_CREATE_ACTION) { if (oplock & CIFS_CREATE_ACTION) {
/* time to set mode which we can not set earlier due to /* time to set mode which we can not set earlier due to
problems creating new read-only files */ problems creating new read-only files */
...@@ -427,7 +433,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) ...@@ -427,7 +433,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
__u16 netfid; __u16 netfid;
if (file->private_data) if (file->private_data)
pCifsFile = (struct cifsFileInfo *)file->private_data; pCifsFile = file->private_data;
else else
return -EBADF; return -EBADF;
...@@ -565,8 +571,7 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -565,8 +571,7 @@ int cifs_close(struct inode *inode, struct file *file)
int xid, timeout; int xid, timeout;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct cifsFileInfo *pSMBFile = struct cifsFileInfo *pSMBFile = file->private_data;
(struct cifsFileInfo *)file->private_data;
xid = GetXid(); xid = GetXid();
...@@ -641,8 +646,7 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -641,8 +646,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
{ {
int rc = 0; int rc = 0;
int xid; int xid;
struct cifsFileInfo *pCFileStruct = struct cifsFileInfo *pCFileStruct = file->private_data;
(struct cifsFileInfo *)file->private_data;
char *ptmp; char *ptmp;
cFYI(1, "Closedir inode = 0x%p", inode); cFYI(1, "Closedir inode = 0x%p", inode);
...@@ -863,8 +867,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -863,8 +867,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
length, pfLock, length, pfLock,
posix_lock_type, wait_flag); posix_lock_type, wait_flag);
} else { } else {
struct cifsFileInfo *fid = struct cifsFileInfo *fid = file->private_data;
(struct cifsFileInfo *)file->private_data;
if (numLock) { if (numLock) {
rc = CIFSSMBLock(xid, tcon, netfid, length, rc = CIFSSMBLock(xid, tcon, netfid, length,
...@@ -965,7 +968,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -965,7 +968,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
if (file->private_data == NULL) if (file->private_data == NULL)
return -EBADF; return -EBADF;
open_file = (struct cifsFileInfo *) file->private_data; open_file = file->private_data;
rc = generic_write_checks(file, poffset, &write_size, 0); rc = generic_write_checks(file, poffset, &write_size, 0);
if (rc) if (rc)
...@@ -1067,7 +1070,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, ...@@ -1067,7 +1070,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
if (file->private_data == NULL) if (file->private_data == NULL)
return -EBADF; return -EBADF;
open_file = (struct cifsFileInfo *)file->private_data; open_file = file->private_data;
xid = GetXid(); xid = GetXid();
...@@ -1651,8 +1654,7 @@ int cifs_fsync(struct file *file, int datasync) ...@@ -1651,8 +1654,7 @@ int cifs_fsync(struct file *file, int datasync)
int xid; int xid;
int rc = 0; int rc = 0;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
struct cifsFileInfo *smbfile = struct cifsFileInfo *smbfile = file->private_data;
(struct cifsFileInfo *)file->private_data;
struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
xid = GetXid(); xid = GetXid();
...@@ -1756,7 +1758,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1756,7 +1758,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
open_file = (struct cifsFileInfo *)file->private_data; open_file = file->private_data;
if ((file->f_flags & O_ACCMODE) == O_WRONLY) if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, "attempting read on write only file instance"); cFYI(1, "attempting read on write only file instance");
...@@ -1837,7 +1839,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, ...@@ -1837,7 +1839,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
open_file = (struct cifsFileInfo *)file->private_data; open_file = file->private_data;
if ((file->f_flags & O_ACCMODE) == O_WRONLY) if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, "attempting read on write only file instance"); cFYI(1, "attempting read on write only file instance");
...@@ -1942,6 +1944,9 @@ static void cifs_copy_cache_pages(struct address_space *mapping, ...@@ -1942,6 +1944,9 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
SetPageUptodate(page); SetPageUptodate(page);
unlock_page(page); unlock_page(page);
data += PAGE_CACHE_SIZE; data += PAGE_CACHE_SIZE;
/* add page to FS-Cache */
cifs_readpage_to_fscache(mapping->host, page);
} }
return; return;
} }
...@@ -1968,10 +1973,19 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1968,10 +1973,19 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
open_file = (struct cifsFileInfo *)file->private_data; open_file = file->private_data;
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
/*
* Reads as many pages as possible from fscache. Returns -ENOBUFS
* immediately if the cookie is negative
*/
rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
&num_pages);
if (rc == 0)
goto read_complete;
cFYI(DBG2, "rpages: num pages %d", num_pages); cFYI(DBG2, "rpages: num pages %d", num_pages);
for (i = 0; i < num_pages; ) { for (i = 0; i < num_pages; ) {
unsigned contig_pages; unsigned contig_pages;
...@@ -2082,6 +2096,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -2082,6 +2096,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
smb_read_data = NULL; smb_read_data = NULL;
} }
read_complete:
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
...@@ -2092,6 +2107,11 @@ static int cifs_readpage_worker(struct file *file, struct page *page, ...@@ -2092,6 +2107,11 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
char *read_data; char *read_data;
int rc; int rc;
/* Is the page cached? */
rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
if (rc == 0)
goto read_complete;
page_cache_get(page); page_cache_get(page);
read_data = kmap(page); read_data = kmap(page);
/* for reads over a certain size could initiate async read ahead */ /* for reads over a certain size could initiate async read ahead */
...@@ -2111,11 +2131,17 @@ static int cifs_readpage_worker(struct file *file, struct page *page, ...@@ -2111,11 +2131,17 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
flush_dcache_page(page); flush_dcache_page(page);
SetPageUptodate(page); SetPageUptodate(page);
/* send this page to the cache */
cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page);
rc = 0; rc = 0;
io_error: io_error:
kunmap(page); kunmap(page);
page_cache_release(page); page_cache_release(page);
read_complete:
return rc; return rc;
} }
...@@ -2265,6 +2291,22 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, ...@@ -2265,6 +2291,22 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping,
return rc; return rc;
} }
static int cifs_release_page(struct page *page, gfp_t gfp)
{
if (PagePrivate(page))
return 0;
return cifs_fscache_release_page(page, gfp);
}
static void cifs_invalidate_page(struct page *page, unsigned long offset)
{
struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
if (offset == 0)
cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
}
static void static void
cifs_oplock_break(struct slow_work *work) cifs_oplock_break(struct slow_work *work)
{ {
...@@ -2338,6 +2380,8 @@ const struct address_space_operations cifs_addr_ops = { ...@@ -2338,6 +2380,8 @@ const struct address_space_operations cifs_addr_ops = {
.write_begin = cifs_write_begin, .write_begin = cifs_write_begin,
.write_end = cifs_write_end, .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers, .set_page_dirty = __set_page_dirty_nobuffers,
.releasepage = cifs_release_page,
.invalidatepage = cifs_invalidate_page,
/* .sync_page = cifs_sync_page, */ /* .sync_page = cifs_sync_page, */
/* .direct_IO = */ /* .direct_IO = */
}; };
...@@ -2354,6 +2398,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { ...@@ -2354,6 +2398,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
.write_begin = cifs_write_begin, .write_begin = cifs_write_begin,
.write_end = cifs_write_end, .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers, .set_page_dirty = __set_page_dirty_nobuffers,
.releasepage = cifs_release_page,
.invalidatepage = cifs_invalidate_page,
/* .sync_page = cifs_sync_page, */ /* .sync_page = cifs_sync_page, */
/* .direct_IO = */ /* .direct_IO = */
}; };
/*
* fs/cifs/fscache.c - CIFS filesystem cache interface
*
* Copyright (c) 2010 Novell, Inc.
* Author(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 "cifsglob.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
{
server->fscache =
fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
&cifs_fscache_server_index_def, server);
cFYI(1, "CIFS: get client cookie (0x%p/0x%p)", server,
server->fscache);
}
void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
{
cFYI(1, "CIFS: release client cookie (0x%p/0x%p)", server,
server->fscache);
fscache_relinquish_cookie(server->fscache, 0);
server->fscache = NULL;
}
void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon)
{
struct TCP_Server_Info *server = tcon->ses->server;
tcon->fscache =
fscache_acquire_cookie(server->fscache,
&cifs_fscache_super_index_def, tcon);
cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)",
server->fscache, tcon->fscache);
}
void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon)
{
cFYI(1, "CIFS: releasing superblock cookie (0x%p)", tcon->fscache);
fscache_relinquish_cookie(tcon->fscache, 0);
tcon->fscache = NULL;
}
static void cifs_fscache_enable_inode_cookie(struct inode *inode)
{
struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
if (cifsi->fscache)
return;
cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache,
&cifs_fscache_inode_object_def,
cifsi);
cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)",
cifs_sb->tcon->fscache, cifsi->fscache);
}
void cifs_fscache_release_inode_cookie(struct inode *inode)
{
struct cifsInodeInfo *cifsi = CIFS_I(inode);
if (cifsi->fscache) {
cFYI(1, "CIFS releasing inode cookie (0x%p)",
cifsi->fscache);
fscache_relinquish_cookie(cifsi->fscache, 0);
cifsi->fscache = NULL;
}
}
static void cifs_fscache_disable_inode_cookie(struct inode *inode)
{
struct cifsInodeInfo *cifsi = CIFS_I(inode);
if (cifsi->fscache) {
cFYI(1, "CIFS disabling inode cookie (0x%p)",
cifsi->fscache);
fscache_relinquish_cookie(cifsi->fscache, 1);
cifsi->fscache = NULL;
}
}
void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
{
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
cifs_fscache_disable_inode_cookie(inode);
else {
cifs_fscache_enable_inode_cookie(inode);
cFYI(1, "CIFS: fscache inode cookie set");
}
}
void cifs_fscache_reset_inode_cookie(struct inode *inode)
{
struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct fscache_cookie *old = cifsi->fscache;
if (cifsi->fscache) {
/* retire the current fscache cache and get a new one */
fscache_relinquish_cookie(cifsi->fscache, 1);
cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache,
&cifs_fscache_inode_object_def,
cifsi);
cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p",
cifsi->fscache, old);
}
}
int cifs_fscache_release_page(struct page *page, gfp_t gfp)
{
if (PageFsCache(page)) {
struct inode *inode = page->mapping->host;
struct cifsInodeInfo *cifsi = CIFS_I(inode);
cFYI(1, "CIFS: fscache release page (0x%p/0x%p)",
page, cifsi->fscache);
if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
return 0;
}
return 1;
}
static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
int error)
{
cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)",
page, error);
if (!error)
SetPageUptodate(page);
unlock_page(page);
}
/*
* Retrieve a page from FS-Cache
*/
int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
{
int ret;
cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p",
CIFS_I(inode)->fscache, page, inode);
ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
cifs_readpage_from_fscache_complete,
NULL,
GFP_KERNEL);
switch (ret) {
case 0: /* page found in fscache, read submitted */
cFYI(1, "CIFS: readpage_from_fscache: submitted");
return ret;
case -ENOBUFS: /* page won't be cached */
case -ENODATA: /* page not in cache */
cFYI(1, "CIFS: readpage_from_fscache %d", ret);
return 1;
default:
cERROR(1, "unknown error ret = %d", ret);
}
return ret;
}
/*
* Retrieve a set of pages from FS-Cache
*/
int __cifs_readpages_from_fscache(struct inode *inode,
struct address_space *mapping,
struct list_head *pages,
unsigned *nr_pages)
{
int ret;
cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)",
CIFS_I(inode)->fscache, *nr_pages, inode);
ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
pages, nr_pages,
cifs_readpage_from_fscache_complete,
NULL,
mapping_gfp_mask(mapping));
switch (ret) {
case 0: /* read submitted to the cache for all pages */
cFYI(1, "CIFS: readpages_from_fscache: submitted");
return ret;
case -ENOBUFS: /* some pages are not cached and can't be */
case -ENODATA: /* some pages are not cached */
cFYI(1, "CIFS: readpages_from_fscache: no page");
return 1;
default:
cFYI(1, "unknown error ret = %d", ret);
}
return ret;
}
void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
{
int ret;
cFYI(1, "CIFS: readpage_to_fscache(fsc: %p, p: %p, i: %p",
CIFS_I(inode)->fscache, page, inode);
ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL);
if (ret != 0)
fscache_uncache_page(CIFS_I(inode)->fscache, page);
}
void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
{
struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct fscache_cookie *cookie = cifsi->fscache;
cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie);
fscache_wait_on_page_write(cookie, page);
fscache_uncache_page(cookie, page);
}
/*
* fs/cifs/fscache.h - CIFS filesystem cache interface 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
*/
#ifndef _CIFS_FSCACHE_H
#define _CIFS_FSCACHE_H
#include <linux/fscache.h>
#include "cifsglob.h"
#ifdef CONFIG_CIFS_FSCACHE
extern struct fscache_netfs cifs_fscache_netfs;
extern const struct fscache_cookie_def cifs_fscache_server_index_def;
extern const struct fscache_cookie_def cifs_fscache_super_index_def;
extern const struct fscache_cookie_def cifs_fscache_inode_object_def;
extern int cifs_fscache_register(void);
extern void cifs_fscache_unregister(void);
/*
* fscache.c
*/
extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *);
extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *);
extern void cifs_fscache_get_super_cookie(struct cifsTconInfo *);
extern void cifs_fscache_release_super_cookie(struct cifsTconInfo *);
extern void cifs_fscache_release_inode_cookie(struct inode *);
extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
extern void cifs_fscache_reset_inode_cookie(struct inode *);
extern void __cifs_fscache_invalidate_page(struct page *, struct inode *);
extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
extern int __cifs_readpages_from_fscache(struct inode *,
struct address_space *,
struct list_head *,
unsigned *);
extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
static inline void cifs_fscache_invalidate_page(struct page *page,
struct inode *inode)
{
if (PageFsCache(page))
__cifs_fscache_invalidate_page(page, inode);
}
static inline int cifs_readpage_from_fscache(struct inode *inode,
struct page *page)
{
if (CIFS_I(inode)->fscache)
return __cifs_readpage_from_fscache(inode, page);
return -ENOBUFS;
}
static inline int cifs_readpages_from_fscache(struct inode *inode,
struct address_space *mapping,
struct list_head *pages,
unsigned *nr_pages)
{
if (CIFS_I(inode)->fscache)
return __cifs_readpages_from_fscache(inode, mapping, pages,
nr_pages);
return -ENOBUFS;
}
static inline void cifs_readpage_to_fscache(struct inode *inode,
struct page *page)
{
if (PageFsCache(page))
__cifs_readpage_to_fscache(inode, page);
}
#else /* CONFIG_CIFS_FSCACHE */
static inline int cifs_fscache_register(void) { return 0; }
static inline void cifs_fscache_unregister(void) {}
static inline void
cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {}
static inline void
cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {}
static inline void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) {}
static inline void
cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) {}
static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {}
static inline void cifs_fscache_set_inode_cookie(struct inode *inode,
struct file *filp) {}
static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {}
static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
{
return 1; /* May release page */
}
static inline void cifs_fscache_invalidate_page(struct page *page,
struct inode *inode) {}
static inline int
cifs_readpage_from_fscache(struct inode *inode, struct page *page)
{
return -ENOBUFS;
}
static inline int cifs_readpages_from_fscache(struct inode *inode,
struct address_space *mapping,
struct list_head *pages,
unsigned *nr_pages)
{
return -ENOBUFS;
}
static inline void cifs_readpage_to_fscache(struct inode *inode,
struct page *page) {}
#endif /* CONFIG_CIFS_FSCACHE */
#endif /* _CIFS_FSCACHE_H */
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
#include "fscache.h"
static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
...@@ -288,7 +289,7 @@ int cifs_get_file_info_unix(struct file *filp) ...@@ -288,7 +289,7 @@ int cifs_get_file_info_unix(struct file *filp)
struct inode *inode = filp->f_path.dentry->d_inode; struct inode *inode = filp->f_path.dentry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *tcon = cifs_sb->tcon; struct cifsTconInfo *tcon = cifs_sb->tcon;
struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; struct cifsFileInfo *cfile = filp->private_data;
xid = GetXid(); xid = GetXid();
rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
...@@ -515,7 +516,7 @@ int cifs_get_file_info(struct file *filp) ...@@ -515,7 +516,7 @@ int cifs_get_file_info(struct file *filp)
struct inode *inode = filp->f_path.dentry->d_inode; struct inode *inode = filp->f_path.dentry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *tcon = cifs_sb->tcon; struct cifsTconInfo *tcon = cifs_sb->tcon;
struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; struct cifsFileInfo *cfile = filp->private_data;
xid = GetXid(); xid = GetXid();
rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
...@@ -723,9 +724,14 @@ cifs_find_inode(struct inode *inode, void *opaque) ...@@ -723,9 +724,14 @@ cifs_find_inode(struct inode *inode, void *opaque)
{ {
struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
/* don't match inode with different uniqueid */
if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
return 0; return 0;
/* don't match inode of different type */
if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
return 0;
/* /*
* uh oh -- it's a directory. We can't use it since hardlinked dirs are * uh oh -- it's a directory. We can't use it since hardlinked dirs are
* verboten. Disable serverino and return it as if it were found, the * verboten. Disable serverino and return it as if it were found, the
...@@ -776,6 +782,10 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) ...@@ -776,6 +782,10 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
inode->i_flags |= S_NOATIME | S_NOCMTIME; inode->i_flags |= S_NOATIME | S_NOCMTIME;
if (inode->i_state & I_NEW) { if (inode->i_state & I_NEW) {
inode->i_ino = hash; inode->i_ino = hash;
#ifdef CONFIG_CIFS_FSCACHE
/* initialize per-inode cache cookie pointer */
CIFS_I(inode)->fscache = NULL;
#endif
unlock_new_inode(inode); unlock_new_inode(inode);
} }
} }
...@@ -807,6 +817,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) ...@@ -807,6 +817,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
if (!inode) if (!inode)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
#ifdef CONFIG_CIFS_FSCACHE
/* populate tcon->resource_id */
cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid;
#endif
if (rc && cifs_sb->tcon->ipc) { if (rc && cifs_sb->tcon->ipc) {
cFYI(1, "ipc connection - fake read inode"); cFYI(1, "ipc connection - fake read inode");
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
...@@ -1568,6 +1583,7 @@ cifs_invalidate_mapping(struct inode *inode) ...@@ -1568,6 +1583,7 @@ cifs_invalidate_mapping(struct inode *inode)
cifs_i->write_behind_rc = rc; cifs_i->write_behind_rc = rc;
} }
invalidate_remote_inode(inode); invalidate_remote_inode(inode);
cifs_fscache_reset_inode_cookie(inode);
} }
int cifs_revalidate_file(struct file *filp) int cifs_revalidate_file(struct file *filp)
......
...@@ -41,8 +41,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -41,8 +41,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
__u64 ExtAttrMask = 0; __u64 ExtAttrMask = 0;
__u64 caps; __u64 caps;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
struct cifsFileInfo *pSMBFile = struct cifsFileInfo *pSMBFile = filep->private_data;
(struct cifsFileInfo *)filep->private_data;
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
xid = GetXid(); xid = GetXid();
......
...@@ -61,6 +61,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { ...@@ -61,6 +61,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{ERRremcd, -EACCES}, {ERRremcd, -EACCES},
{ERRdiffdevice, -EXDEV}, {ERRdiffdevice, -EXDEV},
{ERRnofiles, -ENOENT}, {ERRnofiles, -ENOENT},
{ERRwriteprot, -EROFS},
{ERRbadshare, -ETXTBSY}, {ERRbadshare, -ETXTBSY},
{ERRlock, -EACCES}, {ERRlock, -EACCES},
{ERRunsup, -EINVAL}, {ERRunsup, -EINVAL},
...@@ -164,7 +165,7 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) ...@@ -164,7 +165,7 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
* Returns 0 on failure. * Returns 0 on failure.
*/ */
int int
cifs_convert_address(char *src, void *dst) cifs_convert_address(struct sockaddr *dst, char *src)
{ {
int rc; int rc;
char *pct, *endp; char *pct, *endp;
...@@ -201,6 +202,27 @@ cifs_convert_address(char *src, void *dst) ...@@ -201,6 +202,27 @@ cifs_convert_address(char *src, void *dst)
return rc; return rc;
} }
int
cifs_fill_sockaddr(struct sockaddr *dst, char *src,
const unsigned short int port)
{
if (!cifs_convert_address(dst, src))
return 0;
switch (dst->sa_family) {
case AF_INET:
((struct sockaddr_in *)dst)->sin_port = htons(port);
break;
case AF_INET6:
((struct sockaddr_in6 *)dst)->sin6_port = htons(port);
break;
default:
return 0;
}
return 1;
}
/***************************************************************************** /*****************************************************************************
convert a NT status code to a dos class/code convert a NT status code to a dos class/code
*****************************************************************************/ *****************************************************************************/
......
...@@ -847,6 +847,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -847,6 +847,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
if (tmp_buf == NULL) {
rc = -ENOMEM;
break;
}
for (i = 0; (i < num_to_fill) && (rc == 0); i++) { for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
if (current_entry == NULL) { if (current_entry == NULL) {
/* evaluate whether this case is an error */ /* evaluate whether this case is an error */
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
#define ERRnofiles 18 /* A File Search command can find no #define ERRnofiles 18 /* A File Search command can find no
more files matching the specified more files matching the specified
criteria. */ criteria. */
#define ERRwriteprot 19 /* media is write protected */
#define ERRgeneral 31 #define ERRgeneral 31
#define ERRbadshare 32 /* The sharing mode specified for an #define ERRbadshare 32 /* The sharing mode specified for an
Open conflicts with existing FIDs on Open conflicts with existing FIDs on
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment