diff options
Diffstat (limited to 'fs/smb/client/inode.c')
-rw-r--r-- | fs/smb/client/inode.c | 140 |
1 files changed, 86 insertions, 54 deletions
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index cb9e719e67..4c3dec384f 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -104,7 +104,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode); mtime = inode_get_mtime(inode); if (timespec64_equal(&mtime, &fattr->cf_mtime) && - cifs_i->server_eof == fattr->cf_eof) { + cifs_i->netfs.remote_i_size == fattr->cf_eof) { cifs_dbg(FYI, "%s: inode %llu is unchanged\n", __func__, cifs_i->uniqueid); return; @@ -195,7 +195,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, else clear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags); - cifs_i->server_eof = fattr->cf_eof; + cifs_i->netfs.remote_i_size = fattr->cf_eof; /* * Can't safely change the file size here if the client is writing to * it due to potential races. @@ -666,8 +666,6 @@ 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 cifs_open_info_data *data, - struct cifs_sid *owner, - struct cifs_sid *group, struct super_block *sb) { struct smb311_posix_qinfo *info = &data->posix_fi; @@ -693,31 +691,38 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; } + /* + * The srv fs device id is overridden on network mount so setting + * @fattr->cf_rdev isn't needed here. + */ fattr->cf_eof = le64_to_cpu(info->EndOfFile); fattr->cf_bytes = le64_to_cpu(info->AllocationSize); fattr->cf_createtime = le64_to_cpu(info->CreationTime); - fattr->cf_nlink = le32_to_cpu(info->HardLinks); fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); - /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ - /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ - if (data->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) { + if (cifs_open_data_reparse(data) && + cifs_reparse_point_to_fattr(cifs_sb, fattr, data)) + goto out_reparse; + + fattr->cf_mode &= ~S_IFMT; + if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { fattr->cf_mode |= S_IFDIR; fattr->cf_dtype = DT_DIR; } else { /* file */ fattr->cf_mode |= S_IFREG; fattr->cf_dtype = DT_REG; } - /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ - sid_to_id(cifs_sb, owner, fattr, SIDOWNER); - sid_to_id(cifs_sb, group, fattr, SIDGROUP); +out_reparse: + if (S_ISLNK(fattr->cf_mode)) { + if (likely(data->symlink_target)) + fattr->cf_eof = strnlen(data->symlink_target, PATH_MAX); + fattr->cf_symlink_target = data->symlink_target; + data->symlink_target = NULL; + } + sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER); + sid_to_id(cifs_sb, &data->posix_group, fattr, SIDGROUP); cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); @@ -740,25 +745,25 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, if (tag == IO_REPARSE_TAG_NFS && buf) { switch (le64_to_cpu(buf->InodeType)) { case NFS_SPECFILE_CHR: - fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFCHR; fattr->cf_dtype = DT_CHR; fattr->cf_rdev = nfs_mkdev(buf); break; case NFS_SPECFILE_BLK: - fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFBLK; fattr->cf_dtype = DT_BLK; fattr->cf_rdev = nfs_mkdev(buf); break; case NFS_SPECFILE_FIFO: - fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFIFO; fattr->cf_dtype = DT_FIFO; break; case NFS_SPECFILE_SOCK: - fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFSOCK; fattr->cf_dtype = DT_SOCK; break; case NFS_SPECFILE_LNK: - fattr->cf_mode = S_IFLNK | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFLNK; fattr->cf_dtype = DT_LNK; break; default: @@ -770,29 +775,29 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, switch (tag) { case IO_REPARSE_TAG_LX_SYMLINK: - fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFLNK; fattr->cf_dtype = DT_LNK; break; case IO_REPARSE_TAG_LX_FIFO: - fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFIFO; fattr->cf_dtype = DT_FIFO; break; case IO_REPARSE_TAG_AF_UNIX: - fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFSOCK; fattr->cf_dtype = DT_SOCK; break; case IO_REPARSE_TAG_LX_CHR: - fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFCHR; fattr->cf_dtype = DT_CHR; break; case IO_REPARSE_TAG_LX_BLK: - fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFBLK; fattr->cf_dtype = DT_BLK; break; case 0: /* SMB1 symlink */ case IO_REPARSE_TAG_SYMLINK: case IO_REPARSE_TAG_NFS: - fattr->cf_mode = S_IFLNK | cifs_sb->ctx->file_mode; + fattr->cf_mode |= S_IFLNK; fattr->cf_dtype = DT_LNK; break; default: @@ -832,6 +837,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, fattr->cf_createtime = le64_to_cpu(info->CreationTime); fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); + fattr->cf_mode = cifs_sb->ctx->file_mode; if (cifs_open_data_reparse(data) && cifs_reparse_point_to_fattr(cifs_sb, fattr, data)) goto out_reparse; @@ -1078,6 +1084,9 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data, &rsp_iov, &rsp_buftype); if (!rc) iov = &rsp_iov; + } else if (data->reparse.io.buftype != CIFS_NO_BUFFER && + data->reparse.io.iov.iov_base) { + iov = &data->reparse.io.iov; } rc = -EOPNOTSUPP; @@ -1094,16 +1103,20 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data, rc = 0; goto out; default: - if (data->symlink_target) { + /* Check for cached reparse point data */ + if (data->symlink_target || data->reparse.buf) { rc = 0; - } else if (server->ops->parse_reparse_point) { + } else if (iov && server->ops->parse_reparse_point) { rc = server->ops->parse_reparse_point(cifs_sb, iov, data); } break; } - cifs_open_info_to_fattr(fattr, data, sb); + if (tcon->posix_extensions) + smb311_posix_info_to_fattr(fattr, data, sb); + else + cifs_open_info_to_fattr(fattr, data, sb); out: fattr->cf_cifstag = data->reparse.tag; free_rsp_buf(rsp_buftype, rsp_iov.iov_base); @@ -1293,31 +1306,34 @@ out: return rc; } -static int smb311_posix_get_fattr(struct cifs_fattr *fattr, +static int smb311_posix_get_fattr(struct cifs_open_info_data *data, + struct cifs_fattr *fattr, const char *full_path, struct super_block *sb, const unsigned int xid) { - struct cifs_open_info_data data = {}; + struct cifs_open_info_data tmp_data = {}; + struct TCP_Server_Info *server; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_tcon *tcon; struct tcon_link *tlink; - struct cifs_sid owner, group; int tmprc; - int rc; + int rc = 0; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); tcon = tlink_tcon(tlink); + server = tcon->ses->server; /* - * 1. Fetch file metadata + * 1. Fetch file metadata if not provided (data) */ - - rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, - full_path, &data, - &owner, &group); + if (!data) { + rc = server->ops->query_path_info(xid, tcon, cifs_sb, + full_path, &tmp_data); + data = &tmp_data; + } /* * 2. Convert it to internal cifs metadata (fattr) @@ -1325,7 +1341,12 @@ static int smb311_posix_get_fattr(struct cifs_fattr *fattr, switch (rc) { case 0: - smb311_posix_info_to_fattr(fattr, &data, &owner, &group, sb); + if (cifs_open_data_reparse(data)) { + rc = reparse_info_to_fattr(data, sb, xid, tcon, + full_path, fattr); + } else { + smb311_posix_info_to_fattr(fattr, data, sb); + } break; case -EREMOTE: /* DFS link, no metadata available on this server */ @@ -1356,12 +1377,15 @@ static int smb311_posix_get_fattr(struct cifs_fattr *fattr, out: cifs_put_tlink(tlink); - cifs_free_open_info(&data); + cifs_free_open_info(data); return rc; } -int smb311_posix_get_inode_info(struct inode **inode, const char *full_path, - struct super_block *sb, const unsigned int xid) +int smb311_posix_get_inode_info(struct inode **inode, + const char *full_path, + struct cifs_open_info_data *data, + struct super_block *sb, + const unsigned int xid) { struct cifs_fattr fattr = {}; int rc; @@ -1371,7 +1395,7 @@ int smb311_posix_get_inode_info(struct inode **inode, const char *full_path, return 0; } - rc = smb311_posix_get_fattr(&fattr, full_path, sb, xid); + rc = smb311_posix_get_fattr(data, &fattr, full_path, sb, xid); if (rc) goto out; @@ -1390,6 +1414,8 @@ cifs_find_inode(struct inode *inode, void *opaque) { struct cifs_fattr *fattr = opaque; + /* [!] The compared values must be the same in struct cifs_fscache_inode_key. */ + /* don't match inode with different uniqueid */ if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) return 0; @@ -1519,7 +1545,7 @@ struct inode *cifs_root_iget(struct super_block *sb) convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); if (tcon->posix_extensions) - rc = smb311_posix_get_fattr(&fattr, path, sb, xid); + rc = smb311_posix_get_fattr(NULL, &fattr, path, sb, xid); else rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path); @@ -1892,16 +1918,18 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, int rc = 0; struct inode *inode = NULL; - if (tcon->posix_extensions) - rc = smb311_posix_get_inode_info(&inode, full_path, parent->i_sb, xid); + if (tcon->posix_extensions) { + rc = smb311_posix_get_inode_info(&inode, full_path, + NULL, parent->i_sb, xid); #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - else if (tcon->unix_ext) + } else if (tcon->unix_ext) { rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb, xid); #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ - else + } else { rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb, xid, NULL); + } if (rc) return rc; @@ -2583,13 +2611,15 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) dentry, cifs_get_time(dentry), jiffies); again: - if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) - rc = smb311_posix_get_inode_info(&inode, full_path, sb, xid); - else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) + if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) { + rc = smb311_posix_get_inode_info(&inode, full_path, + NULL, sb, xid); + } else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) { rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); - else + } else { rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, NULL); + } if (rc == -EAGAIN && count++ < 10) goto again; out: @@ -2831,7 +2861,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, set_size_out: if (rc == 0) { - cifsInode->server_eof = attrs->ia_size; + netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true); cifs_setsize(inode, attrs->ia_size); /* * i_blocks is not related to (i_size / i_blksize), but instead @@ -2984,6 +3014,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) if ((attrs->ia_valid & ATTR_SIZE) && attrs->ia_size != i_size_read(inode)) { truncate_setsize(inode, attrs->ia_size); + netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true); fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); } @@ -3183,6 +3214,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) if ((attrs->ia_valid & ATTR_SIZE) && attrs->ia_size != i_size_read(inode)) { truncate_setsize(inode, attrs->ia_size); + netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true); fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); } |