diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 344 |
1 files changed, 243 insertions, 101 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 53cce8cc2224..8852470b4fbb 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -32,7 +32,7 @@ #include "fscache.h" -static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) +static void cifs_set_ops(struct inode *inode) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -44,15 +44,19 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) inode->i_fop = &cifs_file_direct_nobrl_ops; else inode->i_fop = &cifs_file_direct_ops; + } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = &cifs_file_strict_nobrl_ops; + else + inode->i_fop = &cifs_file_strict_ops; } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) inode->i_fop = &cifs_file_nobrl_ops; else { /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; } - /* check if server can support readpages */ - if (cifs_sb->tcon->ses->server->maxBuf < + if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf < PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops = &cifs_addr_ops_smallbuf; else @@ -60,7 +64,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) break; case S_IFDIR: #ifdef CONFIG_CIFS_DFS_UPCALL - if (is_dfs_referral) { + if (IS_AUTOMOUNT(inode)) { inode->i_op = &cifs_dfs_referral_inode_operations; } else { #else /* NO DFS support, treat as a directory */ @@ -167,7 +171,9 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) } spin_unlock(&inode->i_lock); - cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL); + if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL) + inode->i_flags |= S_AUTOMOUNT; + cifs_set_ops(inode); } void @@ -288,8 +294,8 @@ int cifs_get_file_info_unix(struct file *filp) struct cifs_fattr fattr; struct inode *inode = filp->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; struct cifsFileInfo *cfile = filp->private_data; + struct cifsTconInfo *tcon = tlink_tcon(cfile->tlink); xid = GetXid(); rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); @@ -313,15 +319,21 @@ int cifs_get_inode_info_unix(struct inode **pinode, FILE_UNIX_BASIC_INFO find_data; struct cifs_fattr fattr; struct cifsTconInfo *tcon; + struct tcon_link *tlink; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - tcon = cifs_sb->tcon; cFYI(1, "Getting info on %s", full_path); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + /* 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_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); if (!rc) { cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); @@ -332,6 +344,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, return rc; } + /* check for Minshall+French symlinks */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { + int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); + if (tmprc) + cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); + } + if (*pinode == NULL) { /* get new inode */ cifs_fill_uniqueid(sb, &fattr); @@ -353,7 +372,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, int rc; int oplock = 0; __u16 netfid; - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct tcon_link *tlink; + struct cifsTconInfo *tcon; char buf[24]; unsigned int bytes_read; char *pbuf; @@ -372,7 +392,12 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, return -EINVAL; /* EOPNOTSUPP? */ } - rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + + rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -380,7 +405,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, if (rc == 0) { int buf_type = CIFS_NO_BUFFER; /* Read header */ - rc = CIFSSMBRead(xid, pTcon, netfid, + rc = CIFSSMBRead(xid, tcon, netfid, 24 /* length */, 0 /* offset */, &bytes_read, &pbuf, &buf_type); if ((rc == 0) && (bytes_read >= 8)) { @@ -422,8 +447,9 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, fattr->cf_dtype = DT_REG; rc = -EOPNOTSUPP; /* or some unknown SFU type */ } - CIFSSMBClose(xid, pTcon, netfid); + CIFSSMBClose(xid, tcon, netfid); } + cifs_put_tlink(tlink); return rc; } @@ -441,11 +467,19 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, ssize_t rc; char ea_value[4]; __u32 mode; + struct tcon_link *tlink; + struct cifsTconInfo *tcon; - rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS", + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + + rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS", ea_value, 4 /* size of buf */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); if (rc < 0) return (int)rc; else if (rc > 3) { @@ -468,6 +502,8 @@ static void cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, struct cifs_sb_info *cifs_sb, bool adjust_tz) { + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); + memset(fattr, 0, sizeof(*fattr)); fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); if (info->DeletePending) @@ -482,12 +518,13 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); if (adjust_tz) { - fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; - fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; + fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; + fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; } fattr->cf_eof = le64_to_cpu(info->EndOfFile); fattr->cf_bytes = le64_to_cpu(info->AllocationSize); + fattr->cf_createtime = le64_to_cpu(info->CreationTime); if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; @@ -515,8 +552,8 @@ int cifs_get_file_info(struct file *filp) struct cifs_fattr fattr; struct inode *inode = filp->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; struct cifsFileInfo *cfile = filp->private_data; + struct cifsTconInfo *tcon = tlink_tcon(cfile->tlink); xid = GetXid(); rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); @@ -554,26 +591,33 @@ int cifs_get_inode_info(struct inode **pinode, { int rc = 0, tmprc; struct cifsTconInfo *pTcon; + struct tcon_link *tlink; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); char *buf = NULL; bool adjustTZ = false; struct cifs_fattr fattr; - pTcon = cifs_sb->tcon; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + cFYI(1, "Getting info on %s", full_path); if ((pfindData == NULL) && (*pinode != NULL)) { if (CIFS_I(*pinode)->clientCanCacheRead) { cFYI(1, "No need to revalidate cached inode sizes"); - return rc; + goto cgii_exit; } } /* if file info not passed in then get it from server */ if (pfindData == NULL) { buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; + if (buf == NULL) { + rc = -ENOMEM; + goto cgii_exit; + } pfindData = (FILE_ALL_INFO *)buf; /* could do find first instead but this returns more info */ @@ -649,18 +693,30 @@ int cifs_get_inode_info(struct inode **pinode, cFYI(1, "cifs_sfu_type failed: %d", tmprc); } -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CONFIG_CIFS_ACL /* fill in 0777 bits from ACL */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { - cFYI(1, "Getting mode bits from ACL"); - cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid); + rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, + pfid); + if (rc) { + cFYI(1, "%s: Getting ACL failed with error: %d", + __func__, rc); + goto cgii_exit; + } } -#endif +#endif /* CONFIG_CIFS_ACL */ /* fill in remaining high mode bits e.g. SUID, VTX */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); + /* check for Minshall+French symlinks */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { + tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); + if (tmprc) + cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); + } + if (!*pinode) { *pinode = cifs_iget(sb, &fattr); if (!*pinode) @@ -671,6 +727,7 @@ int cifs_get_inode_info(struct inode **pinode, cgii_exit: kfree(buf); + cifs_put_tlink(tlink); return rc; } @@ -678,7 +735,8 @@ static const struct inode_operations cifs_ipc_inode_ops = { .lookup = cifs_lookup, }; -char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) +char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, + struct cifsTconInfo *tcon) { int pplen = cifs_sb->prepathlen; int dfsplen; @@ -692,8 +750,8 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) return full_path; } - if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) - dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); + if (tcon->Flags & SMB_SHARE_IS_IN_DFS) + dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); else dfsplen = 0; @@ -702,7 +760,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) return full_path; if (dfsplen) { - strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); + strncpy(full_path, tcon->treeName, dfsplen); /* switch slash direction in prepath depending on whether * windows or posix style path names */ @@ -728,6 +786,10 @@ cifs_find_inode(struct inode *inode, void *opaque) if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) return 0; + /* use createtime like an i_generation field */ + if (CIFS_I(inode)->createtime != fattr->cf_createtime) + return 0; + /* don't match inode of different type */ if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) return 0; @@ -745,6 +807,7 @@ cifs_init_inode(struct inode *inode, void *opaque) struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; + CIFS_I(inode)->createtime = fattr->cf_createtime; return 0; } @@ -758,14 +821,14 @@ inode_has_hashed_dentries(struct inode *inode) { struct dentry *dentry; - spin_lock(&dcache_lock); + spin_lock(&inode->i_lock); list_for_each_entry(dentry, &inode->i_dentry, d_alias) { if (!d_unhashed(dentry) || IS_ROOT(dentry)) { - spin_unlock(&dcache_lock); + spin_unlock(&inode->i_lock); return true; } } - spin_unlock(&dcache_lock); + spin_unlock(&inode->i_lock); return false; } @@ -818,32 +881,34 @@ retry_iget5_locked: struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) { int xid; - struct cifs_sb_info *cifs_sb; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct inode *inode = NULL; long rc; char *full_path; + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); - cifs_sb = CIFS_SB(sb); - full_path = cifs_build_path_to_root(cifs_sb); + full_path = cifs_build_path_to_root(cifs_sb, tcon); if (full_path == NULL) return ERR_PTR(-ENOMEM); xid = GetXid(); - if (cifs_sb->tcon->unix_ext) + if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, NULL); - if (!inode) - return ERR_PTR(rc); + if (!inode) { + inode = ERR_PTR(rc); + goto out; + } #ifdef CONFIG_CIFS_FSCACHE /* populate tcon->resource_id */ - cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid; + tcon->resource_id = CIFS_I(inode)->uniqueid; #endif - if (rc && cifs_sb->tcon->ipc) { + if (rc && tcon->ipc) { cFYI(1, "ipc connection - fake read inode"); inode->i_mode |= S_IFDIR; inode->i_nlink = 2; @@ -852,13 +917,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; } else if (rc) { - kfree(full_path); - _FreeXid(xid); iget_failed(inode); - return ERR_PTR(rc); + inode = ERR_PTR(rc); } - +out: kfree(full_path); /* can not call macro FreeXid here since in a void func * TODO: This is no longer true @@ -879,7 +942,8 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, struct cifsFileInfo *open_file; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct tcon_link *tlink = NULL; + struct cifsTconInfo *pTcon; FILE_BASIC_INFO info_buf; if (attrs == NULL) @@ -918,13 +982,22 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, /* * If the file is already open for write, just use that fileid */ - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { netfid = open_file->netfid; netpid = open_file->pid; + pTcon = tlink_tcon(open_file->tlink); goto set_via_filehandle; } + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + tlink = NULL; + goto out; + } + pTcon = tlink_tcon(tlink); + /* * NT4 apparently returns success on this call, but it doesn't * really work. @@ -968,6 +1041,8 @@ set_via_filehandle: else cifsFileInfo_put(open_file); out: + if (tlink != NULL) + cifs_put_tlink(tlink); return rc; } @@ -985,10 +1060,16 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid) struct inode *inode = dentry->d_inode; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; + struct tcon_link *tlink; + struct cifsTconInfo *tcon; __u32 dosattr, origattr; FILE_BASIC_INFO *info_buf = NULL; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, @@ -1057,6 +1138,7 @@ out_close: CIFSSMBClose(xid, tcon, netfid); out: kfree(info_buf); + cifs_put_tlink(tlink); return rc; /* @@ -1096,12 +1178,18 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) struct cifsInodeInfo *cifs_inode; struct super_block *sb = dir->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; + struct tcon_link *tlink; + struct cifsTconInfo *tcon; struct iattr *attrs = NULL; __u32 dosattr = 0, origattr = 0; cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + xid = GetXid(); /* Unlink can be called from rename so we can not take the @@ -1109,8 +1197,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) full_path = build_path_from_dentry(dentry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto unlink_out; } if ((tcon->ses->capabilities & CAP_UNIX) && @@ -1176,10 +1263,11 @@ out_reval: dir->i_ctime = dir->i_mtime = current_fs_time(sb); cifs_inode = CIFS_I(dir); CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ - +unlink_out: kfree(full_path); kfree(attrs); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } @@ -1188,6 +1276,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) int rc = 0, tmprc; int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; @@ -1195,16 +1284,18 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) cFYI(1, "In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode); - xid = GetXid(); - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + + xid = GetXid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto mkdir_out; } if ((pTcon->ses->capabilities & CAP_UNIX) && @@ -1239,10 +1330,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ inc_nlink(inode); - if (pTcon->nocase) - direntry->d_op = &cifs_ci_dentry_ops; - else - direntry->d_op = &cifs_dentry_ops; cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); cifs_fill_uniqueid(inode->i_sb, &fattr); @@ -1283,10 +1370,6 @@ mkdir_get_info: rc = cifs_get_inode_info(&newinode, full_path, NULL, inode->i_sb, xid, NULL); - if (pTcon->nocase) - direntry->d_op = &cifs_ci_dentry_ops; - else - direntry->d_op = &cifs_dentry_ops; d_instantiate(direntry, newinode); /* setting nlink not necessary except in cases where we * failed to get it from the server or was set bogus */ @@ -1362,6 +1445,7 @@ mkdir_get_info: mkdir_out: kfree(full_path); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } @@ -1370,6 +1454,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) int rc = 0; int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; char *full_path = NULL; struct cifsInodeInfo *cifsInode; @@ -1378,18 +1463,23 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) xid = GetXid(); - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; - full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto rmdir_exit; } + cifs_sb = CIFS_SB(inode->i_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + goto rmdir_exit; + } + pTcon = tlink_tcon(tlink); + rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); if (!rc) { drop_nlink(inode); @@ -1410,6 +1500,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); +rmdir_exit: kfree(full_path); FreeXid(xid); return rc; @@ -1420,10 +1511,16 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, struct dentry *to_dentry, const char *toPath) { struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct tcon_link *tlink; + struct cifsTconInfo *pTcon; __u16 srcfid; int oplock, rc; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + /* try path-based rename first */ rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -1435,11 +1532,11 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, * rename by filehandle to various Windows servers. */ if (rc == 0 || rc != -ETXTBSY) - return rc; + goto do_rename_exit; /* open-file renames don't work across directories */ if (to_dentry->d_parent != from_dentry->d_parent) - return rc; + goto do_rename_exit; /* open the file to be renamed -- we need DELETE perms */ rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, @@ -1455,7 +1552,8 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, CIFSSMBClose(xid, pTcon, srcfid); } - +do_rename_exit: + cifs_put_tlink(tlink); return rc; } @@ -1465,13 +1563,17 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, char *fromName = NULL; char *toName = NULL; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *tcon; FILE_UNIX_BASIC_INFO *info_buf_source = NULL; FILE_UNIX_BASIC_INFO *info_buf_target; int xid, rc, tmprc; cifs_sb = CIFS_SB(source_dir->i_sb); - tcon = cifs_sb->tcon; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); xid = GetXid(); @@ -1547,6 +1649,7 @@ cifs_rename_exit: kfree(fromName); kfree(toName); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } @@ -1554,6 +1657,7 @@ static bool cifs_inode_needs_reval(struct inode *inode) { struct cifsInodeInfo *cifs_i = CIFS_I(inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); if (cifs_i->clientCanCacheRead) return false; @@ -1564,20 +1668,22 @@ cifs_inode_needs_reval(struct inode *inode) if (cifs_i->time == 0) return true; - /* FIXME: the actimeo should be tunable */ - if (time_after_eq(jiffies, cifs_i->time + HZ)) + if (!time_in_range(jiffies, cifs_i->time, + cifs_i->time + cifs_sb->actimeo)) return true; /* hardlinked files w/ noserverino get "special" treatment */ - if (!(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && S_ISREG(inode->i_mode) && inode->i_nlink != 1) return true; return false; } -/* check invalid_mapping flag and zap the cache if it's set */ -static void +/* + * Zap the cache. Called when invalid_mapping flag is set. + */ +void cifs_invalidate_mapping(struct inode *inode) { int rc; @@ -1588,8 +1694,7 @@ cifs_invalidate_mapping(struct inode *inode) /* write back any cached data */ if (inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_write_and_wait(inode->i_mapping); - if (rc) - cifs_i->write_behind_rc = rc; + mapping_set_error(inode->i_mapping, rc); } invalidate_remote_inode(inode); cifs_fscache_reset_inode_cookie(inode); @@ -1599,11 +1704,12 @@ int cifs_revalidate_file(struct file *filp) { int rc = 0; struct inode *inode = filp->f_path.dentry->d_inode; + struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; if (!cifs_inode_needs_reval(inode)) goto check_inval; - if (CIFS_SB(inode->i_sb)->tcon->unix_ext) + if (tlink_tcon(cfile->tlink)->unix_ext) rc = cifs_get_file_info_unix(filp); else rc = cifs_get_file_info(filp); @@ -1644,7 +1750,7 @@ int cifs_revalidate_dentry(struct dentry *dentry) "jiffies %ld", full_path, inode, inode->i_count.counter, dentry, dentry->d_time, jiffies); - if (CIFS_SB(sb)->tcon->unix_ext) + if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, @@ -1660,13 +1766,29 @@ check_inval: } int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) + struct kstat *stat) { + struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); int err = cifs_revalidate_dentry(dentry); + if (!err) { generic_fillattr(dentry->d_inode, stat); stat->blksize = CIFS_MAX_MSGSIZE; stat->ino = CIFS_I(dentry->d_inode)->uniqueid; + + /* + * If on a multiuser mount without unix extensions, and the + * admin hasn't overridden them, set the ownership to the + * fsuid/fsgid of the current process. + */ + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && + !tcon->unix_ext) { + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) + stat->uid = current_fsuid(); + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) + stat->gid = current_fsgid(); + } } return err; } @@ -1708,7 +1830,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, struct cifsFileInfo *open_file; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct tcon_link *tlink = NULL; + struct cifsTconInfo *pTcon = NULL; /* * To avoid spurious oplock breaks from server, in the case of @@ -1719,10 +1842,11 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, * writebehind data than the SMB timeout for the SetPathInfo * request would allow */ - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { __u16 nfid = open_file->netfid; __u32 npid = open_file->pid; + pTcon = tlink_tcon(open_file->tlink); rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, npid, false); cifsFileInfo_put(open_file); @@ -1737,6 +1861,13 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, rc = -EINVAL; if (rc != 0) { + if (pTcon == NULL) { + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + } + /* Set file size by pathname rather than by handle either because no valid, writeable file handle for it was found or because there was an error setting @@ -1766,6 +1897,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, CIFSSMBClose(xid, pTcon, netfid); } } + if (tlink) + cifs_put_tlink(tlink); } if (rc == 0) { @@ -1786,7 +1919,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) struct inode *inode = direntry->d_inode; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct tcon_link *tlink; + struct cifsTconInfo *pTcon; struct cifs_unix_set_info_args *args = NULL; struct cifsFileInfo *open_file; @@ -1820,10 +1954,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) * the flush returns error? */ rc = filemap_write_and_wait(inode->i_mapping); - if (rc != 0) { - cifsInode->write_behind_rc = rc; - rc = 0; - } + mapping_set_error(inode->i_mapping, rc); + rc = 0; if (attrs->ia_valid & ATTR_SIZE) { rc = cifs_set_file_size(inode, attrs, xid, full_path); @@ -1873,17 +2005,25 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) args->ctime = NO_CHANGE_64; args->device = 0; - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { u16 nfid = open_file->netfid; u32 npid = open_file->pid; + pTcon = tlink_tcon(open_file->tlink); rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); cifsFileInfo_put(open_file); } else { + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + goto out; + } + pTcon = tlink_tcon(tlink); rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); } if (rc) @@ -1956,10 +2096,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) * the flush returns error? */ rc = filemap_write_and_wait(inode->i_mapping); - if (rc != 0) { - cifsInode->write_behind_rc = rc; - rc = 0; - } + mapping_set_error(inode->i_mapping, rc); + rc = 0; if (attrs->ia_valid & ATTR_SIZE) { rc = cifs_set_file_size(inode, attrs, xid, full_path); @@ -1988,11 +2126,16 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) if (attrs->ia_valid & ATTR_MODE) { rc = 0; -#ifdef CONFIG_CIFS_EXPERIMENTAL - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) - rc = mode_to_acl(inode, full_path, mode); - else -#endif +#ifdef CONFIG_CIFS_ACL + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { + rc = mode_to_cifs_acl(inode, full_path, mode); + if (rc) { + cFYI(1, "%s: Setting ACL failed with error: %d", + __func__, rc); + goto cifs_setattr_exit; + } + } else +#endif /* CONFIG_CIFS_ACL */ if (((mode & S_IWUGO) == 0) && (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { @@ -2051,7 +2194,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) setattr_copy(inode, attrs); mark_inode_dirty(inode); - return 0; cifs_setattr_exit: kfree(full_path); @@ -2064,7 +2206,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) { struct inode *inode = direntry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon = cifs_sb_master_tcon(cifs_sb); if (pTcon->unix_ext) return cifs_setattr_unix(direntry, attrs); |