Commit f87f60b3 authored by Pavel Shilovsky's avatar Pavel Shilovsky

Add strict cache mode for 2.6.35

parent edc2bedb
...@@ -433,6 +433,11 @@ A partial list of the supported mount options follows: ...@@ -433,6 +433,11 @@ A partial list of the supported mount options follows:
if oplock (caching token) is granted and held. Note that if oplock (caching token) is granted and held. Note that
direct allows write operations larger than page size direct allows write operations larger than page size
to be sent to the server. to be sent to the server.
strictcache Use for switching on strict cache mode. In this mode the
client reads from the cache all the time it has Oplock Level II,
otherwise - reads from the server. All written data are stored
in the cache, but if the client doesn't have Exclusive Oplock,
it writes the data to the server.
acl Allow setfacl and getfacl to manage posix ACLs if server acl Allow setfacl and getfacl to manage posix ACLs if server
supports them. (default) supports them. (default)
noacl Do not allow setfacl and getfacl calls on this mount noacl Do not allow setfacl and getfacl calls on this mount
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#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_WINE_MODE 0x8000 /* use pid forwarding for wine apps */ #define CIFS_MOUNT_WINE_MODE 0x8000 /* use pid forwarding for wine apps */
#define CIFS_MOUNT_STRICT_IO 0x10000 /* strict cache mode */
struct cifs_sb_info { struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */
......
...@@ -308,8 +308,7 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -308,8 +308,7 @@ cifs_alloc_inode(struct super_block *sb)
/* Until the file is open and we have gotten oplock /* Until the file is open and we have gotten oplock
info back from the server, can not assume caching of info back from the server, can not assume caching of
file data or metadata */ file data or metadata */
cifs_inode->clientCanCacheRead = false; cifs_set_oplock_level(cifs_inode, 0);
cifs_inode->clientCanCacheAll = false;
cifs_inode->delete_pending = false; cifs_inode->delete_pending = false;
cifs_inode->invalid_mapping = false; cifs_inode->invalid_mapping = false;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
...@@ -538,10 +537,17 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -538,10 +537,17 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
{ {
struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
ssize_t written; ssize_t written;
int rc;
written = generic_file_aio_write(iocb, iov, nr_segs, pos); written = generic_file_aio_write(iocb, iov, nr_segs, pos);
if (!CIFS_I(inode)->clientCanCacheAll)
filemap_fdatawrite(inode->i_mapping); if (CIFS_I(inode)->clientCanCacheAll)
return written;
rc = filemap_fdatawrite(inode->i_mapping);
if (rc)
cFYI(1, "cifs_file_aio_write: %d rc on %p inode", rc, inode);
return written; return written;
} }
...@@ -670,6 +676,25 @@ const struct file_operations cifs_file_ops = { ...@@ -670,6 +676,25 @@ const struct file_operations cifs_file_ops = {
.setlease = cifs_setlease, .setlease = cifs_setlease,
}; };
const struct file_operations cifs_file_strict_ops = {
.read = do_sync_read,
.write = do_sync_write,
.aio_read = cifs_strict_readv,
.aio_write = cifs_strict_writev,
.open = cifs_open,
.release = cifs_close,
.lock = cifs_lock,
.fsync = cifs_strict_fsync,
.flush = cifs_flush,
.mmap = cifs_file_strict_mmap,
.splice_read = generic_file_splice_read,
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
.setlease = cifs_setlease,
};
const struct file_operations cifs_file_direct_ops = { const struct file_operations cifs_file_direct_ops = {
/* no aio, no readv - /* no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */ BB reevaluate whether they can be done with directio, no cache */
...@@ -688,6 +713,7 @@ const struct file_operations cifs_file_direct_ops = { ...@@ -688,6 +713,7 @@ const struct file_operations cifs_file_direct_ops = {
.llseek = cifs_llseek, .llseek = cifs_llseek,
.setlease = cifs_setlease, .setlease = cifs_setlease,
}; };
const struct file_operations cifs_file_nobrl_ops = { const struct file_operations cifs_file_nobrl_ops = {
.read = do_sync_read, .read = do_sync_read,
.write = do_sync_write, .write = do_sync_write,
...@@ -706,6 +732,24 @@ const struct file_operations cifs_file_nobrl_ops = { ...@@ -706,6 +732,24 @@ const struct file_operations cifs_file_nobrl_ops = {
.setlease = cifs_setlease, .setlease = cifs_setlease,
}; };
const struct file_operations cifs_file_strict_nobrl_ops = {
.read = do_sync_read,
.write = do_sync_write,
.aio_read = cifs_strict_readv,
.aio_write = cifs_strict_writev,
.open = cifs_open,
.release = cifs_close,
.fsync = cifs_strict_fsync,
.flush = cifs_flush,
.mmap = cifs_file_strict_mmap,
.splice_read = generic_file_splice_read,
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
.setlease = cifs_setlease,
};
const struct file_operations cifs_file_direct_nobrl_ops = { const struct file_operations cifs_file_direct_nobrl_ops = {
/* no mmap, no aio, no readv - /* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */ BB reevaluate whether they can be done with directio, no cache */
......
...@@ -63,6 +63,7 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *, ...@@ -63,6 +63,7 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
struct dentry *); struct dentry *);
extern int cifs_revalidate_file(struct file *filp); extern int cifs_revalidate_file(struct file *filp);
extern int cifs_revalidate_dentry(struct dentry *); extern int cifs_revalidate_dentry(struct dentry *);
extern void cifs_invalidate_mapping(struct inode *inode);
extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int cifs_setattr(struct dentry *, struct iattr *); extern int cifs_setattr(struct dentry *, struct iattr *);
...@@ -74,19 +75,27 @@ extern const struct inode_operations cifs_dfs_referral_inode_operations; ...@@ -74,19 +75,27 @@ extern const struct inode_operations cifs_dfs_referral_inode_operations;
/* Functions related to files and directories */ /* Functions related to files and directories */
extern const struct file_operations cifs_file_ops; extern const struct file_operations cifs_file_ops;
extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
extern const struct file_operations cifs_file_nobrl_ops; extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */
extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */ extern const struct file_operations cifs_file_nobrl_ops; /* no brlocks */
extern const struct file_operations cifs_file_direct_nobrl_ops;
extern const struct file_operations cifs_file_strict_nobrl_ops;
extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_open(struct inode *inode, struct file *file);
extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file);
extern int cifs_closedir(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file);
extern ssize_t cifs_user_read(struct file *file, char __user *read_data, extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
size_t read_size, loff_t *poffset); size_t read_size, loff_t *poffset);
extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
size_t write_size, loff_t *poffset); size_t write_size, loff_t *poffset);
extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, int); extern int cifs_fsync(struct file *, int);
extern int cifs_strict_fsync(struct file *, int);
extern int cifs_flush(struct file *, fl_owner_t id); extern int cifs_flush(struct file *, fl_owner_t id);
extern int cifs_file_mmap(struct file * , struct vm_area_struct *); extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
extern const struct file_operations cifs_dir_ops; extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file); extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
......
...@@ -82,6 +82,8 @@ extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); ...@@ -82,6 +82,8 @@ extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *); extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
#endif #endif
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written);
extern unsigned int smbCalcSize(struct smb_hdr *ptr); 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,
...@@ -101,6 +103,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); ...@@ -101,6 +103,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
extern u64 cifs_UnixTimeToNT(struct timespec); extern u64 cifs_UnixTimeToNT(struct timespec);
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
int offset); int offset);
extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode,
__u16 fileHandle, struct file *file, __u16 fileHandle, struct file *file,
......
...@@ -83,6 +83,7 @@ struct smb_vol { ...@@ -83,6 +83,7 @@ struct smb_vol {
bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
bool server_ino:1; /* use inode numbers from server ie UniqueId */ bool server_ino:1; /* use inode numbers from server ie UniqueId */
bool direct_io:1; bool direct_io:1;
bool strict_io:1; /* strict cache behavior */
bool remap:1; /* set to remap seven reserved chars in filenames */ bool remap:1; /* set to remap seven reserved chars in filenames */
bool posix_paths:1; /* unset to not ask for posix pathnames. */ bool posix_paths:1; /* unset to not ask for posix pathnames. */
bool no_linux_ext:1; bool no_linux_ext:1;
...@@ -1307,7 +1308,7 @@ cifs_parse_mount_options(char *options, const char *devname, ...@@ -1307,7 +1308,7 @@ cifs_parse_mount_options(char *options, const char *devname,
} else if (strnicmp(data, "wine", 4) == 0) { } else if (strnicmp(data, "wine", 4) == 0) {
vol->wine_mode = 1; vol->wine_mode = 1;
vol->mand_lock = 1; vol->mand_lock = 1;
vol->direct_io = 1; vol->strict_io = 1;
} else if (strnicmp(data, "cifsacl", 7) == 0) { } else if (strnicmp(data, "cifsacl", 7) == 0) {
vol->cifs_acl = 1; vol->cifs_acl = 1;
} else if (strnicmp(data, "nocifsacl", 9) == 0) { } else if (strnicmp(data, "nocifsacl", 9) == 0) {
...@@ -1332,6 +1333,8 @@ cifs_parse_mount_options(char *options, const char *devname, ...@@ -1332,6 +1333,8 @@ cifs_parse_mount_options(char *options, const char *devname,
vol->direct_io = 1; vol->direct_io = 1;
} else if (strnicmp(data, "forcedirectio", 13) == 0) { } else if (strnicmp(data, "forcedirectio", 13) == 0) {
vol->direct_io = 1; vol->direct_io = 1;
} else if (strnicmp(data, "strictcache", 11) == 0) {
vol->strict_io = 1;
} else if (strnicmp(data, "noac", 4) == 0) { } else if (strnicmp(data, "noac", 4) == 0) {
printk(KERN_WARNING "CIFS: Mount option noac not " printk(KERN_WARNING "CIFS: Mount option noac not "
"supported. Instead set " "supported. Instead set "
...@@ -2427,6 +2430,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, ...@@ -2427,6 +2430,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
if (pvolume_info->dynperm) if (pvolume_info->dynperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
if (pvolume_info->strict_io)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
if (pvolume_info->direct_io) { if (pvolume_info->direct_io) {
cFYI(1, "mounting share using direct i/o"); cFYI(1, "mounting share using direct i/o");
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
......
...@@ -162,9 +162,11 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, ...@@ -162,9 +162,11 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
atomic_set(&pCifsFile->count, 1); atomic_set(&pCifsFile->count, 1);
slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops); slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops);
pCifsInode = CIFS_I(newinode);
if (pCifsInode)
cifs_set_oplock_level(pCifsInode, oplock);
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
pCifsInode = CIFS_I(newinode);
if (pCifsInode) { if (pCifsInode) {
/* if readable file instance put first in list*/ /* if readable file instance put first in list*/
if (oflags & FMODE_READ) if (oflags & FMODE_READ)
...@@ -172,13 +174,6 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, ...@@ -172,13 +174,6 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
else else
list_add_tail(&pCifsFile->flist, list_add_tail(&pCifsFile->flist,
&pCifsInode->openFileList); &pCifsInode->openFileList);
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = true;
pCifsInode->clientCanCacheRead = true;
cFYI(1, "Exclusive Oplock inode %p", newinode);
} else if ((oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = true;
} }
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
......
...@@ -43,13 +43,17 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) ...@@ -43,13 +43,17 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
inode->i_fop = &cifs_file_direct_nobrl_ops; inode->i_fop = &cifs_file_direct_nobrl_ops;
else else
inode->i_fop = &cifs_file_direct_ops; inode->i_fop = &cifs_file_direct_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_strict_nobrl_ops;
else
inode->i_fop = &cifs_file_strict_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops; inode->i_fop = &cifs_file_nobrl_ops;
else { /* not direct, send byte range locks */ else { /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops; inode->i_fop = &cifs_file_ops;
} }
/* check if server can support readpages */ /* check if server can support readpages */
if (cifs_sb->tcon->ses->server->maxBuf < if (cifs_sb->tcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
...@@ -1552,8 +1556,10 @@ cifs_inode_needs_reval(struct inode *inode) ...@@ -1552,8 +1556,10 @@ cifs_inode_needs_reval(struct inode *inode)
return false; return false;
} }
/* check invalid_mapping flag and zap the cache if it's set */ /*
static void * Zap the cache. Called when invalid_mapping flag is set.
*/
void
cifs_invalidate_mapping(struct inode *inode) cifs_invalidate_mapping(struct inode *inode)
{ {
int rc; int rc;
...@@ -1566,8 +1572,13 @@ cifs_invalidate_mapping(struct inode *inode) ...@@ -1566,8 +1572,13 @@ cifs_invalidate_mapping(struct inode *inode)
rc = filemap_write_and_wait(inode->i_mapping); rc = filemap_write_and_wait(inode->i_mapping);
if (rc) if (rc)
cifs_i->write_behind_rc = rc; cifs_i->write_behind_rc = rc;
rc = invalidate_inode_pages2(inode->i_mapping);
if (rc) {
cERROR(1, "%s: could not invalidate inode %p", __func__,
inode);
cifs_i->invalid_mapping = true;
}
} }
invalidate_remote_inode(inode);
} }
int cifs_revalidate_file(struct file *filp) int cifs_revalidate_file(struct file *filp)
......
...@@ -568,6 +568,10 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -568,6 +568,10 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
if (pSMB->Fid != netfile->netfid) if (pSMB->Fid != netfile->netfid)
continue; continue;
cFYI(1, "file id match, oplock break");
pCifsInode = CIFS_I(netfile->pInode);
cifs_set_oplock_level(pCifsInode,
pSMB->OplockLevel ? OPLOCK_READ : 0);
/* /*
* don't do anything if file is about to be * don't do anything if file is about to be
* closed anyway. * closed anyway.
...@@ -578,11 +582,6 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -578,11 +582,6 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
return true; return true;
} }
cFYI(1, "file id match, oplock break");
pCifsInode = CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = false;
if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead = false;
rc = slow_work_enqueue(&netfile->oplock_break); rc = slow_work_enqueue(&netfile->oplock_break);
if (rc) { if (rc) {
cERROR(1, "failed to enqueue oplock " cERROR(1, "failed to enqueue oplock "
...@@ -728,3 +727,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) ...@@ -728,3 +727,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
cifs_sb->tcon->treeName); cifs_sb->tcon->treeName);
} }
} }
void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
{
oplock &= 0xF;
if (oplock == OPLOCK_EXCLUSIVE) {
cinode->clientCanCacheAll = true;
cinode->clientCanCacheRead = true;
cFYI(1, "Exclusive Oplock granted on inode %p",
&cinode->vfs_inode);
} else if (oplock == OPLOCK_READ) {
cinode->clientCanCacheAll = false;
cinode->clientCanCacheRead = true;
cFYI(1, "Level II Oplock granted on inode %p",
&cinode->vfs_inode);
} else {
cinode->clientCanCacheAll = false;
cinode->clientCanCacheRead = false;
}
}
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