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

[CIFS] Allow null nd (as nfs server uses) on create



While creating a file on a server which supports unix extensions
such as Samba, if a file is being created which does not supply
nameidata (i.e. nd is null), cifs client can oops when calling
cifs_posix_open.

Signed-off-by: default avatarShirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 2c964d1f
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -107,7 +107,9 @@ 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 vfsmount *mnt, int mode, int oflags,
				struct vfsmount *mnt,
				struct super_block *sb,
				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,
+12 −8
Original line number Diff line number Diff line
@@ -182,13 +182,14 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
}

int cifs_posix_open(char *full_path, struct inode **pinode,
		    struct vfsmount *mnt, int mode, int oflags,
			struct vfsmount *mnt, struct super_block *sb,
			int mode, int oflags,
			__u32 *poplock, __u16 *pnetfid, int xid)
{
	int rc;
	FILE_UNIX_BASIC_INFO *presp_data;
	__u32 posix_flags = 0;
	struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	struct cifs_fattr fattr;

	cFYI(1, "posix open %s", full_path);
@@ -241,7 +242,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,

	/* get new inode and set it up */
	if (*pinode == NULL) {
		*pinode = cifs_iget(mnt->mnt_sb, &fattr);
		*pinode = cifs_iget(sb, &fattr);
		if (!*pinode) {
			rc = -ENOMEM;
			goto posix_open_ret;
@@ -250,6 +251,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
		cifs_fattr_to_inode(*pinode, &fattr);
	}

	if (mnt)
		cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);

posix_open_ret:
@@ -314,13 +316,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
	if (nd && (nd->flags & LOOKUP_OPEN))
		oflags = nd->intent.open.flags;
	else
		oflags = FMODE_READ;
		oflags = FMODE_READ | SMB_O_CREAT;

	if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
		rc = cifs_posix_open(full_path, &newinode, nd->path.mnt,
				     mode, oflags, &oplock, &fileHandle, xid);
		rc = cifs_posix_open(full_path, &newinode,
			nd ? nd->path.mnt : NULL,
			inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
		/* EIO could indicate that (posix open) operation is not
		   supported, despite what server claimed in capability
		   negotation.  EREMOTE indicates DFS junction, which is not
@@ -677,6 +680,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
		     (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
		     (nd->intent.open.flags & O_CREAT)) {
			rc = cifs_posix_open(full_path, &newInode, nd->path.mnt,
					parent_dir_inode->i_sb,
					nd->intent.open.create_mode,
					nd->intent.open.flags, &oplock,
					&fileHandle, xid);
+7 −4
Original line number Diff line number Diff line
@@ -298,8 +298,10 @@ int cifs_open(struct inode *inode, struct file *file)
	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
			le64_to_cpu(tcon->fsUnixInfo.Capability))) {
		int oflags = (int) cifs_posix_convert_flags(file->f_flags);
		oflags |= SMB_O_CREAT;
		/* can not refresh inode info since size could be stale */
		rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
				inode->i_sb,
				cifs_sb->mnt_file_mode /* ignored */,
				oflags, &oplock, &netfid, xid);
		if (rc == 0) {
@@ -513,6 +515,7 @@ reopen_error_exit:
		int oflags = (int) cifs_posix_convert_flags(file->f_flags);
		/* can not refresh inode info since size could be stale */
		rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
				inode->i_sb,
				cifs_sb->mnt_file_mode /* ignored */,
				oflags, &oplock, &netfid, xid);
		if (rc == 0) {