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

Commit 7ee1af76 authored by Jeremy Allison's avatar Jeremy Allison Committed by Steve French
Browse files

[CIFS]



Allow Windows blocking locks to be cancelled via a
CANCEL_LOCK call. TODO - restrict this to servers
that support NT_STATUS codes (Win9x will probably
not support this call).

Signed-off-by: default avatarJeremy Allison <jra@samba.org>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
(cherry picked from 570d4d2d895569825d0d017d4e76b51138f68864 commit)
parent 6c3d8909
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 *
 *   Copyright (C) International Business Machines  Corp., 2002,2006
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *              Jeremy Allison (jra@samba.org)
 *
 *   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
@@ -267,14 +268,14 @@ struct cifsTconInfo {
};

/*
 * This info hangs off the cifsFileInfo structure.  This is used to track
 * byte stream locks on the file
 * This info hangs off the cifsFileInfo structure, pointed to by llist.
 * This is used to track byte stream locks on the file
 */
struct cifsLockInfo {
	struct cifsLockInfo *next;
	int start;
	int length;
	int type;
	struct list_head llist;	/* pointer to next cifsLockInfo */
	__u64 offset;
	__u64 length;
	__u8 type;
};

/*
@@ -305,6 +306,8 @@ struct cifsFileInfo {
	/* lock scope id (0 if none) */
	struct file * pfile; /* needed for writepage */
	struct inode * pInode; /* needed for oplock break */
	struct semaphore lock_sem;
	struct list_head llist; /* list of byte range locks we have. */
	unsigned closePend:1;	/* file is marked to close */
	unsigned invalidHandle:1;  /* file closed via session abend */
	atomic_t wrtPending;   /* handle in use - defer close */
+4 −0
Original line number Diff line number Diff line
@@ -50,6 +50,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
			struct kvec *, int /* nvec to send */, 
			int * /* type of buf returned */ , const int long_op);
extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *,
				struct smb_hdr * /* input */ ,
				struct smb_hdr * /* out */ ,
				int * /* bytes returned */);
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
+13 −2
Original line number Diff line number Diff line
@@ -1460,8 +1460,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
	pSMB->hdr.smb_buf_length += count;
	pSMB->ByteCount = cpu_to_le16(count);

	if (waitFlag) {
		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
			(struct smb_hdr *) pSMBr, &bytes_returned);
	} else {
		rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
	}
	cifs_stats_inc(&tcon->num_locks);
	if (rc) {
		cFYI(1, ("Send error in Lock = %d", rc));
@@ -1546,8 +1551,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
	pSMB->Reserved4 = 0;
	pSMB->hdr.smb_buf_length += byte_count;
	pSMB->ByteCount = cpu_to_le16(byte_count);
	if (waitFlag) {
		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
			(struct smb_hdr *) pSMBr, &bytes_returned);
	} else {
		rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
	}

	if (rc) {
		cFYI(1, ("Send error in Posix Lock = %d", rc));
	} else if (get_flag) {
+80 −15
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 * 
 *   Copyright (C) International Business Machines  Corp., 2002,2003
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *              Jeremy Allison (jra@samba.org)
 *
 *   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
@@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private(
	private_data->netfid = netfid;
	private_data->pid = current->tgid;	
	init_MUTEX(&private_data->fh_sem);
	init_MUTEX(&private_data->lock_sem);
	INIT_LIST_HEAD(&private_data->llist);
	private_data->pfile = file; /* needed for writepage */
	private_data->pInode = inode;
	private_data->invalidHandle = FALSE;
@@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file)
	cifs_sb = CIFS_SB(inode->i_sb);
	pTcon = cifs_sb->tcon;
	if (pSMBFile) {
		struct cifsLockInfo *li, *tmp;

		pSMBFile->closePend = TRUE;
		if (pTcon) {
			/* no sense reconnecting to close a file that is
@@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file)
						  pSMBFile->netfid);
			}
		}

		/* Delete any outstanding lock records.
		   We'll lose them when the file is closed anyway. */
		down(&pSMBFile->lock_sem);
		list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
			list_del(&li->llist);
			kfree(li);
		}
		up(&pSMBFile->lock_sem);

		write_lock(&GlobalSMBSeslock);
		list_del(&pSMBFile->flist);
		list_del(&pSMBFile->tlist);
@@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file)
	return rc;
}

static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
				__u64 offset, __u8 lockType)
{
	struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
	if (li == NULL)
		return -ENOMEM;
	li->offset = offset;
	li->length = len;
	li->type = lockType;
	down(&fid->lock_sem);
	list_add(&li->llist, &fid->llist);
	up(&fid->lock_sem);
	return 0;
}

int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
{
	int rc, xid;
@@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
	struct cifsTconInfo *pTcon;
	__u16 netfid;
	__u8 lockType = LOCKING_ANDX_LARGE_FILES;
	int posix_locking;

	length = 1 + pfLock->fl_end - pfLock->fl_start;
	rc = -EACCES;
@@ -639,14 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
	}
	netfid = ((struct cifsFileInfo *)file->private_data)->netfid;

	posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
			(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));

	/* BB add code here to normalize offset and length to
	account for negative length which we can not accept over the
	wire */
	if (IS_GETLK(cmd)) {
		if((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
		   (CIFS_UNIX_FCNTL_CAP & 
			le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
		if(posix_locking) {
			int posix_lock_type;
			if(lockType & LOCKING_ANDX_SHARED_LOCK)
				posix_lock_type = CIFS_RDLCK;
@@ -682,9 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
		FreeXid(xid);
		return rc;
	}
	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
		(CIFS_UNIX_FCNTL_CAP &
			 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {

	if (!numLock && !numUnlock) {
		/* if no lock or unlock then nothing
		to do since we do not know what it is */
		FreeXid(xid);
		return -EOPNOTSUPP;
	}

	if (posix_locking) {
		int posix_lock_type;
		if(lockType & LOCKING_ANDX_SHARED_LOCK)
			posix_lock_type = CIFS_RDLCK;
@@ -693,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
		
		if(numUnlock == 1)
			posix_lock_type = CIFS_UNLCK;
		else if(numLock == 0) {
			/* if no lock or unlock then nothing
			to do since we do not know what it is */
			FreeXid(xid);
			return -EOPNOTSUPP;
		}

		rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
				      length, pfLock,
				      posix_lock_type, wait_flag);
	} else
	} else {
		struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data;

		if (numLock) {
			rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
				numUnlock, numLock, lockType, wait_flag);
					0, numLock, lockType, wait_flag);

			if (rc == 0) {
				/* For Windows locks we must store them. */
				rc = store_file_lock(fid, length,
						pfLock->fl_start, lockType);
			}
		} else if (numUnlock) {
			/* For each stored lock that this unlock overlaps
			   completely, unlock it. */
			int stored_rc = 0;
			struct cifsLockInfo *li, *tmp;

			down(&fid->lock_sem);
			list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
				if (pfLock->fl_start <= li->offset &&
						length >= li->length) {
					stored_rc = CIFSSMBLock(xid, pTcon, netfid,
							li->length, li->offset,
							1, 0, li->type, FALSE);
					if (stored_rc)
						rc = stored_rc;

					list_del(&li->llist);
					kfree(li);
				}
			}
		up(&fid->lock_sem);
		}
	}

	if (pfLock->fl_flags & FL_POSIX)
		posix_lock_file_wait(file, pfLock);
	FreeXid(xid);
+1 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
	{ERRinvlevel,-EOPNOTSUPP},
	{ERRdirnotempty, -ENOTEMPTY},
	{ERRnotlocked, -ENOLCK},
	{ERRcancelviolation, -ENOLCK},
	{ERRalreadyexists, -EEXIST},
	{ERRmoredata, -EOVERFLOW},
	{ERReasnotsupported,-EOPNOTSUPP},
Loading