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

Commit a6ce4932 authored by Steve French's avatar Steve French
Browse files

[CIFS] Add support for posix open during lookup



This patch by utilizing lookup intents, and thus removing a network
roundtrip in the open path, improves performance dramatically on
open (30% or more) to Samba and other servers which support the
cifs posix extensions

Signed-off-by: default avatarShirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent d9fb5c09
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -350,7 +350,7 @@ struct cifsFileInfo {
	bool invalidHandle:1;	/* file closed via session abend */
	bool messageMode:1;	/* for pipes: message vs byte mode */
	atomic_t wrtPending;   /* handle in use - defer close */
	struct semaphore fh_sem; /* prevents reopen race after dead ses*/
	struct mutex fh_mutex; /* prevents reopen race after dead ses*/
	struct cifs_search_info srch_inf;
};

+85 −46
Original line number Diff line number Diff line
@@ -129,12 +129,64 @@ build_path_from_dentry(struct dentry *direntry)
	return full_path;
}

static void
cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
			struct cifsTconInfo *tcon, bool write_only)
{
	int oplock = 0;
	struct cifsFileInfo *pCifsFile;
	struct cifsInodeInfo *pCifsInode;

	pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);

	if (pCifsFile == NULL)
		return;

	if (oplockEnabled)
		oplock = REQ_OPLOCK;

	pCifsFile->netfid = fileHandle;
	pCifsFile->pid = current->tgid;
	pCifsFile->pInode = newinode;
	pCifsFile->invalidHandle = false;
	pCifsFile->closePend     = false;
	mutex_init(&pCifsFile->fh_mutex);
	mutex_init(&pCifsFile->lock_mutex);
	INIT_LIST_HEAD(&pCifsFile->llist);
	atomic_set(&pCifsFile->wrtPending, 0);

	/* set the following in open now
			pCifsFile->pfile = file; */
	write_lock(&GlobalSMBSeslock);
	list_add(&pCifsFile->tlist, &tcon->openFileList);
	pCifsInode = CIFS_I(newinode);
	if (pCifsInode) {
		/* if readable file instance put first in list*/
		if (write_only) {
			list_add_tail(&pCifsFile->flist,
				      &pCifsInode->openFileList);
		} else {
			list_add(&pCifsFile->flist,
				 &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);
}

int cifs_posix_open(char *full_path, struct inode **pinode,
		    struct super_block *sb, int mode, int oflags,
		    int *poplock, __u16 *pnetfid, int xid)
{
	int rc;
	__u32 oplock;
	bool write_only = false;
	FILE_UNIX_BASIC_INFO *presp_data;
	__u32 posix_flags = 0;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -172,6 +224,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
	if (oflags & O_DIRECT)
		posix_flags |= SMB_O_DIRECT;

	if (!(oflags & FMODE_READ))
		write_only = true;

	rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
			pnetfid, presp_data, &oplock, full_path,
@@ -200,6 +254,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,

	posix_fill_in_inode(*pinode, presp_data, 1);

	cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);

posix_open_ret:
	kfree(presp_data);
	return rc;
@@ -241,7 +297,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
	char *full_path = NULL;
	FILE_ALL_INFO *buf = NULL;
	struct inode *newinode = NULL;
	struct cifsInodeInfo *pCifsInode;
	int disposition = FILE_OVERWRITE_IF;
	bool write_only = false;

@@ -412,44 +467,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
		/* mknod case - do not leave file open */
		CIFSSMBClose(xid, tcon, fileHandle);
	} else if (newinode) {
		struct cifsFileInfo *pCifsFile =
			kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);

		if (pCifsFile == NULL)
			goto cifs_create_out;
		pCifsFile->netfid = fileHandle;
		pCifsFile->pid = current->tgid;
		pCifsFile->pInode = newinode;
		pCifsFile->invalidHandle = false;
		pCifsFile->closePend     = false;
		init_MUTEX(&pCifsFile->fh_sem);
		mutex_init(&pCifsFile->lock_mutex);
		INIT_LIST_HEAD(&pCifsFile->llist);
		atomic_set(&pCifsFile->wrtPending, 0);

		/* set the following in open now
				pCifsFile->pfile = file; */
		write_lock(&GlobalSMBSeslock);
		list_add(&pCifsFile->tlist, &tcon->openFileList);
		pCifsInode = CIFS_I(newinode);
		if (pCifsInode) {
			/* if readable file instance put first in list*/
			if (write_only) {
				list_add_tail(&pCifsFile->flist,
					      &pCifsInode->openFileList);
			} else {
				list_add(&pCifsFile->flist,
					 &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);
			cifs_fill_fileinfo(newinode, fileHandle,
					cifs_sb->tcon, write_only);
	}
cifs_create_out:
	kfree(buf);
@@ -582,17 +601,21 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
	return rc;
}


