Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07e2e6ba authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 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
parents d8f654ef 3321b791
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ config CIFS
	tristate "CIFS support (advanced network filesystem, SMBFS successor)"
	depends on INET
	select NLS
	select SLOW_WORK
	help
	  This is the client VFS module for the Common Internet File System
	  (CIFS) protocol which is the successor to the Server Message Block
+4 −89
Original line number Diff line number Diff line
@@ -64,9 +64,6 @@ unsigned int multiuser_mount = 0;
unsigned int extended_security = CIFSSEC_DEF;
/* unsigned int ntlmv2_support = 0; */
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;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0);
@@ -972,89 +969,12 @@ cifs_destroy_mids(void)
	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
init_cifs(void)
{
	int rc = 0;
	cifs_proc_init();
	INIT_LIST_HEAD(&cifs_tcp_ses_list);
	INIT_LIST_HEAD(&cifs_oplock_list);
#ifdef CONFIG_CIFS_EXPERIMENTAL
	INIT_LIST_HEAD(&GlobalDnotifyReqList);
	INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
@@ -1083,7 +1003,6 @@ init_cifs(void)
	rwlock_init(&GlobalSMBSeslock);
	rwlock_init(&cifs_tcp_ses_lock);
	spin_lock_init(&GlobalMid_Lock);
	spin_lock_init(&cifs_oplock_lock);

	if (cifs_max_pending < 2) {
		cifs_max_pending = 2;
@@ -1118,16 +1037,13 @@ init_cifs(void)
	if (rc)
		goto out_unregister_key_type;
#endif
	oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
	if (IS_ERR(oplockThread)) {
		rc = PTR_ERR(oplockThread);
		cERROR(1, ("error %d create oplock thread", rc));
		goto out_unregister_dfs_key_type;
	}
	rc = slow_work_register_user();
	if (rc)
		goto out_unregister_resolver_key;

	return 0;

 out_unregister_dfs_key_type:
 out_unregister_resolver_key:
#ifdef CONFIG_CIFS_DFS_UPCALL
	unregister_key_type(&key_type_dns_resolver);
 out_unregister_key_type:
@@ -1164,7 +1080,6 @@ exit_cifs(void)
	cifs_destroy_inodecache();
	cifs_destroy_mids();
	cifs_destroy_request_bufs();
	kthread_stop(oplockThread);
}

MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
+10 −11
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
 */
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/slow-work.h>
#include "cifs_fs_sb.h"
#include "cifsacl.h"
/*
@@ -346,14 +347,16 @@ struct cifsFileInfo {
	/* lock scope id (0 if none) */
	struct file *pfile; /* needed for writepage */
	struct inode *pInode; /* needed for oplock break */
	struct vfsmount *mnt;
	struct mutex lock_mutex;
	struct list_head llist; /* list of byte range locks we have. */
	bool closePend:1;	/* file is marked to close */
	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 */
	struct mutex fh_mutex; /* prevents reopen race after dead ses*/
	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 */
@@ -365,9 +368,11 @@ static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file)
/* Release a reference on the file private data */
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);
	}
}

/*
 * One of these for each file inode
@@ -382,7 +387,6 @@ struct cifsInodeInfo {
	unsigned long time;	/* jiffies of last update/check of inode */
	bool clientCanCacheRead:1;	/* read oplock */
	bool clientCanCacheAll:1;	/* read and writebehind oplock */
	bool oplockPending:1;
	bool delete_pending:1;		/* DELETE_ON_CLOSE is set */
	u64  server_eof;		/* current file size on server */
	u64  uniqueid;			/* server inode number */
@@ -585,9 +589,9 @@ require use of the stronger protocol */
#define   CIFSSEC_MUST_LANMAN	0x10010
#define   CIFSSEC_MUST_PLNTXT	0x20020
#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
#define   CIFSSEC_MASK          0xA70A7 /* current flags supported if weak */
#define   CIFSSEC_MASK          0xB70B7 /* current flags supported if weak */
#endif /* UPCALL */
#else /* do not allow weak pw hash */
#ifdef CONFIG_CIFS_UPCALL
@@ -669,12 +673,6 @@ GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
 */
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 */
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
/* 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_max_pending; /* MAX requests at once to server*/

extern const struct slow_work_ops cifs_oplock_break_ops;
+5 −6
Original line number Diff line number Diff line
@@ -86,18 +86,17 @@ extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
			     const int stage,
			     const struct nls_table *nls_cp);
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 u64 cifs_UnixTimeToNT(struct timespec);
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
				      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,
			   struct super_block *sb, int mode, int oflags,
			   int *poplock, __u16 *pnetfid, int xid);
			   struct vfsmount *mnt, int mode, int oflags,
			   __u32 *poplock, __u16 *pnetfid, int xid);
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
				     FILE_UNIX_BASIC_INFO *info,
				     struct cifs_sb_info *cifs_sb);
+1 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
	list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
		open_file = list_entry(tmp, struct cifsFileInfo, tlist);
		open_file->invalidHandle = true;
		open_file->oplock_break_cancelled = true;
	}
	write_unlock(&GlobalSMBSeslock);
	/* BB Add call to invalidate_inodes(sb) for all superblocks mounted
Loading