On 5 October 2022 04:39:43 GMT-03:00, Steve French <smfrench@xxxxxxxxx> wrote: >could you fixup some of the checkpatch warnings - the ENOSYS one looks >like a potential problem and "unsigned int" is better style than >"unsigned" etc. > >WARNING: function definition argument 'const unsigned int' should also >have an identifier name >#113: FILE: fs/cifs/cifsglob.h:333: >+ int (*query_path_info)(const unsigned int, struct cifs_tcon *, >struct cifs_sb_info *, > >WARNING: function definition argument 'struct cifs_tcon *' should also >have an identifier name >#113: FILE: fs/cifs/cifsglob.h:333: >+ int (*query_path_info)(const unsigned int, struct cifs_tcon *, >struct cifs_sb_info *, > >WARNING: function definition argument 'struct cifs_sb_info *' should >also have an identifier name >#113: FILE: fs/cifs/cifsglob.h:333: >+ int (*query_path_info)(const unsigned int, struct cifs_tcon *, >struct cifs_sb_info *, > >WARNING: function definition argument 'const char *' should also have >an identifier name >#113: FILE: fs/cifs/cifsglob.h:333: >+ int (*query_path_info)(const unsigned int, struct cifs_tcon *, >struct cifs_sb_info *, > >WARNING: function definition argument 'struct cifs_open_info_data *' >should also have an identifier name >#113: FILE: fs/cifs/cifsglob.h:333: >+ int (*query_path_info)(const unsigned int, struct cifs_tcon *, >struct cifs_sb_info *, > >WARNING: function definition argument 'bool *' should also have an >identifier name >#113: FILE: fs/cifs/cifsglob.h:333: >+ int (*query_path_info)(const unsigned int, struct cifs_tcon *, >struct cifs_sb_info *, > >WARNING: function definition argument 'bool *' should also have an >identifier name >#113: FILE: fs/cifs/cifsglob.h:333: >+ int (*query_path_info)(const unsigned int, struct cifs_tcon *, >struct cifs_sb_info *, > >WARNING: function definition argument 'const unsigned int' should also >have an identifier name >#118: FILE: fs/cifs/cifsglob.h:336: >+ int (*query_file_info)(const unsigned int, struct cifs_tcon *, >struct cifsFileInfo *, > >WARNING: function definition argument 'struct cifs_tcon *' should also >have an identifier name >#118: FILE: fs/cifs/cifsglob.h:336: >+ int (*query_file_info)(const unsigned int, struct cifs_tcon *, >struct cifsFileInfo *, > >WARNING: function definition argument 'struct cifsFileInfo *' should >also have an identifier name >#118: FILE: fs/cifs/cifsglob.h:336: >+ int (*query_file_info)(const unsigned int, struct cifs_tcon *, >struct cifsFileInfo *, > >WARNING: function definition argument 'struct cifs_open_info_data *' >should also have an identifier name >#118: FILE: fs/cifs/cifsglob.h:336: >+ int (*query_file_info)(const unsigned int, struct cifs_tcon *, >struct cifsFileInfo *, > >WARNING: function definition argument 'const unsigned int' should also >have an identifier name >#128: FILE: fs/cifs/cifsglob.h:343: >+ int (*get_srv_inum)(const unsigned int, struct cifs_tcon *, struct >cifs_sb_info *, > >WARNING: function definition argument 'struct cifs_tcon *' should also >have an identifier name >#128: FILE: fs/cifs/cifsglob.h:343: >+ int (*get_srv_inum)(const unsigned int, struct cifs_tcon *, struct >cifs_sb_info *, > >WARNING: function definition argument 'struct cifs_sb_info *' should >also have an identifier name >#128: FILE: fs/cifs/cifsglob.h:343: >+ int (*get_srv_inum)(const unsigned int, struct cifs_tcon *, struct >cifs_sb_info *, > >WARNING: function definition argument 'const char *' should also have >an identifier name >#128: FILE: fs/cifs/cifsglob.h:343: >+ int (*get_srv_inum)(const unsigned int, struct cifs_tcon *, struct >cifs_sb_info *, > >WARNING: function definition argument 'struct cifs_open_info_data *' >should also have an identifier name >#128: FILE: fs/cifs/cifsglob.h:343: >+ int (*get_srv_inum)(const unsigned int, struct cifs_tcon *, struct >cifs_sb_info *, > >WARNING: function definition argument 'const unsigned int' should also >have an identifier name >#139: FILE: fs/cifs/cifsglob.h:393: >+ int (*open)(const unsigned int, struct cifs_open_parms *, __u32 *, void *); > >WARNING: function definition argument 'struct cifs_open_parms *' >should also have an identifier name >#139: FILE: fs/cifs/cifsglob.h:393: >+ int (*open)(const unsigned int, struct cifs_open_parms *, __u32 *, void *); > >WARNING: function definition argument '__u32 *' should also have an >identifier name >#139: FILE: fs/cifs/cifsglob.h:393: >+ int (*open)(const unsigned int, struct cifs_open_parms *, __u32 *, void *); > >WARNING: function definition argument 'void *' should also have an >identifier name >#139: FILE: fs/cifs/cifsglob.h:393: >+ int (*open)(const unsigned int, struct cifs_open_parms *, __u32 *, void *); > >WARNING: Prefer 'unsigned int' to bare use of 'unsigned' >#226: FILE: fs/cifs/dir.c:169: >+ struct tcon_link *tlink, unsigned oflags, umode_t mode, __u32 *oplock, > >WARNING: ENOSYS means 'invalid syscall nr' and nothing else >#525: FILE: fs/cifs/inode.c:436: >+ return -ENOSYS; > >total: 0 errors, 23 warnings, 1689 lines checked > >On Tue, Oct 4, 2022 at 1:12 PM Paulo Alcantara <pc@xxxxxx> wrote: >> >> When creating inode for symlink, the client used to send below >> requests to fill it in: >> >> * create+query_info+close (STATUS_STOPPED_ON_SYMLINK) >> * create(+reparse_flag)+query_info+close (set file attrs) >> * create+ioctl(get_reparse)+close (query reparse tag) >> >> and then for every access to the symlink dentry, the ->link() method >> would send another: >> >> * create+ioctl(get_reparse)+close (parse symlink) >> >> So, in order to improve: >> >> (i) Get rid of unnecessary roundtrips and then resolve symlinks as >> follows: >> >> * create+query_info+close (STATUS_STOPPED_ON_SYMLINK + parse symlink + get reparse tag) >> * create(+reparse_flag)+query_info+close (set file attrs) >> >> (ii) Set the resolved symlink target directly in inode->i_link and >> use simple_get_link() for ->link() to simply return it. >> >> Signed-off-by: Paulo Alcantara (SUSE) <pc@xxxxxx> >> --- >> fs/cifs/cifsfs.c | 9 ++- >> fs/cifs/cifsglob.h | 43 ++++++++--- >> fs/cifs/cifsproto.h | 13 ++-- >> fs/cifs/dir.c | 30 +++----- >> fs/cifs/file.c | 41 ++++++----- >> fs/cifs/inode.c | 170 ++++++++++++++++++++++++++------------------ >> fs/cifs/link.c | 107 +--------------------------- >> fs/cifs/readdir.c | 2 + >> fs/cifs/smb1ops.c | 56 +++++++++------ >> fs/cifs/smb2file.c | 127 +++++++++++++++++++++++++++------ >> fs/cifs/smb2inode.c | 169 ++++++++++++++++++++++--------------------- >> fs/cifs/smb2ops.c | 109 ++++++---------------------- >> fs/cifs/smb2pdu.h | 3 + >> fs/cifs/smb2proto.h | 22 +++--- >> 14 files changed, 448 insertions(+), 453 deletions(-) >> >> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c >> index 8042d7280dec..c6ac19223ddc 100644 >> --- a/fs/cifs/cifsfs.c >> +++ b/fs/cifs/cifsfs.c >> @@ -396,6 +396,7 @@ cifs_alloc_inode(struct super_block *sb) >> cifs_inode->epoch = 0; >> spin_lock_init(&cifs_inode->open_file_lock); >> generate_random_uuid(cifs_inode->lease_key); >> + cifs_inode->symlink_target = NULL; >> >> /* >> * Can not set i_flags here - they get immediately overwritten to zero >> @@ -412,7 +413,11 @@ cifs_alloc_inode(struct super_block *sb) >> static void >> cifs_free_inode(struct inode *inode) >> { >> - kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); >> + struct cifsInodeInfo *cinode = CIFS_I(inode); >> + >> + if (S_ISLNK(inode->i_mode)) >> + kfree(cinode->symlink_target); >> + kmem_cache_free(cifs_inode_cachep, cinode); >> } >> >> static void >> @@ -1139,7 +1144,7 @@ const struct inode_operations cifs_file_inode_ops = { >> }; >> >> const struct inode_operations cifs_symlink_inode_ops = { >> - .get_link = cifs_get_link, >> + .get_link = simple_get_link, >> .permission = cifs_permission, >> .listxattr = cifs_listxattr, >> }; >> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h >> index 52ddf4163b98..9a3386d827b6 100644 >> --- a/fs/cifs/cifsglob.h >> +++ b/fs/cifs/cifsglob.h >> @@ -185,6 +185,19 @@ struct cifs_cred { >> struct cifs_ace *aces; >> }; >> >> +struct cifs_open_info_data { >> + char *symlink_target; >> + union { >> + struct smb2_file_all_info fi; >> + struct smb311_posix_qinfo posix_fi; >> + }; >> +}; >> + >> +static inline void cifs_free_open_info(struct cifs_open_info_data *data) >> +{ >> + kfree(data->symlink_target); >> +} >> + >> /* >> ***************************************************************** >> * Except the CIFS PDUs themselves all the >> @@ -307,20 +320,18 @@ struct smb_version_operations { >> int (*is_path_accessible)(const unsigned int, struct cifs_tcon *, >> struct cifs_sb_info *, const char *); >> /* query path data from the server */ >> - int (*query_path_info)(const unsigned int, struct cifs_tcon *, >> - struct cifs_sb_info *, const char *, >> - FILE_ALL_INFO *, bool *, bool *); >> + int (*query_path_info)(const unsigned int, struct cifs_tcon *, struct cifs_sb_info *, >> + const char *, struct cifs_open_info_data *, bool *, bool *); >> /* query file data from the server */ >> - int (*query_file_info)(const unsigned int, struct cifs_tcon *, >> - struct cifs_fid *, FILE_ALL_INFO *); >> + int (*query_file_info)(const unsigned int, struct cifs_tcon *, struct cifsFileInfo *, >> + struct cifs_open_info_data *); >> /* query reparse tag from srv to determine which type of special file */ >> int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon, >> struct cifs_sb_info *cifs_sb, const char *path, >> __u32 *reparse_tag); >> /* get server index number */ >> - int (*get_srv_inum)(const unsigned int, struct cifs_tcon *, >> - struct cifs_sb_info *, const char *, >> - u64 *uniqueid, FILE_ALL_INFO *); >> + int (*get_srv_inum)(const unsigned int, struct cifs_tcon *, struct cifs_sb_info *, >> + const char *, u64 *uniqueid, struct cifs_open_info_data *); >> /* set size by path */ >> int (*set_path_size)(const unsigned int, struct cifs_tcon *, >> const char *, __u64, struct cifs_sb_info *, bool); >> @@ -369,8 +380,7 @@ struct smb_version_operations { >> struct cifs_sb_info *, const char *, >> char **, bool); >> /* open a file for non-posix mounts */ >> - int (*open)(const unsigned int, struct cifs_open_parms *, >> - __u32 *, FILE_ALL_INFO *); >> + int (*open)(const unsigned int, struct cifs_open_parms *, __u32 *, void *); >> /* set fid protocol-specific info */ >> void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32); >> /* close a file */ >> @@ -1123,6 +1133,7 @@ struct cifs_fattr { >> struct timespec64 cf_mtime; >> struct timespec64 cf_ctime; >> u32 cf_cifstag; >> + char *cf_symlink_target; >> }; >> >> /* >> @@ -1385,6 +1396,7 @@ struct cifsFileInfo { >> struct work_struct put; /* work for the final part of _put */ >> struct delayed_work deferred; >> bool deferred_close_scheduled; /* Flag to indicate close is scheduled */ >> + char *symlink_target; >> }; >> >> struct cifs_io_parms { >> @@ -1543,6 +1555,7 @@ struct cifsInodeInfo { >> struct list_head deferred_closes; /* list of deferred closes */ >> spinlock_t deferred_lock; /* protection on deferred list */ >> bool lease_granted; /* Flag to indicate whether lease or oplock is granted. */ >> + char *symlink_target; >> }; >> >> static inline struct cifsInodeInfo * >> @@ -2111,4 +2124,14 @@ static inline size_t ntlmssp_workstation_name_size(const struct cifs_ses *ses) >> return sizeof(ses->workstation_name); >> } >> >> +static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const FILE_ALL_INFO *src) >> +{ >> + memcpy(dst, src, (size_t)((u8 *)&src->AccessFlags - (u8 *)src)); >> + dst->AccessFlags = src->AccessFlags; >> + dst->CurrentByteOffset = src->CurrentByteOffset; >> + dst->Mode = src->Mode; >> + dst->AlignmentRequirement = src->AlignmentRequirement; >> + dst->FileNameLength = src->FileNameLength; >> +} >> + >> #endif /* _CIFS_GLOB_H */ >> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h >> index f5adcb8ea04d..13a675d9d3b9 100644 >> --- a/fs/cifs/cifsproto.h >> +++ b/fs/cifs/cifsproto.h >> @@ -182,10 +182,9 @@ extern int cifs_unlock_range(struct cifsFileInfo *cfile, >> extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile); >> >> extern void cifs_down_write(struct rw_semaphore *sem); >> -extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, >> - struct file *file, >> - struct tcon_link *tlink, >> - __u32 oplock); >> +struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, >> + struct tcon_link *tlink, __u32 oplock, >> + const char *symlink_target); >> extern int cifs_posix_open(const char *full_path, struct inode **inode, >> struct super_block *sb, int mode, >> unsigned int f_flags, __u32 *oplock, __u16 *netfid, >> @@ -200,9 +199,9 @@ extern int cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); >> extern struct inode *cifs_iget(struct super_block *sb, >> struct cifs_fattr *fattr); >> >> -extern int cifs_get_inode_info(struct inode **inode, const char *full_path, >> - FILE_ALL_INFO *data, struct super_block *sb, >> - int xid, const struct cifs_fid *fid); >> +int cifs_get_inode_info(struct inode **inode, const char *full_path, >> + struct cifs_open_info_data *data, struct super_block *sb, int xid, >> + const struct cifs_fid *fid); >> extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path, >> struct super_block *sb, unsigned int xid); >> extern int cifs_get_inode_info_unix(struct inode **pinode, >> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c >> index f58869306309..4edd55384662 100644 >> --- a/fs/cifs/dir.c >> +++ b/fs/cifs/dir.c >> @@ -165,10 +165,9 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon) >> >> /* Inode operations in similar order to how they appear in Linux file fs.h */ >> >> -static int >> -cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, >> - struct tcon_link *tlink, unsigned oflags, umode_t mode, >> - __u32 *oplock, struct cifs_fid *fid) >> +static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, >> + struct tcon_link *tlink, unsigned oflags, umode_t mode, __u32 *oplock, >> + struct cifs_fid *fid, struct cifs_open_info_data *buf) >> { >> int rc = -ENOENT; >> int create_options = CREATE_NOT_DIR; >> @@ -177,7 +176,6 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, >> struct cifs_tcon *tcon = tlink_tcon(tlink); >> const char *full_path; >> void *page = alloc_dentry_path(); >> - FILE_ALL_INFO *buf = NULL; >> struct inode *newinode = NULL; >> int disposition; >> struct TCP_Server_Info *server = tcon->ses->server; >> @@ -290,12 +288,6 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, >> goto out; >> } >> >> - buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); >> - if (buf == NULL) { >> - rc = -ENOMEM; >> - goto out; >> - } >> - >> /* >> * if we're not using unix extensions, see if we need to set >> * ATTR_READONLY on the create call >> @@ -364,8 +356,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, >> { >> #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ >> /* TODO: Add support for calling POSIX query info here, but passing in fid */ >> - rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, >> - xid, fid); >> + rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, xid, fid); >> if (newinode) { >> if (server->ops->set_lease_key) >> server->ops->set_lease_key(newinode, fid); >> @@ -402,7 +393,6 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, >> d_add(direntry, newinode); >> >> out: >> - kfree(buf); >> free_dentry_path(page); >> return rc; >> >> @@ -427,6 +417,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, >> struct cifs_pending_open open; >> __u32 oplock; >> struct cifsFileInfo *file_info; >> + struct cifs_open_info_data buf = {}; >> >> if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) >> return -EIO; >> @@ -484,8 +475,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, >> cifs_add_pending_open(&fid, tlink, &open); >> >> rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, >> - &oplock, &fid); >> - >> + &oplock, &fid, &buf); >> if (rc) { >> cifs_del_pending_open(&open); >> goto out; >> @@ -510,7 +500,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, >> file->f_op = &cifs_file_direct_ops; >> } >> >> - file_info = cifs_new_fileinfo(&fid, file, tlink, oplock); >> + file_info = cifs_new_fileinfo(&fid, file, tlink, oplock, buf.symlink_target); >> if (file_info == NULL) { >> if (server->ops->close) >> server->ops->close(xid, tcon, &fid); >> @@ -526,6 +516,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, >> cifs_put_tlink(tlink); >> out_free_xid: >> free_xid(xid); >> + cifs_free_open_info(&buf); >> return rc; >> } >> >> @@ -547,6 +538,7 @@ int cifs_create(struct user_namespace *mnt_userns, struct inode *inode, >> struct TCP_Server_Info *server; >> struct cifs_fid fid; >> __u32 oplock; >> + struct cifs_open_info_data buf = {}; >> >> cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n", >> inode, direntry, direntry); >> @@ -565,11 +557,11 @@ int cifs_create(struct user_namespace *mnt_userns, struct inode *inode, >> if (server->ops->new_lease_key) >> server->ops->new_lease_key(&fid); >> >> - rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, >> - &oplock, &fid); >> + rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, &oplock, &fid, &buf); >> if (!rc && server->ops->close) >> server->ops->close(xid, tcon, &fid); >> >> + cifs_free_open_info(&buf); >> cifs_put_tlink(tlink); >> out_free_xid: >> free_xid(xid); >> diff --git a/fs/cifs/file.c b/fs/cifs/file.c >> index 7d756721e1a6..dcec1690312b 100644 >> --- a/fs/cifs/file.c >> +++ b/fs/cifs/file.c >> @@ -209,16 +209,14 @@ int cifs_posix_open(const char *full_path, struct inode **pinode, >> } >> #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ >> >> -static int >> -cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, >> - struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock, >> - struct cifs_fid *fid, unsigned int xid) >> +static int cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, >> + struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock, >> + struct cifs_fid *fid, unsigned int xid, struct cifs_open_info_data *buf) >> { >> int rc; >> int desired_access; >> int disposition; >> int create_options = CREATE_NOT_DIR; >> - FILE_ALL_INFO *buf; >> struct TCP_Server_Info *server = tcon->ses->server; >> struct cifs_open_parms oparms; >> >> @@ -255,10 +253,6 @@ cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *ci >> >> /* BB pass O_SYNC flag through on file attributes .. BB */ >> >> - buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); >> - if (!buf) >> - return -ENOMEM; >> - >> /* O_SYNC also has bit for O_DSYNC so following check picks up either */ >> if (f_flags & O_SYNC) >> create_options |= CREATE_WRITE_THROUGH; >> @@ -276,9 +270,8 @@ cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *ci >> oparms.reconnect = false; >> >> rc = server->ops->open(xid, &oparms, oplock, buf); >> - >> if (rc) >> - goto out; >> + return rc; >> >> /* TODO: Add support for calling posix query info but with passing in fid */ >> if (tcon->unix_ext) >> @@ -294,8 +287,6 @@ cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *ci >> rc = -EOPENSTALE; >> } >> >> -out: >> - kfree(buf); >> return rc; >> } >> >> @@ -325,9 +316,9 @@ cifs_down_write(struct rw_semaphore *sem) >> >> static void cifsFileInfo_put_work(struct work_struct *work); >> >> -struct cifsFileInfo * >> -cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, >> - struct tcon_link *tlink, __u32 oplock) >> +struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, >> + struct tcon_link *tlink, __u32 oplock, >> + const char *symlink_target) >> { >> struct dentry *dentry = file_dentry(file); >> struct inode *inode = d_inode(dentry); >> @@ -347,6 +338,15 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, >> return NULL; >> } >> >> + if (symlink_target) { >> + cfile->symlink_target = kstrdup(symlink_target, GFP_KERNEL); >> + if (!cfile->symlink_target) { >> + kfree(fdlocks); >> + kfree(cfile); >> + return NULL; >> + } >> + } >> + >> INIT_LIST_HEAD(&fdlocks->locks); >> fdlocks->cfile = cfile; >> cfile->llist = fdlocks; >> @@ -440,6 +440,7 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file) >> cifs_put_tlink(cifs_file->tlink); >> dput(cifs_file->dentry); >> cifs_sb_deactive(sb); >> + kfree(cifs_file->symlink_target); >> kfree(cifs_file); >> } >> >> @@ -572,6 +573,7 @@ int cifs_open(struct inode *inode, struct file *file) >> bool posix_open_ok = false; >> struct cifs_fid fid; >> struct cifs_pending_open open; >> + struct cifs_open_info_data data = {}; >> >> xid = get_xid(); >> >> @@ -662,15 +664,15 @@ int cifs_open(struct inode *inode, struct file *file) >> if (server->ops->get_lease_key) >> server->ops->get_lease_key(inode, &fid); >> >> - rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, >> - file->f_flags, &oplock, &fid, xid); >> + rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, file->f_flags, &oplock, &fid, >> + xid, &data); >> if (rc) { >> cifs_del_pending_open(&open); >> goto out; >> } >> } >> >> - cfile = cifs_new_fileinfo(&fid, file, tlink, oplock); >> + cfile = cifs_new_fileinfo(&fid, file, tlink, oplock, data.symlink_target); >> if (cfile == NULL) { >> if (server->ops->close) >> server->ops->close(xid, tcon, &fid); >> @@ -712,6 +714,7 @@ int cifs_open(struct inode *inode, struct file *file) >> free_dentry_path(page); >> free_xid(xid); >> cifs_put_tlink(tlink); >> + cifs_free_open_info(&data); >> return rc; >> } >> >> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c >> index 3784d3a88053..37ada3912022 100644 >> --- a/fs/cifs/inode.c >> +++ b/fs/cifs/inode.c >> @@ -212,6 +212,17 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) >> } >> spin_unlock(&inode->i_lock); >> >> + if (S_ISLNK(fattr->cf_mode)) { >> + kfree(cifs_i->symlink_target); >> + cifs_i->symlink_target = fattr->cf_symlink_target; >> + fattr->cf_symlink_target = NULL; >> + >> + if (unlikely(!cifs_i->symlink_target)) >> + inode->i_link = ERR_PTR(-EOPNOTSUPP); >> + else >> + inode->i_link = cifs_i->symlink_target; >> + } >> + >> if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL) >> inode->i_flags |= S_AUTOMOUNT; >> if (inode->i_state & I_NEW) >> @@ -347,13 +358,20 @@ cifs_get_file_info_unix(struct file *filp) >> int rc; >> unsigned int xid; >> FILE_UNIX_BASIC_INFO find_data; >> - struct cifs_fattr fattr; >> + struct cifs_fattr fattr = {}; >> struct inode *inode = file_inode(filp); >> struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); >> struct cifsFileInfo *cfile = filp->private_data; >> struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); >> >> xid = get_xid(); >> + >> + if (cfile->symlink_target) { >> + fattr.cf_symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL); >> + if (!fattr.cf_symlink_target) >> + return -ENOMEM; >> + } >> + >> rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data); >> if (!rc) { >> cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); >> @@ -378,6 +396,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, >> FILE_UNIX_BASIC_INFO find_data; >> struct cifs_fattr fattr; >> struct cifs_tcon *tcon; >> + struct TCP_Server_Info *server; >> struct tcon_link *tlink; >> struct cifs_sb_info *cifs_sb = CIFS_SB(sb); >> >> @@ -387,10 +406,12 @@ int cifs_get_inode_info_unix(struct inode **pinode, >> if (IS_ERR(tlink)) >> return PTR_ERR(tlink); >> tcon = tlink_tcon(tlink); >> + server = tcon->ses->server; >> >> /* could have done a find first instead but this returns more info */ >> rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, >> cifs_sb->local_nls, cifs_remap(cifs_sb)); >> + cifs_dbg(FYI, "%s: query path info: rc = %d\n", __func__, rc); >> cifs_put_tlink(tlink); >> >> if (!rc) { >> @@ -410,6 +431,17 @@ int cifs_get_inode_info_unix(struct inode **pinode, >> cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); >> } >> >> + if (S_ISLNK(fattr.cf_mode) && !fattr.cf_symlink_target) { >> + if (!server->ops->query_symlink) >> + return -ENOSYS; >> + rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path, >> + &fattr.cf_symlink_target, false); >> + if (rc) { >> + cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); >> + goto cgiiu_exit; >> + } >> + } >> + >> if (*pinode == NULL) { >> /* get new inode */ >> cifs_fill_uniqueid(sb, &fattr); >> @@ -432,6 +464,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, >> } >> >> cgiiu_exit: >> + kfree(fattr.cf_symlink_target); >> return rc; >> } >> #else >> @@ -601,10 +634,10 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, >> } >> >> /* Fill a cifs_fattr struct with info from POSIX info struct */ >> -static void >> -smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo *info, >> - struct super_block *sb, bool adjust_tz, bool symlink) >> +static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data, >> + struct super_block *sb, bool adjust_tz, bool symlink) >> { >> + struct smb311_posix_qinfo *info = &data->posix_fi; >> struct cifs_sb_info *cifs_sb = CIFS_SB(sb); >> struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); >> >> @@ -639,6 +672,8 @@ smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo * >> if (symlink) { >> fattr->cf_mode |= S_IFLNK; >> fattr->cf_dtype = DT_LNK; >> + fattr->cf_symlink_target = data->symlink_target; >> + data->symlink_target = NULL; >> } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { >> fattr->cf_mode |= S_IFDIR; >> fattr->cf_dtype = DT_DIR; >> @@ -655,13 +690,11 @@ smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo * >> fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); >> } >> >> - >> -/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ >> -static void >> -cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, >> - struct super_block *sb, bool adjust_tz, >> - bool symlink, u32 reparse_tag) >> +static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data, >> + struct super_block *sb, bool adjust_tz, bool symlink, >> + u32 reparse_tag) >> { >> + struct smb2_file_all_info *info = &data->fi; >> struct cifs_sb_info *cifs_sb = CIFS_SB(sb); >> struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); >> >> @@ -703,7 +736,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, >> } else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) { >> fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; >> fattr->cf_dtype = DT_BLK; >> - } else if (symlink) { /* TODO add more reparse tag checks */ >> + } else if (symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK || >> + reparse_tag == IO_REPARSE_TAG_NFS) { >> fattr->cf_mode = S_IFLNK; >> fattr->cf_dtype = DT_LNK; >> } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { >> @@ -735,6 +769,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, >> } >> } >> >> + if (S_ISLNK(fattr->cf_mode)) { >> + fattr->cf_symlink_target = data->symlink_target; >> + data->symlink_target = NULL; >> + } >> + >> fattr->cf_uid = cifs_sb->ctx->linux_uid; >> fattr->cf_gid = cifs_sb->ctx->linux_gid; >> } >> @@ -744,23 +783,28 @@ cifs_get_file_info(struct file *filp) >> { >> int rc; >> unsigned int xid; >> - FILE_ALL_INFO find_data; >> + struct cifs_open_info_data data = {}; >> struct cifs_fattr fattr; >> struct inode *inode = file_inode(filp); >> struct cifsFileInfo *cfile = filp->private_data; >> struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); >> struct TCP_Server_Info *server = tcon->ses->server; >> + bool symlink = false; >> + u32 tag = 0; >> >> if (!server->ops->query_file_info) >> return -ENOSYS; >> >> xid = get_xid(); >> - rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data); >> + rc = server->ops->query_file_info(xid, tcon, Yep.