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: cifs: fix locking and list handling code in cifs_open and its helper [CIFS] Remove build warning cifs: fix problems with last two commits [CIFS] Fix build break when keys support turned off cifs: eliminate cifs_init_private cifs: convert oplock breaks to use slow_work facility (try #4) cifs: have cifsFileInfo hold an extra inode reference cifs: take read lock on GlobalSMBSes_lock in is_valid_oplock_break cifs: remove cifsInodeInfo.oplockPending flag cifs: fix oplock request handling in posix codepath [CIFS] Re-enable Lanman security
This commit is contained in:
@@ -2,6 +2,7 @@ config CIFS
|
|||||||
tristate "CIFS support (advanced network filesystem, SMBFS successor)"
|
tristate "CIFS support (advanced network filesystem, SMBFS successor)"
|
||||||
depends on INET
|
depends on INET
|
||||||
select NLS
|
select NLS
|
||||||
|
select SLOW_WORK
|
||||||
help
|
help
|
||||||
This is the client VFS module for the Common Internet File System
|
This is the client VFS module for the Common Internet File System
|
||||||
(CIFS) protocol which is the successor to the Server Message Block
|
(CIFS) protocol which is the successor to the Server Message Block
|
||||||
|
@@ -64,9 +64,6 @@ unsigned int multiuser_mount = 0;
|
|||||||
unsigned int extended_security = CIFSSEC_DEF;
|
unsigned int extended_security = CIFSSEC_DEF;
|
||||||
/* unsigned int ntlmv2_support = 0; */
|
/* unsigned int ntlmv2_support = 0; */
|
||||||
unsigned int sign_CIFS_PDUs = 1;
|
unsigned int sign_CIFS_PDUs = 1;
|
||||||
extern struct task_struct *oplockThread; /* remove sparse warning */
|
|
||||||
struct task_struct *oplockThread = NULL;
|
|
||||||
/* extern struct task_struct * dnotifyThread; remove sparse warning */
|
|
||||||
static const struct super_operations cifs_super_ops;
|
static const struct super_operations cifs_super_ops;
|
||||||
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
|
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
|
||||||
module_param(CIFSMaxBufSize, int, 0);
|
module_param(CIFSMaxBufSize, int, 0);
|
||||||
@@ -972,89 +969,12 @@ cifs_destroy_mids(void)
|
|||||||
kmem_cache_destroy(cifs_oplock_cachep);
|
kmem_cache_destroy(cifs_oplock_cachep);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cifs_oplock_thread(void *dummyarg)
|
|
||||||
{
|
|
||||||
struct oplock_q_entry *oplock_item;
|
|
||||||
struct cifsTconInfo *pTcon;
|
|
||||||
struct inode *inode;
|
|
||||||
__u16 netfid;
|
|
||||||
int rc, waitrc = 0;
|
|
||||||
|
|
||||||
set_freezable();
|
|
||||||
do {
|
|
||||||
if (try_to_freeze())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
spin_lock(&cifs_oplock_lock);
|
|
||||||
if (list_empty(&cifs_oplock_list)) {
|
|
||||||
spin_unlock(&cifs_oplock_lock);
|
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
|
||||||
schedule_timeout(39*HZ);
|
|
||||||
} else {
|
|
||||||
oplock_item = list_entry(cifs_oplock_list.next,
|
|
||||||
struct oplock_q_entry, qhead);
|
|
||||||
cFYI(1, ("found oplock item to write out"));
|
|
||||||
pTcon = oplock_item->tcon;
|
|
||||||
inode = oplock_item->pinode;
|
|
||||||
netfid = oplock_item->netfid;
|
|
||||||
spin_unlock(&cifs_oplock_lock);
|
|
||||||
DeleteOplockQEntry(oplock_item);
|
|
||||||
/* can not grab inode sem here since it would
|
|
||||||
deadlock when oplock received on delete
|
|
||||||
since vfs_unlink holds the i_mutex across
|
|
||||||
the call */
|
|
||||||
/* mutex_lock(&inode->i_mutex);*/
|
|
||||||
if (S_ISREG(inode->i_mode)) {
|
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
|
||||||
if (CIFS_I(inode)->clientCanCacheAll == 0)
|
|
||||||
break_lease(inode, FMODE_READ);
|
|
||||||
else if (CIFS_I(inode)->clientCanCacheRead == 0)
|
|
||||||
break_lease(inode, FMODE_WRITE);
|
|
||||||
#endif
|
|
||||||
rc = filemap_fdatawrite(inode->i_mapping);
|
|
||||||
if (CIFS_I(inode)->clientCanCacheRead == 0) {
|
|
||||||
waitrc = filemap_fdatawait(
|
|
||||||
inode->i_mapping);
|
|
||||||
invalidate_remote_inode(inode);
|
|
||||||
}
|
|
||||||
if (rc == 0)
|
|
||||||
rc = waitrc;
|
|
||||||
} else
|
|
||||||
rc = 0;
|
|
||||||
/* mutex_unlock(&inode->i_mutex);*/
|
|
||||||
if (rc)
|
|
||||||
CIFS_I(inode)->write_behind_rc = rc;
|
|
||||||
cFYI(1, ("Oplock flush inode %p rc %d",
|
|
||||||
inode, rc));
|
|
||||||
|
|
||||||
/* releasing stale oplock after recent reconnect
|
|
||||||
of smb session using a now incorrect file
|
|
||||||
handle is not a data integrity issue but do
|
|
||||||
not bother sending an oplock release if session
|
|
||||||
to server still is disconnected since oplock
|
|
||||||
already released by the server in that case */
|
|
||||||
if (!pTcon->need_reconnect) {
|
|
||||||
rc = CIFSSMBLock(0, pTcon, netfid,
|
|
||||||
0 /* len */ , 0 /* offset */, 0,
|
|
||||||
0, LOCKING_ANDX_OPLOCK_RELEASE,
|
|
||||||
false /* wait flag */);
|
|
||||||
cFYI(1, ("Oplock release rc = %d", rc));
|
|
||||||
}
|
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
|
||||||
schedule_timeout(1); /* yield in case q were corrupt */
|
|
||||||
}
|
|
||||||
} while (!kthread_should_stop());
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init
|
static int __init
|
||||||
init_cifs(void)
|
init_cifs(void)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
cifs_proc_init();
|
cifs_proc_init();
|
||||||
INIT_LIST_HEAD(&cifs_tcp_ses_list);
|
INIT_LIST_HEAD(&cifs_tcp_ses_list);
|
||||||
INIT_LIST_HEAD(&cifs_oplock_list);
|
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
INIT_LIST_HEAD(&GlobalDnotifyReqList);
|
INIT_LIST_HEAD(&GlobalDnotifyReqList);
|
||||||
INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
|
INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
|
||||||
@@ -1083,7 +1003,6 @@ init_cifs(void)
|
|||||||
rwlock_init(&GlobalSMBSeslock);
|
rwlock_init(&GlobalSMBSeslock);
|
||||||
rwlock_init(&cifs_tcp_ses_lock);
|
rwlock_init(&cifs_tcp_ses_lock);
|
||||||
spin_lock_init(&GlobalMid_Lock);
|
spin_lock_init(&GlobalMid_Lock);
|
||||||
spin_lock_init(&cifs_oplock_lock);
|
|
||||||
|
|
||||||
if (cifs_max_pending < 2) {
|
if (cifs_max_pending < 2) {
|
||||||
cifs_max_pending = 2;
|
cifs_max_pending = 2;
|
||||||
@@ -1118,16 +1037,13 @@ init_cifs(void)
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto out_unregister_key_type;
|
goto out_unregister_key_type;
|
||||||
#endif
|
#endif
|
||||||
oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
|
rc = slow_work_register_user();
|
||||||
if (IS_ERR(oplockThread)) {
|
if (rc)
|
||||||
rc = PTR_ERR(oplockThread);
|
goto out_unregister_resolver_key;
|
||||||
cERROR(1, ("error %d create oplock thread", rc));
|
|
||||||
goto out_unregister_dfs_key_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_unregister_dfs_key_type:
|
out_unregister_resolver_key:
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
unregister_key_type(&key_type_dns_resolver);
|
unregister_key_type(&key_type_dns_resolver);
|
||||||
out_unregister_key_type:
|
out_unregister_key_type:
|
||||||
@@ -1164,7 +1080,6 @@ exit_cifs(void)
|
|||||||
cifs_destroy_inodecache();
|
cifs_destroy_inodecache();
|
||||||
cifs_destroy_mids();
|
cifs_destroy_mids();
|
||||||
cifs_destroy_request_bufs();
|
cifs_destroy_request_bufs();
|
||||||
kthread_stop(oplockThread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
|
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
#include <linux/in6.h>
|
#include <linux/in6.h>
|
||||||
|
#include <linux/slow-work.h>
|
||||||
#include "cifs_fs_sb.h"
|
#include "cifs_fs_sb.h"
|
||||||
#include "cifsacl.h"
|
#include "cifsacl.h"
|
||||||
/*
|
/*
|
||||||
@@ -346,14 +347,16 @@ struct cifsFileInfo {
|
|||||||
/* lock scope id (0 if none) */
|
/* lock scope id (0 if none) */
|
||||||
struct file *pfile; /* needed for writepage */
|
struct file *pfile; /* needed for writepage */
|
||||||
struct inode *pInode; /* needed for oplock break */
|
struct inode *pInode; /* needed for oplock break */
|
||||||
|
struct vfsmount *mnt;
|
||||||
struct mutex lock_mutex;
|
struct mutex lock_mutex;
|
||||||
struct list_head llist; /* list of byte range locks we have. */
|
struct list_head llist; /* list of byte range locks we have. */
|
||||||
bool closePend:1; /* file is marked to close */
|
bool closePend:1; /* file is marked to close */
|
||||||
bool invalidHandle:1; /* file closed via session abend */
|
bool invalidHandle:1; /* file closed via session abend */
|
||||||
bool messageMode:1; /* for pipes: message vs byte mode */
|
bool oplock_break_cancelled:1;
|
||||||
atomic_t count; /* reference count */
|
atomic_t count; /* reference count */
|
||||||
struct mutex fh_mutex; /* prevents reopen race after dead ses*/
|
struct mutex fh_mutex; /* prevents reopen race after dead ses*/
|
||||||
struct cifs_search_info srch_inf;
|
struct cifs_search_info srch_inf;
|
||||||
|
struct slow_work oplock_break; /* slow_work job for oplock breaks */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Take a reference on the file private data */
|
/* Take a reference on the file private data */
|
||||||
@@ -365,8 +368,10 @@ static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file)
|
|||||||
/* Release a reference on the file private data */
|
/* Release a reference on the file private data */
|
||||||
static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&cifs_file->count))
|
if (atomic_dec_and_test(&cifs_file->count)) {
|
||||||
|
iput(cifs_file->pInode);
|
||||||
kfree(cifs_file);
|
kfree(cifs_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -382,7 +387,6 @@ struct cifsInodeInfo {
|
|||||||
unsigned long time; /* jiffies of last update/check of inode */
|
unsigned long time; /* jiffies of last update/check of inode */
|
||||||
bool clientCanCacheRead:1; /* read oplock */
|
bool clientCanCacheRead:1; /* read oplock */
|
||||||
bool clientCanCacheAll:1; /* read and writebehind oplock */
|
bool clientCanCacheAll:1; /* read and writebehind oplock */
|
||||||
bool oplockPending:1;
|
|
||||||
bool delete_pending:1; /* DELETE_ON_CLOSE is set */
|
bool delete_pending:1; /* DELETE_ON_CLOSE is set */
|
||||||
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 */
|
||||||
@@ -585,9 +589,9 @@ require use of the stronger protocol */
|
|||||||
#define CIFSSEC_MUST_LANMAN 0x10010
|
#define CIFSSEC_MUST_LANMAN 0x10010
|
||||||
#define CIFSSEC_MUST_PLNTXT 0x20020
|
#define CIFSSEC_MUST_PLNTXT 0x20020
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
#define CIFSSEC_MASK 0xAF0AF /* allows weak security but also krb5 */
|
#define CIFSSEC_MASK 0xBF0BF /* allows weak security but also krb5 */
|
||||||
#else
|
#else
|
||||||
#define CIFSSEC_MASK 0xA70A7 /* current flags supported if weak */
|
#define CIFSSEC_MASK 0xB70B7 /* current flags supported if weak */
|
||||||
#endif /* UPCALL */
|
#endif /* UPCALL */
|
||||||
#else /* do not allow weak pw hash */
|
#else /* do not allow weak pw hash */
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
@@ -669,12 +673,6 @@ GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
|
|||||||
*/
|
*/
|
||||||
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;
|
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;
|
||||||
|
|
||||||
/* Global list of oplocks */
|
|
||||||
GLOBAL_EXTERN struct list_head cifs_oplock_list;
|
|
||||||
|
|
||||||
/* Protects the cifs_oplock_list */
|
|
||||||
GLOBAL_EXTERN spinlock_t cifs_oplock_lock;
|
|
||||||
|
|
||||||
/* Outstanding dir notify requests */
|
/* Outstanding dir notify requests */
|
||||||
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
|
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
|
||||||
/* DirNotify response queue */
|
/* DirNotify response queue */
|
||||||
@@ -725,3 +723,4 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
|
|||||||
GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
|
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;
|
||||||
|
@@ -86,18 +86,17 @@ extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
const int stage,
|
const int stage,
|
||||||
const struct nls_table *nls_cp);
|
const struct nls_table *nls_cp);
|
||||||
extern __u16 GetNextMid(struct TCP_Server_Info *server);
|
extern __u16 GetNextMid(struct TCP_Server_Info *server);
|
||||||
extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
|
|
||||||
struct cifsTconInfo *);
|
|
||||||
extern void DeleteOplockQEntry(struct oplock_q_entry *);
|
|
||||||
extern void DeleteTconOplockQEntries(struct cifsTconInfo *);
|
|
||||||
extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
|
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 struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode,
|
||||||
|
__u16 fileHandle, struct file *file,
|
||||||
|
struct vfsmount *mnt, unsigned int oflags);
|
||||||
extern int cifs_posix_open(char *full_path, struct inode **pinode,
|
extern int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||||
struct super_block *sb, int mode, int oflags,
|
struct vfsmount *mnt, int mode, int oflags,
|
||||||
int *poplock, __u16 *pnetfid, int xid);
|
__u32 *poplock, __u16 *pnetfid, int xid);
|
||||||
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
|
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
|
||||||
FILE_UNIX_BASIC_INFO *info,
|
FILE_UNIX_BASIC_INFO *info,
|
||||||
struct cifs_sb_info *cifs_sb);
|
struct cifs_sb_info *cifs_sb);
|
||||||
|
@@ -94,6 +94,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
|
|||||||
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
|
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
|
||||||
open_file = list_entry(tmp, struct cifsFileInfo, tlist);
|
open_file = list_entry(tmp, struct cifsFileInfo, tlist);
|
||||||
open_file->invalidHandle = true;
|
open_file->invalidHandle = true;
|
||||||
|
open_file->oplock_break_cancelled = true;
|
||||||
}
|
}
|
||||||
write_unlock(&GlobalSMBSeslock);
|
write_unlock(&GlobalSMBSeslock);
|
||||||
/* BB Add call to invalidate_inodes(sb) for all superblocks mounted
|
/* BB Add call to invalidate_inodes(sb) for all superblocks mounted
|
||||||
|
@@ -1670,7 +1670,6 @@ cifs_put_tcon(struct cifsTconInfo *tcon)
|
|||||||
CIFSSMBTDis(xid, tcon);
|
CIFSSMBTDis(xid, tcon);
|
||||||
_FreeXid(xid);
|
_FreeXid(xid);
|
||||||
|
|
||||||
DeleteTconOplockQEntries(tcon);
|
|
||||||
tconInfoFree(tcon);
|
tconInfoFree(tcon);
|
||||||
cifs_put_smb_ses(ses);
|
cifs_put_smb_ses(ses);
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include <linux/stat.h>
|
#include <linux/stat.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/namei.h>
|
#include <linux/namei.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
#include "cifsfs.h"
|
#include "cifsfs.h"
|
||||||
#include "cifspdu.h"
|
#include "cifspdu.h"
|
||||||
#include "cifsglob.h"
|
#include "cifsglob.h"
|
||||||
@@ -129,44 +130,45 @@ cifs_bp_rename_retry:
|
|||||||
return full_path;
|
return full_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
struct cifsFileInfo *
|
||||||
cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
|
cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
|
||||||
struct cifsTconInfo *tcon, bool write_only)
|
struct file *file, struct vfsmount *mnt, unsigned int oflags)
|
||||||
{
|
{
|
||||||
int oplock = 0;
|
int oplock = 0;
|
||||||
struct cifsFileInfo *pCifsFile;
|
struct cifsFileInfo *pCifsFile;
|
||||||
struct cifsInodeInfo *pCifsInode;
|
struct cifsInodeInfo *pCifsInode;
|
||||||
|
struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
|
||||||
|
|
||||||
pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||||
|
|
||||||
if (pCifsFile == NULL)
|
if (pCifsFile == NULL)
|
||||||
return;
|
return pCifsFile;
|
||||||
|
|
||||||
if (oplockEnabled)
|
if (oplockEnabled)
|
||||||
oplock = REQ_OPLOCK;
|
oplock = REQ_OPLOCK;
|
||||||
|
|
||||||
pCifsFile->netfid = fileHandle;
|
pCifsFile->netfid = fileHandle;
|
||||||
pCifsFile->pid = current->tgid;
|
pCifsFile->pid = current->tgid;
|
||||||
pCifsFile->pInode = newinode;
|
pCifsFile->pInode = igrab(newinode);
|
||||||
|
pCifsFile->mnt = mnt;
|
||||||
|
pCifsFile->pfile = file;
|
||||||
pCifsFile->invalidHandle = false;
|
pCifsFile->invalidHandle = false;
|
||||||
pCifsFile->closePend = false;
|
pCifsFile->closePend = false;
|
||||||
mutex_init(&pCifsFile->fh_mutex);
|
mutex_init(&pCifsFile->fh_mutex);
|
||||||
mutex_init(&pCifsFile->lock_mutex);
|
mutex_init(&pCifsFile->lock_mutex);
|
||||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||||
atomic_set(&pCifsFile->count, 1);
|
atomic_set(&pCifsFile->count, 1);
|
||||||
|
slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops);
|
||||||
|
|
||||||
/* set the following in open now
|
|
||||||
pCifsFile->pfile = file; */
|
|
||||||
write_lock(&GlobalSMBSeslock);
|
write_lock(&GlobalSMBSeslock);
|
||||||
list_add(&pCifsFile->tlist, &tcon->openFileList);
|
list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
|
||||||
pCifsInode = CIFS_I(newinode);
|
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 (write_only)
|
if (oflags & FMODE_READ)
|
||||||
|
list_add(&pCifsFile->flist, &pCifsInode->openFileList);
|
||||||
|
else
|
||||||
list_add_tail(&pCifsFile->flist,
|
list_add_tail(&pCifsFile->flist,
|
||||||
&pCifsInode->openFileList);
|
&pCifsInode->openFileList);
|
||||||
else
|
|
||||||
list_add(&pCifsFile->flist, &pCifsInode->openFileList);
|
|
||||||
|
|
||||||
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
|
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
|
||||||
pCifsInode->clientCanCacheAll = true;
|
pCifsInode->clientCanCacheAll = true;
|
||||||
@@ -176,18 +178,18 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
|
|||||||
pCifsInode->clientCanCacheRead = true;
|
pCifsInode->clientCanCacheRead = true;
|
||||||
}
|
}
|
||||||
write_unlock(&GlobalSMBSeslock);
|
write_unlock(&GlobalSMBSeslock);
|
||||||
|
|
||||||
|
return pCifsFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cifs_posix_open(char *full_path, struct inode **pinode,
|
int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||||
struct super_block *sb, int mode, int oflags,
|
struct vfsmount *mnt, int mode, int oflags,
|
||||||
int *poplock, __u16 *pnetfid, int xid)
|
__u32 *poplock, __u16 *pnetfid, int xid)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
__u32 oplock;
|
|
||||||
bool write_only = false;
|
|
||||||
FILE_UNIX_BASIC_INFO *presp_data;
|
FILE_UNIX_BASIC_INFO *presp_data;
|
||||||
__u32 posix_flags = 0;
|
__u32 posix_flags = 0;
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
|
||||||
struct cifs_fattr fattr;
|
struct cifs_fattr fattr;
|
||||||
|
|
||||||
cFYI(1, ("posix open %s", full_path));
|
cFYI(1, ("posix open %s", full_path));
|
||||||
@@ -223,12 +225,9 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
|
|||||||
if (oflags & O_DIRECT)
|
if (oflags & O_DIRECT)
|
||||||
posix_flags |= SMB_O_DIRECT;
|
posix_flags |= SMB_O_DIRECT;
|
||||||
|
|
||||||
if (!(oflags & FMODE_READ))
|
|
||||||
write_only = true;
|
|
||||||
|
|
||||||
mode &= ~current_umask();
|
mode &= ~current_umask();
|
||||||
rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
|
rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
|
||||||
pnetfid, presp_data, &oplock, full_path,
|
pnetfid, presp_data, poplock, full_path,
|
||||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
if (rc)
|
if (rc)
|
||||||
@@ -244,7 +243,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
|
|||||||
|
|
||||||
/* get new inode and set it up */
|
/* get new inode and set it up */
|
||||||
if (*pinode == NULL) {
|
if (*pinode == NULL) {
|
||||||
*pinode = cifs_iget(sb, &fattr);
|
*pinode = cifs_iget(mnt->mnt_sb, &fattr);
|
||||||
if (!*pinode) {
|
if (!*pinode) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto posix_open_ret;
|
goto posix_open_ret;
|
||||||
@@ -253,7 +252,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
|
|||||||
cifs_fattr_to_inode(*pinode, &fattr);
|
cifs_fattr_to_inode(*pinode, &fattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
|
cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);
|
||||||
|
|
||||||
posix_open_ret:
|
posix_open_ret:
|
||||||
kfree(presp_data);
|
kfree(presp_data);
|
||||||
@@ -280,7 +279,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||||||
int rc = -ENOENT;
|
int rc = -ENOENT;
|
||||||
int xid;
|
int xid;
|
||||||
int create_options = CREATE_NOT_DIR;
|
int create_options = CREATE_NOT_DIR;
|
||||||
int oplock = 0;
|
__u32 oplock = 0;
|
||||||
int oflags;
|
int oflags;
|
||||||
bool posix_create = false;
|
bool posix_create = false;
|
||||||
/*
|
/*
|
||||||
@@ -298,7 +297,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||||||
FILE_ALL_INFO *buf = NULL;
|
FILE_ALL_INFO *buf = NULL;
|
||||||
struct inode *newinode = NULL;
|
struct inode *newinode = NULL;
|
||||||
int disposition = FILE_OVERWRITE_IF;
|
int disposition = FILE_OVERWRITE_IF;
|
||||||
bool write_only = false;
|
|
||||||
|
|
||||||
xid = GetXid();
|
xid = GetXid();
|
||||||
|
|
||||||
@@ -323,7 +321,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||||||
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
|
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
|
||||||
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||||
rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
|
rc = cifs_posix_open(full_path, &newinode, nd->path.mnt,
|
||||||
mode, oflags, &oplock, &fileHandle, xid);
|
mode, oflags, &oplock, &fileHandle, xid);
|
||||||
/* EIO could indicate that (posix open) operation is not
|
/* EIO could indicate that (posix open) operation is not
|
||||||
supported, despite what server claimed in capability
|
supported, despite what server claimed in capability
|
||||||
@@ -351,11 +349,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||||||
desiredAccess = 0;
|
desiredAccess = 0;
|
||||||
if (oflags & FMODE_READ)
|
if (oflags & FMODE_READ)
|
||||||
desiredAccess |= GENERIC_READ; /* is this too little? */
|
desiredAccess |= GENERIC_READ; /* is this too little? */
|
||||||
if (oflags & FMODE_WRITE) {
|
if (oflags & FMODE_WRITE)
|
||||||
desiredAccess |= GENERIC_WRITE;
|
desiredAccess |= GENERIC_WRITE;
|
||||||
if (!(oflags & FMODE_READ))
|
|
||||||
write_only = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
|
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
|
||||||
disposition = FILE_CREATE;
|
disposition = FILE_CREATE;
|
||||||
@@ -470,8 +465,8 @@ cifs_create_set_dentry:
|
|||||||
/* mknod case - do not leave file open */
|
/* mknod case - do not leave file open */
|
||||||
CIFSSMBClose(xid, tcon, fileHandle);
|
CIFSSMBClose(xid, tcon, fileHandle);
|
||||||
} else if (!(posix_create) && (newinode)) {
|
} else if (!(posix_create) && (newinode)) {
|
||||||
cifs_fill_fileinfo(newinode, fileHandle,
|
cifs_new_fileinfo(newinode, fileHandle, NULL,
|
||||||
cifs_sb->tcon, write_only);
|
nd->path.mnt, oflags);
|
||||||
}
|
}
|
||||||
cifs_create_out:
|
cifs_create_out:
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
@@ -611,7 +606,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||||||
{
|
{
|
||||||
int xid;
|
int xid;
|
||||||
int rc = 0; /* to get around spurious gcc warning, set to zero here */
|
int rc = 0; /* to get around spurious gcc warning, set to zero here */
|
||||||
int oplock = 0;
|
__u32 oplock = 0;
|
||||||
__u16 fileHandle = 0;
|
__u16 fileHandle = 0;
|
||||||
bool posix_open = false;
|
bool posix_open = false;
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
@@ -683,8 +678,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||||||
if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
|
if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
|
||||||
(nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
|
(nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
|
||||||
(nd->intent.open.flags & O_CREAT)) {
|
(nd->intent.open.flags & O_CREAT)) {
|
||||||
rc = cifs_posix_open(full_path, &newInode,
|
rc = cifs_posix_open(full_path, &newInode, nd->path.mnt,
|
||||||
parent_dir_inode->i_sb,
|
|
||||||
nd->intent.open.create_mode,
|
nd->intent.open.create_mode,
|
||||||
nd->intent.open.flags, &oplock,
|
nd->intent.open.flags, &oplock,
|
||||||
&fileHandle, xid);
|
&fileHandle, xid);
|
||||||
|
137
fs/cifs/file.c
137
fs/cifs/file.c
@@ -30,6 +30,7 @@
|
|||||||
#include <linux/writeback.h>
|
#include <linux/writeback.h>
|
||||||
#include <linux/task_io_accounting_ops.h>
|
#include <linux/task_io_accounting_ops.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
#include <asm/div64.h>
|
#include <asm/div64.h>
|
||||||
#include "cifsfs.h"
|
#include "cifsfs.h"
|
||||||
#include "cifspdu.h"
|
#include "cifspdu.h"
|
||||||
@@ -39,27 +40,6 @@
|
|||||||
#include "cifs_debug.h"
|
#include "cifs_debug.h"
|
||||||
#include "cifs_fs_sb.h"
|
#include "cifs_fs_sb.h"
|
||||||
|
|
||||||
static inline struct cifsFileInfo *cifs_init_private(
|
|
||||||
struct cifsFileInfo *private_data, struct inode *inode,
|
|
||||||
struct file *file, __u16 netfid)
|
|
||||||
{
|
|
||||||
memset(private_data, 0, sizeof(struct cifsFileInfo));
|
|
||||||
private_data->netfid = netfid;
|
|
||||||
private_data->pid = current->tgid;
|
|
||||||
mutex_init(&private_data->fh_mutex);
|
|
||||||
mutex_init(&private_data->lock_mutex);
|
|
||||||
INIT_LIST_HEAD(&private_data->llist);
|
|
||||||
private_data->pfile = file; /* needed for writepage */
|
|
||||||
private_data->pInode = inode;
|
|
||||||
private_data->invalidHandle = false;
|
|
||||||
private_data->closePend = false;
|
|
||||||
/* Initialize reference count to one. The private data is
|
|
||||||
freed on the release of the last reference */
|
|
||||||
atomic_set(&private_data->count, 1);
|
|
||||||
|
|
||||||
return private_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int cifs_convert_flags(unsigned int flags)
|
static inline int cifs_convert_flags(unsigned int flags)
|
||||||
{
|
{
|
||||||
if ((flags & O_ACCMODE) == O_RDONLY)
|
if ((flags & O_ACCMODE) == O_RDONLY)
|
||||||
@@ -123,9 +103,11 @@ static inline int cifs_get_disposition(unsigned int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* all arguments to this function must be checked for validity in caller */
|
/* all arguments to this function must be checked for validity in caller */
|
||||||
static inline int cifs_posix_open_inode_helper(struct inode *inode,
|
static inline int
|
||||||
struct file *file, struct cifsInodeInfo *pCifsInode,
|
cifs_posix_open_inode_helper(struct inode *inode, struct file *file,
|
||||||
struct cifsFileInfo *pCifsFile, int oplock, u16 netfid)
|
struct cifsInodeInfo *pCifsInode,
|
||||||
|
struct cifsFileInfo *pCifsFile, __u32 oplock,
|
||||||
|
u16 netfid)
|
||||||
{
|
{
|
||||||
|
|
||||||
write_lock(&GlobalSMBSeslock);
|
write_lock(&GlobalSMBSeslock);
|
||||||
@@ -219,17 +201,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
|
|||||||
struct timespec temp;
|
struct timespec temp;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* want handles we can use to read with first
|
|
||||||
in the list so we do not have to walk the
|
|
||||||
list to search for one in write_begin */
|
|
||||||
if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
|
|
||||||
list_add_tail(&pCifsFile->flist,
|
|
||||||
&pCifsInode->openFileList);
|
|
||||||
} else {
|
|
||||||
list_add(&pCifsFile->flist,
|
|
||||||
&pCifsInode->openFileList);
|
|
||||||
}
|
|
||||||
write_unlock(&GlobalSMBSeslock);
|
|
||||||
if (pCifsInode->clientCanCacheRead) {
|
if (pCifsInode->clientCanCacheRead) {
|
||||||
/* we have the inode open somewhere else
|
/* we have the inode open somewhere else
|
||||||
no need to discard cache data */
|
no need to discard cache data */
|
||||||
@@ -279,7 +250,8 @@ client_can_cache:
|
|||||||
int cifs_open(struct inode *inode, struct file *file)
|
int cifs_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
int rc = -EACCES;
|
int rc = -EACCES;
|
||||||
int xid, oplock;
|
int xid;
|
||||||
|
__u32 oplock;
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct cifsTconInfo *tcon;
|
struct cifsTconInfo *tcon;
|
||||||
struct cifsFileInfo *pCifsFile;
|
struct cifsFileInfo *pCifsFile;
|
||||||
@@ -324,7 +296,7 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||||
int oflags = (int) cifs_posix_convert_flags(file->f_flags);
|
int oflags = (int) cifs_posix_convert_flags(file->f_flags);
|
||||||
/* can not refresh inode info since size could be stale */
|
/* can not refresh inode info since size could be stale */
|
||||||
rc = cifs_posix_open(full_path, &inode, inode->i_sb,
|
rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
|
||||||
cifs_sb->mnt_file_mode /* ignored */,
|
cifs_sb->mnt_file_mode /* ignored */,
|
||||||
oflags, &oplock, &netfid, xid);
|
oflags, &oplock, &netfid, xid);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
@@ -414,24 +386,17 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||||||
cFYI(1, ("cifs_open returned 0x%x", rc));
|
cFYI(1, ("cifs_open returned 0x%x", rc));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
file->private_data =
|
|
||||||
kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt,
|
||||||
|
file->f_flags);
|
||||||
|
file->private_data = pCifsFile;
|
||||||
if (file->private_data == NULL) {
|
if (file->private_data == NULL) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
|
|
||||||
write_lock(&GlobalSMBSeslock);
|
|
||||||
list_add(&pCifsFile->tlist, &tcon->openFileList);
|
|
||||||
|
|
||||||
pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
|
rc = cifs_open_inode_helper(inode, file, pCifsInode, pCifsFile, tcon,
|
||||||
if (pCifsInode) {
|
&oplock, buf, full_path, xid);
|
||||||
rc = cifs_open_inode_helper(inode, file, pCifsInode,
|
|
||||||
pCifsFile, tcon,
|
|
||||||
&oplock, buf, full_path, xid);
|
|
||||||
} else {
|
|
||||||
write_unlock(&GlobalSMBSeslock);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
@@ -474,7 +439,8 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile)
|
|||||||
static int cifs_reopen_file(struct file *file, bool can_flush)
|
static int cifs_reopen_file(struct file *file, bool can_flush)
|
||||||
{
|
{
|
||||||
int rc = -EACCES;
|
int rc = -EACCES;
|
||||||
int xid, oplock;
|
int xid;
|
||||||
|
__u32 oplock;
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct cifsTconInfo *tcon;
|
struct cifsTconInfo *tcon;
|
||||||
struct cifsFileInfo *pCifsFile;
|
struct cifsFileInfo *pCifsFile;
|
||||||
@@ -543,7 +509,7 @@ reopen_error_exit:
|
|||||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||||
int oflags = (int) cifs_posix_convert_flags(file->f_flags);
|
int oflags = (int) cifs_posix_convert_flags(file->f_flags);
|
||||||
/* can not refresh inode info since size could be stale */
|
/* can not refresh inode info since size could be stale */
|
||||||
rc = cifs_posix_open(full_path, NULL, inode->i_sb,
|
rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
|
||||||
cifs_sb->mnt_file_mode /* ignored */,
|
cifs_sb->mnt_file_mode /* ignored */,
|
||||||
oflags, &oplock, &netfid, xid);
|
oflags, &oplock, &netfid, xid);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
@@ -2308,6 +2274,73 @@ out:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cifs_oplock_break(struct slow_work *work)
|
||||||
|
{
|
||||||
|
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
|
||||||
|
oplock_break);
|
||||||
|
struct inode *inode = cfile->pInode;
|
||||||
|
struct cifsInodeInfo *cinode = CIFS_I(inode);
|
||||||
|
struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
|
||||||
|
int rc, waitrc = 0;
|
||||||
|
|
||||||
|
if (inode && S_ISREG(inode->i_mode)) {
|
||||||
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
|
if (cinode->clientCanCacheAll == 0)
|
||||||
|
break_lease(inode, FMODE_READ);
|
||||||
|
else if (cinode->clientCanCacheRead == 0)
|
||||||
|
break_lease(inode, FMODE_WRITE);
|
||||||
|
#endif
|
||||||
|
rc = filemap_fdatawrite(inode->i_mapping);
|
||||||
|
if (cinode->clientCanCacheRead == 0) {
|
||||||
|
waitrc = filemap_fdatawait(inode->i_mapping);
|
||||||
|
invalidate_remote_inode(inode);
|
||||||
|
}
|
||||||
|
if (!rc)
|
||||||
|
rc = waitrc;
|
||||||
|
if (rc)
|
||||||
|
cinode->write_behind_rc = rc;
|
||||||
|
cFYI(1, ("Oplock flush inode %p rc %d", inode, rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* releasing stale oplock after recent reconnect of smb session using
|
||||||
|
* a now incorrect file handle is not a data integrity issue but do
|
||||||
|
* not bother sending an oplock release if session to server still is
|
||||||
|
* disconnected since oplock already released by the server
|
||||||
|
*/
|
||||||
|
if (!cfile->closePend && !cfile->oplock_break_cancelled) {
|
||||||
|
rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
|
||||||
|
LOCKING_ANDX_OPLOCK_RELEASE, false);
|
||||||
|
cFYI(1, ("Oplock release rc = %d", rc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cifs_oplock_break_get(struct slow_work *work)
|
||||||
|
{
|
||||||
|
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
|
||||||
|
oplock_break);
|
||||||
|
mntget(cfile->mnt);
|
||||||
|
cifsFileInfo_get(cfile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cifs_oplock_break_put(struct slow_work *work)
|
||||||
|
{
|
||||||
|
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
|
||||||
|
oplock_break);
|
||||||
|
mntput(cfile->mnt);
|
||||||
|
cifsFileInfo_put(cfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct slow_work_ops cifs_oplock_break_ops = {
|
||||||
|
.get_ref = cifs_oplock_break_get,
|
||||||
|
.put_ref = cifs_oplock_break_put,
|
||||||
|
.execute = cifs_oplock_break,
|
||||||
|
};
|
||||||
|
|
||||||
const struct address_space_operations cifs_addr_ops = {
|
const struct address_space_operations cifs_addr_ops = {
|
||||||
.readpage = cifs_readpage,
|
.readpage = cifs_readpage,
|
||||||
.readpages = cifs_readpages,
|
.readpages = cifs_readpages,
|
||||||
|
@@ -32,7 +32,6 @@
|
|||||||
|
|
||||||
extern mempool_t *cifs_sm_req_poolp;
|
extern mempool_t *cifs_sm_req_poolp;
|
||||||
extern mempool_t *cifs_req_poolp;
|
extern mempool_t *cifs_req_poolp;
|
||||||
extern struct task_struct *oplockThread;
|
|
||||||
|
|
||||||
/* The xid serves as a useful identifier for each incoming vfs request,
|
/* The xid serves as a useful identifier for each incoming vfs request,
|
||||||
in a similar way to the mid which is useful to track each sent smb,
|
in a similar way to the mid which is useful to track each sent smb,
|
||||||
@@ -500,6 +499,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
|
|||||||
struct cifsTconInfo *tcon;
|
struct cifsTconInfo *tcon;
|
||||||
struct cifsInodeInfo *pCifsInode;
|
struct cifsInodeInfo *pCifsInode;
|
||||||
struct cifsFileInfo *netfile;
|
struct cifsFileInfo *netfile;
|
||||||
|
int rc;
|
||||||
|
|
||||||
cFYI(1, ("Checking for oplock break or dnotify response"));
|
cFYI(1, ("Checking for oplock break or dnotify response"));
|
||||||
if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
|
if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
|
||||||
@@ -562,30 +562,40 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
cifs_stats_inc(&tcon->num_oplock_brks);
|
cifs_stats_inc(&tcon->num_oplock_brks);
|
||||||
write_lock(&GlobalSMBSeslock);
|
read_lock(&GlobalSMBSeslock);
|
||||||
list_for_each(tmp2, &tcon->openFileList) {
|
list_for_each(tmp2, &tcon->openFileList) {
|
||||||
netfile = list_entry(tmp2, struct cifsFileInfo,
|
netfile = list_entry(tmp2, struct cifsFileInfo,
|
||||||
tlist);
|
tlist);
|
||||||
if (pSMB->Fid != netfile->netfid)
|
if (pSMB->Fid != netfile->netfid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
write_unlock(&GlobalSMBSeslock);
|
/*
|
||||||
read_unlock(&cifs_tcp_ses_lock);
|
* don't do anything if file is about to be
|
||||||
|
* closed anyway.
|
||||||
|
*/
|
||||||
|
if (netfile->closePend) {
|
||||||
|
read_unlock(&GlobalSMBSeslock);
|
||||||
|
read_unlock(&cifs_tcp_ses_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
cFYI(1, ("file id match, oplock break"));
|
cFYI(1, ("file id match, oplock break"));
|
||||||
pCifsInode = CIFS_I(netfile->pInode);
|
pCifsInode = CIFS_I(netfile->pInode);
|
||||||
pCifsInode->clientCanCacheAll = false;
|
pCifsInode->clientCanCacheAll = false;
|
||||||
if (pSMB->OplockLevel == 0)
|
if (pSMB->OplockLevel == 0)
|
||||||
pCifsInode->clientCanCacheRead = false;
|
pCifsInode->clientCanCacheRead = false;
|
||||||
pCifsInode->oplockPending = true;
|
rc = slow_work_enqueue(&netfile->oplock_break);
|
||||||
AllocOplockQEntry(netfile->pInode,
|
if (rc) {
|
||||||
netfile->netfid, tcon);
|
cERROR(1, ("failed to enqueue oplock "
|
||||||
cFYI(1, ("about to wake up oplock thread"));
|
"break: %d\n", rc));
|
||||||
if (oplockThread)
|
} else {
|
||||||
wake_up_process(oplockThread);
|
netfile->oplock_break_cancelled = false;
|
||||||
|
}
|
||||||
|
read_unlock(&GlobalSMBSeslock);
|
||||||
|
read_unlock(&cifs_tcp_ses_lock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
write_unlock(&GlobalSMBSeslock);
|
read_unlock(&GlobalSMBSeslock);
|
||||||
read_unlock(&cifs_tcp_ses_lock);
|
read_unlock(&cifs_tcp_ses_lock);
|
||||||
cFYI(1, ("No matching file for oplock break"));
|
cFYI(1, ("No matching file for oplock break"));
|
||||||
return true;
|
return true;
|
||||||
|
@@ -146,7 +146,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
|
cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
|
||||||
struct cifs_sb_info *cifs_sb)
|
struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
@@ -161,7 +161,7 @@ cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
|
|||||||
cifs_fill_common_info(fattr, cifs_sb);
|
cifs_fill_common_info(fattr, cifs_sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
|
cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
|
||||||
struct cifs_sb_info *cifs_sb)
|
struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
|
@@ -103,56 +103,6 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
|||||||
mempool_free(midEntry, cifs_mid_poolp);
|
mempool_free(midEntry, cifs_mid_poolp);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct oplock_q_entry *
|
|
||||||
AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
|
|
||||||
{
|
|
||||||
struct oplock_q_entry *temp;
|
|
||||||
if ((pinode == NULL) || (tcon == NULL)) {
|
|
||||||
cERROR(1, ("Null parms passed to AllocOplockQEntry"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (temp == NULL)
|
|
||||||
return temp;
|
|
||||||
else {
|
|
||||||
temp->pinode = pinode;
|
|
||||||
temp->tcon = tcon;
|
|
||||||
temp->netfid = fid;
|
|
||||||
spin_lock(&cifs_oplock_lock);
|
|
||||||
list_add_tail(&temp->qhead, &cifs_oplock_list);
|
|
||||||
spin_unlock(&cifs_oplock_lock);
|
|
||||||
}
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
|
|
||||||
{
|
|
||||||
spin_lock(&cifs_oplock_lock);
|
|
||||||
/* should we check if list empty first? */
|
|
||||||
list_del(&oplockEntry->qhead);
|
|
||||||
spin_unlock(&cifs_oplock_lock);
|
|
||||||
kmem_cache_free(cifs_oplock_cachep, oplockEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
|
|
||||||
{
|
|
||||||
struct oplock_q_entry *temp;
|
|
||||||
|
|
||||||
if (tcon == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
spin_lock(&cifs_oplock_lock);
|
|
||||||
list_for_each_entry(temp, &cifs_oplock_list, qhead) {
|
|
||||||
if ((temp->tcon) && (temp->tcon == tcon)) {
|
|
||||||
list_del(&temp->qhead);
|
|
||||||
kmem_cache_free(cifs_oplock_cachep, temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock(&cifs_oplock_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
|
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user