struct dentry *
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
	    struct nameidata *nd)
{
	int xid;
	int rc = 0; /* to get around spurious gcc warning, set to zero here */
	int oplock = 0;
	int mode;
	__u16 fileHandle = 0;
	bool posix_open = false;
	struct cifs_sb_info *cifs_sb;
	struct cifsTconInfo *pTcon;
	struct inode *newInode = NULL;
	char *full_path = NULL;
	struct file *filp;

	xid = GetXid();

@@ -634,10 +657,25 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
	}
	cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));

	if (pTcon->unix_ext)
	if (pTcon->unix_ext) {
		if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
				(nd->flags & LOOKUP_OPEN)) {
			if (!((nd->intent.open.flags & O_CREAT) &&
					(nd->intent.open.flags & O_EXCL))) {
				mode = nd->intent.open.create_mode &
						~current->fs->umask;
				rc = cifs_posix_open(full_path, &newInode,
					parent_dir_inode->i_sb, mode,
					nd->intent.open.flags, &oplock,
					&fileHandle, xid);
				if ((rc != -EINVAL) && (rc != -EOPNOTSUPP))
					posix_open = true;
			}
		}
		if (!posix_open)
			rc = cifs_get_inode_info_unix(&newInode, full_path,
						parent_dir_inode->i_sb, xid);
	else
	} else
		rc = cifs_get_inode_info(&newInode, full_path, NULL,
				parent_dir_inode->i_sb, xid, NULL);

@@ -647,7 +685,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
		else
			direntry->d_op = &cifs_dentry_ops;
		d_add(direntry, newInode);

		if (posix_open)
			filp = lookup_instantiate_filp(nd, direntry, NULL);
		/* since paths are not looked up by component - the parent
		   directories are presumed to be good here */
		renew_parental_timestamps(direntry);
+32 −33
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ static inline struct cifsFileInfo *cifs_init_private(
	memset(private_data, 0, sizeof(struct cifsFileInfo));
	private_data->netfid = netfid;
	private_data->pid = current->tgid;
	init_MUTEX(&private_data->fh_sem);
	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 */
@@ -284,7 +284,6 @@ int cifs_open(struct inode *inode, struct file *file)
	cifs_sb = CIFS_SB(inode->i_sb);
	tcon = cifs_sb->tcon;

	if (file->f_flags & O_CREAT) {
	/* search inode for this file and fill in file->private_data */
	pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
	read_lock(&GlobalSMBSeslock);
@@ -303,16 +302,16 @@ int cifs_open(struct inode *inode, struct file *file)
		}
	}
	read_unlock(&GlobalSMBSeslock);

	if (file->private_data != NULL) {
		rc = 0;
		FreeXid(xid);
		return rc;
	} else {
			if (file->f_flags & O_EXCL)
		if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
			cERROR(1, ("could not find file instance for "
				   "new file %p", file));
	}
	}

	full_path = build_path_from_dentry(file->f_path.dentry);
	if (full_path == NULL) {
@@ -500,9 +499,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
		return -EBADF;

	xid = GetXid();
	down(&pCifsFile->fh_sem);
	mutex_unlock(&pCifsFile->fh_mutex);
	if (!pCifsFile->invalidHandle) {
		up(&pCifsFile->fh_sem);
		mutex_lock(&pCifsFile->fh_mutex);
		FreeXid(xid);
		return 0;
	}
@@ -533,7 +532,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
	if (full_path == NULL) {
		rc = -ENOMEM;
reopen_error_exit:
		up(&pCifsFile->fh_sem);
		mutex_lock(&pCifsFile->fh_mutex);
		FreeXid(xid);
		return rc;
	}
@@ -575,14 +574,14 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
				CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc) {
		up(&pCifsFile->fh_sem);
		mutex_lock(&pCifsFile->fh_mutex);
		cFYI(1, ("cifs_open returned 0x%x", rc));
		cFYI(1, ("oplock: %d", oplock));
	} else {
reopen_success:
		pCifsFile->netfid = netfid;
		pCifsFile->invalidHandle = false;
		up(&pCifsFile->fh_sem);
		mutex_lock(&pCifsFile->fh_mutex);
		pCifsInode = CIFS_I(inode);
		if (pCifsInode) {
			if (can_flush) {