Commit fa588e0c authored by Steve French's avatar Steve French

[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
...@@ -107,8 +107,10 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, ...@@ -107,8 +107,10 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode,
__u16 fileHandle, struct file *file, __u16 fileHandle, struct file *file,
struct vfsmount *mnt, unsigned int oflags); 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 vfsmount *mnt, int mode, int oflags, struct vfsmount *mnt,
__u32 *poplock, __u16 *pnetfid, int xid); 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, 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);
......
...@@ -182,13 +182,14 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, ...@@ -182,13 +182,14 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
} }
int cifs_posix_open(char *full_path, struct inode **pinode, int cifs_posix_open(char *full_path, struct inode **pinode,
struct vfsmount *mnt, int mode, int oflags, struct vfsmount *mnt, struct super_block *sb,
__u32 *poplock, __u16 *pnetfid, int xid) int mode, int oflags,
__u32 *poplock, __u16 *pnetfid, int xid)
{ {
int rc; int rc;
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(mnt->mnt_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_fattr fattr; struct cifs_fattr fattr;
cFYI(1, "posix open %s", full_path); cFYI(1, "posix open %s", full_path);
...@@ -241,7 +242,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, ...@@ -241,7 +242,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(mnt->mnt_sb, &fattr); *pinode = cifs_iget(sb, &fattr);
if (!*pinode) { if (!*pinode) {
rc = -ENOMEM; rc = -ENOMEM;
goto posix_open_ret; goto posix_open_ret;
...@@ -250,7 +251,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode, ...@@ -250,7 +251,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
cifs_fattr_to_inode(*pinode, &fattr); cifs_fattr_to_inode(*pinode, &fattr);
} }
cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags); if (mnt)
cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, oflags);
posix_open_ret: posix_open_ret:
kfree(presp_data); kfree(presp_data);
...@@ -314,13 +316,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -314,13 +316,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if (nd && (nd->flags & LOOKUP_OPEN)) if (nd && (nd->flags & LOOKUP_OPEN))
oflags = nd->intent.open.flags; oflags = nd->intent.open.flags;
else else
oflags = FMODE_READ; oflags = FMODE_READ | SMB_O_CREAT;
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, nd->path.mnt, rc = cifs_posix_open(full_path, &newinode,
mode, oflags, &oplock, &fileHandle, xid); nd ? nd->path.mnt : NULL,
inode->i_sb, 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
negotation. EREMOTE indicates DFS junction, which is not negotation. EREMOTE indicates DFS junction, which is not
...@@ -677,6 +680,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -677,6 +680,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
(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, nd->path.mnt, 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);
......
...@@ -298,10 +298,12 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -298,10 +298,12 @@ int cifs_open(struct inode *inode, struct file *file)
(CIFS_UNIX_POSIX_PATH_OPS_CAP & (CIFS_UNIX_POSIX_PATH_OPS_CAP &
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);
oflags |= SMB_O_CREAT;
/* 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, file->f_path.mnt, rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
cifs_sb->mnt_file_mode /* ignored */, inode->i_sb,
oflags, &oplock, &netfid, xid); cifs_sb->mnt_file_mode /* ignored */,
oflags, &oplock, &netfid, xid);
if (rc == 0) { if (rc == 0) {
cFYI(1, "posix open succeeded"); cFYI(1, "posix open succeeded");
/* no need for special case handling of setting mode /* no need for special case handling of setting mode
...@@ -513,8 +515,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush) ...@@ -513,8 +515,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
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, file->f_path.mnt, rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
cifs_sb->mnt_file_mode /* ignored */, inode->i_sb,
oflags, &oplock, &netfid, xid); cifs_sb->mnt_file_mode /* ignored */,
oflags, &oplock, &netfid, xid);
if (rc == 0) { if (rc == 0) {
cFYI(1, "posix reopen succeeded"); cFYI(1, "posix reopen succeeded");
goto reopen_success; goto reopen_success;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment