diff options
Diffstat (limited to 'fs/cifs')
| -rw-r--r-- | fs/cifs/cifsfs.c | 11 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 7 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 30 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 18 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 448 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 5 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 7 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 26 |
8 files changed, 324 insertions, 228 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8b6e344eb0ba..a7610cfedf0a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -257,7 +257,6 @@ cifs_alloc_inode(struct super_block *sb) | |||
| 257 | static void cifs_i_callback(struct rcu_head *head) | 257 | static void cifs_i_callback(struct rcu_head *head) |
| 258 | { | 258 | { |
| 259 | struct inode *inode = container_of(head, struct inode, i_rcu); | 259 | struct inode *inode = container_of(head, struct inode, i_rcu); |
| 260 | INIT_LIST_HEAD(&inode->i_dentry); | ||
| 261 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | 260 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); |
| 262 | } | 261 | } |
| 263 | 262 | ||
| @@ -638,7 +637,10 @@ cifs_do_mount(struct file_system_type *fs_type, | |||
| 638 | mnt_data.cifs_sb = cifs_sb; | 637 | mnt_data.cifs_sb = cifs_sb; |
| 639 | mnt_data.flags = flags; | 638 | mnt_data.flags = flags; |
| 640 | 639 | ||
| 641 | sb = sget(fs_type, cifs_match_super, cifs_set_super, &mnt_data); | 640 | /* BB should we make this contingent on mount parm? */ |
| 641 | flags |= MS_NODIRATIME | MS_NOATIME; | ||
| 642 | |||
| 643 | sb = sget(fs_type, cifs_match_super, cifs_set_super, flags, &mnt_data); | ||
| 642 | if (IS_ERR(sb)) { | 644 | if (IS_ERR(sb)) { |
| 643 | root = ERR_CAST(sb); | 645 | root = ERR_CAST(sb); |
| 644 | cifs_umount(cifs_sb); | 646 | cifs_umount(cifs_sb); |
| @@ -649,10 +651,6 @@ cifs_do_mount(struct file_system_type *fs_type, | |||
| 649 | cFYI(1, "Use existing superblock"); | 651 | cFYI(1, "Use existing superblock"); |
| 650 | cifs_umount(cifs_sb); | 652 | cifs_umount(cifs_sb); |
| 651 | } else { | 653 | } else { |
| 652 | sb->s_flags = flags; | ||
| 653 | /* BB should we make this contingent on mount parm? */ | ||
| 654 | sb->s_flags |= MS_NODIRATIME | MS_NOATIME; | ||
| 655 | |||
| 656 | rc = cifs_read_super(sb); | 654 | rc = cifs_read_super(sb); |
| 657 | if (rc) { | 655 | if (rc) { |
| 658 | root = ERR_PTR(rc); | 656 | root = ERR_PTR(rc); |
| @@ -778,6 +776,7 @@ struct file_system_type cifs_fs_type = { | |||
| 778 | }; | 776 | }; |
| 779 | const struct inode_operations cifs_dir_inode_ops = { | 777 | const struct inode_operations cifs_dir_inode_ops = { |
| 780 | .create = cifs_create, | 778 | .create = cifs_create, |
| 779 | .atomic_open = cifs_atomic_open, | ||
| 781 | .lookup = cifs_lookup, | 780 | .lookup = cifs_lookup, |
| 782 | .getattr = cifs_getattr, | 781 | .getattr = cifs_getattr, |
| 783 | .unlink = cifs_unlink, | 782 | .unlink = cifs_unlink, |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 65365358c976..1c49c5a9b27a 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -45,9 +45,12 @@ extern const struct address_space_operations cifs_addr_ops_smallbuf; | |||
| 45 | extern const struct inode_operations cifs_dir_inode_ops; | 45 | extern const struct inode_operations cifs_dir_inode_ops; |
| 46 | extern struct inode *cifs_root_iget(struct super_block *); | 46 | extern struct inode *cifs_root_iget(struct super_block *); |
| 47 | extern int cifs_create(struct inode *, struct dentry *, umode_t, | 47 | extern int cifs_create(struct inode *, struct dentry *, umode_t, |
| 48 | struct nameidata *); | 48 | bool excl); |
| 49 | extern int cifs_atomic_open(struct inode *, struct dentry *, | ||
| 50 | struct file *, unsigned, umode_t, | ||
| 51 | int *); | ||
| 49 | extern struct dentry *cifs_lookup(struct inode *, struct dentry *, | 52 | extern struct dentry *cifs_lookup(struct inode *, struct dentry *, |
| 50 | struct nameidata *); | 53 | unsigned int); |
| 51 | extern int cifs_unlink(struct inode *dir, struct dentry *dentry); | 54 | extern int cifs_unlink(struct inode *dir, struct dentry *dentry); |
| 52 | extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); | 55 | extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); |
| 53 | extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t); | 56 | extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5b400730c213..4ee522b3f66f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -86,7 +86,31 @@ static struct { | |||
| 86 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ | 86 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ |
| 87 | #endif /* CIFS_POSIX */ | 87 | #endif /* CIFS_POSIX */ |
| 88 | 88 | ||
| 89 | /* Forward declarations */ | 89 | #ifdef CONFIG_HIGHMEM |
| 90 | /* | ||
| 91 | * On arches that have high memory, kmap address space is limited. By | ||
| 92 | * serializing the kmap operations on those arches, we ensure that we don't | ||
| 93 | * end up with a bunch of threads in writeback with partially mapped page | ||
| 94 | * arrays, stuck waiting for kmap to come back. That situation prevents | ||
| 95 | * progress and can deadlock. | ||
| 96 | */ | ||
| 97 | static DEFINE_MUTEX(cifs_kmap_mutex); | ||
| 98 | |||
| 99 | static inline void | ||
| 100 | cifs_kmap_lock(void) | ||
| 101 | { | ||
| 102 | mutex_lock(&cifs_kmap_mutex); | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline void | ||
| 106 | cifs_kmap_unlock(void) | ||
| 107 | { | ||
| 108 | mutex_unlock(&cifs_kmap_mutex); | ||
| 109 | } | ||
| 110 | #else /* !CONFIG_HIGHMEM */ | ||
| 111 | #define cifs_kmap_lock() do { ; } while(0) | ||
| 112 | #define cifs_kmap_unlock() do { ; } while(0) | ||
| 113 | #endif /* CONFIG_HIGHMEM */ | ||
| 90 | 114 | ||
| 91 | /* Mark as invalid, all open files on tree connections since they | 115 | /* Mark as invalid, all open files on tree connections since they |
| 92 | were closed when session to server was lost */ | 116 | were closed when session to server was lost */ |
| @@ -1503,7 +1527,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
| 1503 | } | 1527 | } |
| 1504 | 1528 | ||
| 1505 | /* marshal up the page array */ | 1529 | /* marshal up the page array */ |
| 1530 | cifs_kmap_lock(); | ||
| 1506 | len = rdata->marshal_iov(rdata, data_len); | 1531 | len = rdata->marshal_iov(rdata, data_len); |
| 1532 | cifs_kmap_unlock(); | ||
| 1507 | data_len -= len; | 1533 | data_len -= len; |
| 1508 | 1534 | ||
| 1509 | /* issue the read if we have any iovecs left to fill */ | 1535 | /* issue the read if we have any iovecs left to fill */ |
| @@ -2069,7 +2095,9 @@ cifs_async_writev(struct cifs_writedata *wdata) | |||
| 2069 | * and set the iov_len properly for each one. It may also set | 2095 | * and set the iov_len properly for each one. It may also set |
| 2070 | * wdata->bytes too. | 2096 | * wdata->bytes too. |
| 2071 | */ | 2097 | */ |
| 2098 | cifs_kmap_lock(); | ||
| 2072 | wdata->marshal_iov(iov, wdata); | 2099 | wdata->marshal_iov(iov, wdata); |
| 2100 | cifs_kmap_unlock(); | ||
| 2073 | 2101 | ||
| 2074 | cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes); | 2102 | cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes); |
| 2075 | 2103 | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0ae86ddf2213..94b7788c3189 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -3445,6 +3445,18 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
| 3445 | #define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024) | 3445 | #define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024) |
| 3446 | #define CIFS_DEFAULT_NON_POSIX_WSIZE (65536) | 3446 | #define CIFS_DEFAULT_NON_POSIX_WSIZE (65536) |
| 3447 | 3447 | ||
| 3448 | /* | ||
| 3449 | * On hosts with high memory, we can't currently support wsize/rsize that are | ||
| 3450 | * larger than we can kmap at once. Cap the rsize/wsize at | ||
| 3451 | * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request | ||
| 3452 | * larger than that anyway. | ||
| 3453 | */ | ||
| 3454 | #ifdef CONFIG_HIGHMEM | ||
| 3455 | #define CIFS_KMAP_SIZE_LIMIT (LAST_PKMAP * PAGE_CACHE_SIZE) | ||
| 3456 | #else /* CONFIG_HIGHMEM */ | ||
| 3457 | #define CIFS_KMAP_SIZE_LIMIT (1<<24) | ||
| 3458 | #endif /* CONFIG_HIGHMEM */ | ||
| 3459 | |||
| 3448 | static unsigned int | 3460 | static unsigned int |
| 3449 | cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | 3461 | cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) |
| 3450 | { | 3462 | { |
| @@ -3475,6 +3487,9 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | |||
| 3475 | wsize = min_t(unsigned int, wsize, | 3487 | wsize = min_t(unsigned int, wsize, |
| 3476 | server->maxBuf - sizeof(WRITE_REQ) + 4); | 3488 | server->maxBuf - sizeof(WRITE_REQ) + 4); |
| 3477 | 3489 | ||
| 3490 | /* limit to the amount that we can kmap at once */ | ||
| 3491 | wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT); | ||
| 3492 | |||
| 3478 | /* hard limit of CIFS_MAX_WSIZE */ | 3493 | /* hard limit of CIFS_MAX_WSIZE */ |
| 3479 | wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); | 3494 | wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); |
| 3480 | 3495 | ||
| @@ -3516,6 +3531,9 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | |||
| 3516 | if (!(server->capabilities & CAP_LARGE_READ_X)) | 3531 | if (!(server->capabilities & CAP_LARGE_READ_X)) |
| 3517 | rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); | 3532 | rsize = min_t(unsigned int, CIFSMaxBufSize, rsize); |
| 3518 | 3533 | ||
| 3534 | /* limit to the amount that we can kmap at once */ | ||
| 3535 | rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT); | ||
| 3536 | |||
| 3519 | /* hard limit of CIFS_MAX_RSIZE */ | 3537 | /* hard limit of CIFS_MAX_RSIZE */ |
| 3520 | rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); | 3538 | rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE); |
| 3521 | 3539 | ||
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index ec4e9a2a12f8..a180265a10b5 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -133,108 +133,141 @@ cifs_bp_rename_retry: | |||
| 133 | return full_path; | 133 | return full_path; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | /* | ||
| 137 | * Don't allow the separator character in a path component. | ||
| 138 | * The VFS will not allow "/", but "\" is allowed by posix. | ||
| 139 | */ | ||
| 140 | static int | ||
| 141 | check_name(struct dentry *direntry) | ||
| 142 | { | ||
| 143 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); | ||
| 144 | int i; | ||
| 145 | |||
| 146 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { | ||
| 147 | for (i = 0; i < direntry->d_name.len; i++) { | ||
| 148 | if (direntry->d_name.name[i] == '\\') { | ||
| 149 | cFYI(1, "Invalid file name"); | ||
| 150 | return -EINVAL; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | } | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 136 | /* Inode operations in similar order to how they appear in Linux file fs.h */ | 158 | /* Inode operations in similar order to how they appear in Linux file fs.h */ |
| 137 | 159 | ||
| 138 | int | 160 | static int cifs_do_create(struct inode *inode, struct dentry *direntry, |
| 139 | cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | 161 | int xid, struct tcon_link *tlink, unsigned oflags, |
| 140 | struct nameidata *nd) | 162 | umode_t mode, __u32 *oplock, __u16 *fileHandle, |
| 163 | int *created) | ||
| 141 | { | 164 | { |
| 142 | int rc = -ENOENT; | 165 | int rc = -ENOENT; |
| 143 | int xid; | ||
| 144 | int create_options = CREATE_NOT_DIR; | 166 | int create_options = CREATE_NOT_DIR; |
| 145 | __u32 oplock = 0; | 167 | int desiredAccess; |
| 146 | int oflags; | 168 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 147 | /* | 169 | struct cifs_tcon *tcon = tlink_tcon(tlink); |
| 148 | * BB below access is probably too much for mknod to request | ||
| 149 | * but we have to do query and setpathinfo so requesting | ||
| 150 | * less could fail (unless we want to request getatr and setatr | ||
| 151 | * permissions (only). At least for POSIX we do not have to | ||
| 152 | * request so much. | ||
| 153 | */ | ||
| 154 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; | ||
| 155 | __u16 fileHandle; | ||
| 156 | struct cifs_sb_info *cifs_sb; | ||
| 157 | struct tcon_link *tlink; | ||
| 158 | struct cifs_tcon *tcon; | ||
| 159 | char *full_path = NULL; | 170 | char *full_path = NULL; |
| 160 | FILE_ALL_INFO *buf = NULL; | 171 | FILE_ALL_INFO *buf = NULL; |
| 161 | struct inode *newinode = NULL; | 172 | struct inode *newinode = NULL; |
| 162 | int disposition = FILE_OVERWRITE_IF; | 173 | int disposition; |
| 163 | |||
| 164 | xid = GetXid(); | ||
| 165 | |||
| 166 | cifs_sb = CIFS_SB(inode->i_sb); | ||
| 167 | tlink = cifs_sb_tlink(cifs_sb); | ||
| 168 | if (IS_ERR(tlink)) { | ||
| 169 | FreeXid(xid); | ||
| 170 | return PTR_ERR(tlink); | ||
| 171 | } | ||
| 172 | tcon = tlink_tcon(tlink); | ||
| 173 | 174 | ||
| 175 | *oplock = 0; | ||
| 174 | if (tcon->ses->server->oplocks) | 176 | if (tcon->ses->server->oplocks) |
| 175 | oplock = REQ_OPLOCK; | 177 | *oplock = REQ_OPLOCK; |
| 176 | |||
| 177 | if (nd) | ||
| 178 | oflags = nd->intent.open.file->f_flags; | ||
| 179 | else | ||
| 180 | oflags = O_RDONLY | O_CREAT; | ||
| 181 | 178 | ||
| 182 | full_path = build_path_from_dentry(direntry); | 179 | full_path = build_path_from_dentry(direntry); |
| 183 | if (full_path == NULL) { | 180 | if (full_path == NULL) { |
| 184 | rc = -ENOMEM; | 181 | rc = -ENOMEM; |
| 185 | goto cifs_create_out; | 182 | goto out; |
| 186 | } | 183 | } |
| 187 | 184 | ||
| 188 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 185 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
| 186 | !tcon->broken_posix_open && | ||
| 189 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 187 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
| 190 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 188 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
| 191 | rc = cifs_posix_open(full_path, &newinode, | 189 | rc = cifs_posix_open(full_path, &newinode, |
| 192 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); | 190 | inode->i_sb, mode, oflags, oplock, fileHandle, xid); |
| 193 | /* EIO could indicate that (posix open) operation is not | 191 | switch (rc) { |
| 194 | supported, despite what server claimed in capability | 192 | case 0: |
| 195 | negotiation. EREMOTE indicates DFS junction, which is not | 193 | if (newinode == NULL) { |
| 196 | handled in posix open */ | 194 | /* query inode info */ |
| 197 | |||
| 198 | if (rc == 0) { | ||
| 199 | if (newinode == NULL) /* query inode info */ | ||
| 200 | goto cifs_create_get_file_info; | 195 | goto cifs_create_get_file_info; |
| 201 | else /* success, no need to query */ | 196 | } |
| 202 | goto cifs_create_set_dentry; | 197 | |
| 203 | } else if ((rc != -EIO) && (rc != -EREMOTE) && | 198 | if (!S_ISREG(newinode->i_mode)) { |
| 204 | (rc != -EOPNOTSUPP) && (rc != -EINVAL)) | 199 | /* |
| 205 | goto cifs_create_out; | 200 | * The server may allow us to open things like |
| 206 | /* else fallthrough to retry, using older open call, this is | 201 | * FIFOs, but the client isn't set up to deal |
| 207 | case where server does not support this SMB level, and | 202 | * with that. If it's not a regular file, just |
| 208 | falsely claims capability (also get here for DFS case | 203 | * close it and proceed as if it were a normal |
| 209 | which should be rare for path not covered on files) */ | 204 | * lookup. |
| 210 | } | 205 | */ |
| 206 | CIFSSMBClose(xid, tcon, *fileHandle); | ||
| 207 | goto cifs_create_get_file_info; | ||
| 208 | } | ||
| 209 | /* success, no need to query */ | ||
| 210 | goto cifs_create_set_dentry; | ||
| 211 | |||
| 212 | case -ENOENT: | ||
| 213 | goto cifs_create_get_file_info; | ||
| 214 | |||
| 215 | case -EIO: | ||
| 216 | case -EINVAL: | ||
| 217 | /* | ||
| 218 | * EIO could indicate that (posix open) operation is not | ||
| 219 | * supported, despite what server claimed in capability | ||
| 220 | * negotiation. | ||
| 221 | * | ||
| 222 | * POSIX open in samba versions 3.3.1 and earlier could | ||
| 223 | * incorrectly fail with invalid parameter. | ||
| 224 | */ | ||
| 225 | tcon->broken_posix_open = true; | ||
| 226 | break; | ||
| 227 | |||
| 228 | case -EREMOTE: | ||
| 229 | case -EOPNOTSUPP: | ||
| 230 | /* | ||
| 231 | * EREMOTE indicates DFS junction, which is not handled | ||
| 232 | * in posix open. If either that or op not supported | ||
| 233 | * returned, follow the normal lookup. | ||
| 234 | */ | ||
| 235 | break; | ||
| 211 | 236 | ||
| 212 | if (nd) { | 237 | default: |
| 213 | /* if the file is going to stay open, then we | 238 | goto out; |
| 214 | need to set the desired access properly */ | 239 | } |
| 215 | desiredAccess = 0; | 240 | /* |
| 216 | if (OPEN_FMODE(oflags) & FMODE_READ) | 241 | * fallthrough to retry, using older open call, this is case |
| 217 | desiredAccess |= GENERIC_READ; /* is this too little? */ | 242 | * where server does not support this SMB level, and falsely |
| 218 | if (OPEN_FMODE(oflags) & FMODE_WRITE) | 243 | * claims capability (also get here for DFS case which should be |
| 219 | desiredAccess |= GENERIC_WRITE; | 244 | * rare for path not covered on files) |
| 220 | 245 | */ | |
| 221 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
| 222 | disposition = FILE_CREATE; | ||
| 223 | else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | ||
| 224 | disposition = FILE_OVERWRITE_IF; | ||
| 225 | else if ((oflags & O_CREAT) == O_CREAT) | ||
| 226 | disposition = FILE_OPEN_IF; | ||
| 227 | else | ||
| 228 | cFYI(1, "Create flag not set in create function"); | ||
| 229 | } | 246 | } |
| 230 | 247 | ||
| 248 | desiredAccess = 0; | ||
| 249 | if (OPEN_FMODE(oflags) & FMODE_READ) | ||
| 250 | desiredAccess |= GENERIC_READ; /* is this too little? */ | ||
| 251 | if (OPEN_FMODE(oflags) & FMODE_WRITE) | ||
| 252 | desiredAccess |= GENERIC_WRITE; | ||
| 253 | |||
| 254 | disposition = FILE_OVERWRITE_IF; | ||
| 255 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
| 256 | disposition = FILE_CREATE; | ||
| 257 | else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | ||
| 258 | disposition = FILE_OVERWRITE_IF; | ||
| 259 | else if ((oflags & O_CREAT) == O_CREAT) | ||
| 260 | disposition = FILE_OPEN_IF; | ||
| 261 | else | ||
| 262 | cFYI(1, "Create flag not set in create function"); | ||
| 263 | |||
| 231 | /* BB add processing to set equivalent of mode - e.g. via CreateX with | 264 | /* BB add processing to set equivalent of mode - e.g. via CreateX with |
| 232 | ACLs */ | 265 | ACLs */ |
| 233 | 266 | ||
| 234 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 267 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
| 235 | if (buf == NULL) { | 268 | if (buf == NULL) { |
| 236 | rc = -ENOMEM; | 269 | rc = -ENOMEM; |
| 237 | goto cifs_create_out; | 270 | goto out; |
| 238 | } | 271 | } |
| 239 | 272 | ||
| 240 | /* | 273 | /* |
| @@ -250,7 +283,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
| 250 | if (tcon->ses->capabilities & CAP_NT_SMBS) | 283 | if (tcon->ses->capabilities & CAP_NT_SMBS) |
| 251 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | 284 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, |
| 252 | desiredAccess, create_options, | 285 | desiredAccess, create_options, |
| 253 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 286 | fileHandle, oplock, buf, cifs_sb->local_nls, |
| 254 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 287 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 255 | else | 288 | else |
| 256 | rc = -EIO; /* no NT SMB support fall into legacy open below */ | 289 | rc = -EIO; /* no NT SMB support fall into legacy open below */ |
| @@ -259,17 +292,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
| 259 | /* old server, retry the open legacy style */ | 292 | /* old server, retry the open legacy style */ |
| 260 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | 293 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, |
| 261 | desiredAccess, create_options, | 294 | desiredAccess, create_options, |
| 262 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 295 | fileHandle, oplock, buf, cifs_sb->local_nls, |
| 263 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 296 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 264 | } | 297 | } |
| 265 | if (rc) { | 298 | if (rc) { |
| 266 | cFYI(1, "cifs_create returned 0x%x", rc); | 299 | cFYI(1, "cifs_create returned 0x%x", rc); |
| 267 | goto cifs_create_out; | 300 | goto out; |
| 268 | } | 301 | } |
| 269 | 302 | ||
| 270 | /* If Open reported that we actually created a file | 303 | /* If Open reported that we actually created a file |
| 271 | then we now have to set the mode if possible */ | 304 | then we now have to set the mode if possible */ |
| 272 | if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { | 305 | if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) { |
| 273 | struct cifs_unix_set_info_args args = { | 306 | struct cifs_unix_set_info_args args = { |
| 274 | .mode = mode, | 307 | .mode = mode, |
| 275 | .ctime = NO_CHANGE_64, | 308 | .ctime = NO_CHANGE_64, |
| @@ -278,6 +311,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
| 278 | .device = 0, | 311 | .device = 0, |
| 279 | }; | 312 | }; |
| 280 | 313 | ||
| 314 | *created |= FILE_CREATED; | ||
| 281 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 315 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
| 282 | args.uid = (__u64) current_fsuid(); | 316 | args.uid = (__u64) current_fsuid(); |
| 283 | if (inode->i_mode & S_ISGID) | 317 | if (inode->i_mode & S_ISGID) |
| @@ -288,7 +322,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
| 288 | args.uid = NO_CHANGE_64; | 322 | args.uid = NO_CHANGE_64; |
| 289 | args.gid = NO_CHANGE_64; | 323 | args.gid = NO_CHANGE_64; |
| 290 | } | 324 | } |
| 291 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle, | 325 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle, |
| 292 | current->tgid); | 326 | current->tgid); |
| 293 | } else { | 327 | } else { |
| 294 | /* BB implement mode setting via Windows security | 328 | /* BB implement mode setting via Windows security |
| @@ -305,11 +339,11 @@ cifs_create_get_file_info: | |||
| 305 | inode->i_sb, xid); | 339 | inode->i_sb, xid); |
| 306 | else { | 340 | else { |
| 307 | rc = cifs_get_inode_info(&newinode, full_path, buf, | 341 | rc = cifs_get_inode_info(&newinode, full_path, buf, |
| 308 | inode->i_sb, xid, &fileHandle); | 342 | inode->i_sb, xid, fileHandle); |
| 309 | if (newinode) { | 343 | if (newinode) { |
| 310 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) | 344 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) |
| 311 | newinode->i_mode = mode; | 345 | newinode->i_mode = mode; |
| 312 | if ((oplock & CIFS_CREATE_ACTION) && | 346 | if ((*oplock & CIFS_CREATE_ACTION) && |
| 313 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { | 347 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { |
| 314 | newinode->i_uid = current_fsuid(); | 348 | newinode->i_uid = current_fsuid(); |
| 315 | if (inode->i_mode & S_ISGID) | 349 | if (inode->i_mode & S_ISGID) |
| @@ -321,40 +355,139 @@ cifs_create_get_file_info: | |||
| 321 | } | 355 | } |
| 322 | 356 | ||
| 323 | cifs_create_set_dentry: | 357 | cifs_create_set_dentry: |
| 324 | if (rc == 0) | 358 | if (rc != 0) { |
| 325 | d_instantiate(direntry, newinode); | ||
| 326 | else | ||
| 327 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); | 359 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); |
| 360 | goto out; | ||
| 361 | } | ||
| 362 | d_drop(direntry); | ||
| 363 | d_add(direntry, newinode); | ||
| 328 | 364 | ||
| 329 | if (newinode && nd) { | 365 | /* ENOENT for create? How weird... */ |
| 330 | struct cifsFileInfo *pfile_info; | 366 | rc = -ENOENT; |
| 331 | struct file *filp; | 367 | if (!newinode) { |
| 368 | CIFSSMBClose(xid, tcon, *fileHandle); | ||
| 369 | goto out; | ||
| 370 | } | ||
| 371 | rc = 0; | ||
| 332 | 372 | ||
| 333 | filp = lookup_instantiate_filp(nd, direntry, generic_file_open); | 373 | out: |
| 334 | if (IS_ERR(filp)) { | 374 | kfree(buf); |
| 335 | rc = PTR_ERR(filp); | 375 | kfree(full_path); |
| 336 | CIFSSMBClose(xid, tcon, fileHandle); | 376 | return rc; |
| 337 | goto cifs_create_out; | 377 | } |
| 338 | } | ||
| 339 | 378 | ||
| 340 | pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); | 379 | int |
| 341 | if (pfile_info == NULL) { | 380 | cifs_atomic_open(struct inode *inode, struct dentry *direntry, |
| 342 | fput(filp); | 381 | struct file *file, unsigned oflags, umode_t mode, |
| 343 | CIFSSMBClose(xid, tcon, fileHandle); | 382 | int *opened) |
| 344 | rc = -ENOMEM; | 383 | { |
| 345 | } | 384 | int rc; |
| 346 | } else { | 385 | int xid; |
| 386 | struct tcon_link *tlink; | ||
| 387 | struct cifs_tcon *tcon; | ||
| 388 | __u16 fileHandle; | ||
| 389 | __u32 oplock; | ||
| 390 | struct file *filp; | ||
| 391 | struct cifsFileInfo *pfile_info; | ||
| 392 | |||
| 393 | /* Posix open is only called (at lookup time) for file create now. For | ||
| 394 | * opens (rather than creates), because we do not know if it is a file | ||
| 395 | * or directory yet, and current Samba no longer allows us to do posix | ||
| 396 | * open on dirs, we could end up wasting an open call on what turns out | ||
| 397 | * to be a dir. For file opens, we wait to call posix open till | ||
| 398 | * cifs_open. It could be added to atomic_open in the future but the | ||
| 399 | * performance tradeoff of the extra network request when EISDIR or | ||
| 400 | * EACCES is returned would have to be weighed against the 50% reduction | ||
| 401 | * in network traffic in the other paths. | ||
| 402 | */ | ||
| 403 | if (!(oflags & O_CREAT)) { | ||
| 404 | struct dentry *res = cifs_lookup(inode, direntry, 0); | ||
| 405 | if (IS_ERR(res)) | ||
| 406 | return PTR_ERR(res); | ||
| 407 | |||
| 408 | return finish_no_open(file, res); | ||
| 409 | } | ||
| 410 | |||
| 411 | rc = check_name(direntry); | ||
| 412 | if (rc) | ||
| 413 | return rc; | ||
| 414 | |||
| 415 | xid = GetXid(); | ||
| 416 | |||
| 417 | cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p", | ||
| 418 | inode, direntry->d_name.name, direntry); | ||
| 419 | |||
| 420 | tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); | ||
| 421 | filp = ERR_CAST(tlink); | ||
| 422 | if (IS_ERR(tlink)) | ||
| 423 | goto free_xid; | ||
| 424 | |||
| 425 | tcon = tlink_tcon(tlink); | ||
| 426 | |||
| 427 | rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, | ||
| 428 | &oplock, &fileHandle, opened); | ||
| 429 | |||
| 430 | if (rc) | ||
| 431 | goto out; | ||
| 432 | |||
| 433 | rc = finish_open(file, direntry, generic_file_open, opened); | ||
| 434 | if (rc) { | ||
| 347 | CIFSSMBClose(xid, tcon, fileHandle); | 435 | CIFSSMBClose(xid, tcon, fileHandle); |
| 436 | goto out; | ||
| 348 | } | 437 | } |
| 349 | 438 | ||
| 350 | cifs_create_out: | 439 | pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); |
| 351 | kfree(buf); | 440 | if (pfile_info == NULL) { |
| 352 | kfree(full_path); | 441 | CIFSSMBClose(xid, tcon, fileHandle); |
| 442 | fput(filp); | ||
| 443 | rc = -ENOMEM; | ||
| 444 | } | ||
| 445 | |||
| 446 | out: | ||
| 353 | cifs_put_tlink(tlink); | 447 | cifs_put_tlink(tlink); |
| 448 | free_xid: | ||
| 354 | FreeXid(xid); | 449 | FreeXid(xid); |
| 355 | return rc; | 450 | return rc; |
| 356 | } | 451 | } |
| 357 | 452 | ||
| 453 | int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | ||
| 454 | bool excl) | ||
| 455 | { | ||
| 456 | int rc; | ||
| 457 | int xid = GetXid(); | ||
| 458 | /* | ||
| 459 | * BB below access is probably too much for mknod to request | ||
| 460 | * but we have to do query and setpathinfo so requesting | ||
| 461 | * less could fail (unless we want to request getatr and setatr | ||
| 462 | * permissions (only). At least for POSIX we do not have to | ||
| 463 | * request so much. | ||
| 464 | */ | ||
| 465 | unsigned oflags = O_EXCL | O_CREAT | O_RDWR; | ||
| 466 | struct tcon_link *tlink; | ||
| 467 | __u16 fileHandle; | ||
| 468 | __u32 oplock; | ||
| 469 | int created = FILE_CREATED; | ||
| 470 | |||
| 471 | cFYI(1, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p", | ||
| 472 | inode, direntry->d_name.name, direntry); | ||
| 473 | |||
| 474 | tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); | ||
| 475 | rc = PTR_ERR(tlink); | ||
| 476 | if (IS_ERR(tlink)) | ||
| 477 | goto free_xid; | ||
| 478 | |||
| 479 | rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, | ||
| 480 | &oplock, &fileHandle, &created); | ||
| 481 | if (!rc) | ||
| 482 | CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle); | ||
| 483 | |||
| 484 | cifs_put_tlink(tlink); | ||
| 485 | free_xid: | ||
| 486 | FreeXid(xid); | ||
| 487 | |||
| 488 | return rc; | ||
| 489 | } | ||
| 490 | |||
| 358 | int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, | 491 | int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, |
| 359 | dev_t device_number) | 492 | dev_t device_number) |
| 360 | { | 493 | { |
| @@ -488,20 +621,15 @@ mknod_out: | |||
| 488 | 621 | ||
| 489 | struct dentry * | 622 | struct dentry * |
| 490 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | 623 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, |
| 491 | struct nameidata *nd) | 624 | unsigned int flags) |
| 492 | { | 625 | { |
| 493 | int xid; | 626 | int xid; |
| 494 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ | 627 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ |
| 495 | __u32 oplock; | ||
| 496 | __u16 fileHandle = 0; | ||
| 497 | bool posix_open = false; | ||
| 498 | struct cifs_sb_info *cifs_sb; | 628 | struct cifs_sb_info *cifs_sb; |
| 499 | struct tcon_link *tlink; | 629 | struct tcon_link *tlink; |
| 500 | struct cifs_tcon *pTcon; | 630 | struct cifs_tcon *pTcon; |
| 501 | struct cifsFileInfo *cfile; | ||
| 502 | struct inode *newInode = NULL; | 631 | struct inode *newInode = NULL; |
| 503 | char *full_path = NULL; | 632 | char *full_path = NULL; |
| 504 | struct file *filp; | ||
| 505 | 633 | ||
| 506 | xid = GetXid(); | 634 | xid = GetXid(); |
| 507 | 635 | ||
| @@ -518,31 +646,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
| 518 | } | 646 | } |
| 519 | pTcon = tlink_tcon(tlink); | 647 | pTcon = tlink_tcon(tlink); |
| 520 | 648 | ||
| 521 | oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0; | 649 | rc = check_name(direntry); |
| 522 | 650 | if (rc) | |
| 523 | /* | ||
| 524 | * Don't allow the separator character in a path component. | ||
| 525 | * The VFS will not allow "/", but "\" is allowed by posix. | ||
| 526 | */ | ||
| 527 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { | ||
| 528 | int i; | ||
| 529 | for (i = 0; i < direntry->d_name.len; i++) | ||
| 530 | if (direntry->d_name.name[i] == '\\') { | ||
| 531 | cFYI(1, "Invalid file name"); | ||
| 532 | rc = -EINVAL; | ||
| 533 | goto lookup_out; | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 537 | /* | ||
| 538 | * O_EXCL: optimize away the lookup, but don't hash the dentry. Let | ||
| 539 | * the VFS handle the create. | ||
| 540 | */ | ||
| 541 | if (nd && (nd->flags & LOOKUP_EXCL)) { | ||
| 542 | d_instantiate(direntry, NULL); | ||
| 543 | rc = 0; | ||
| 544 | goto lookup_out; | 651 | goto lookup_out; |
| 545 | } | ||
| 546 | 652 | ||
| 547 | /* can not grab the rename sem here since it would | 653 | /* can not grab the rename sem here since it would |
| 548 | deadlock in the cases (beginning of sys_rename itself) | 654 | deadlock in the cases (beginning of sys_rename itself) |
| @@ -560,80 +666,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
| 560 | } | 666 | } |
| 561 | cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode); | 667 | cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode); |
| 562 | 668 | ||
| 563 | /* Posix open is only called (at lookup time) for file create now. | ||
| 564 | * For opens (rather than creates), because we do not know if it | ||
| 565 | * is a file or directory yet, and current Samba no longer allows | ||
| 566 | * us to do posix open on dirs, we could end up wasting an open call | ||
| 567 | * on what turns out to be a dir. For file opens, we wait to call posix | ||
| 568 | * open till cifs_open. It could be added here (lookup) in the future | ||
| 569 | * but the performance tradeoff of the extra network request when EISDIR | ||
| 570 | * or EACCES is returned would have to be weighed against the 50% | ||
| 571 | * reduction in network traffic in the other paths. | ||
| 572 | */ | ||
| 573 | if (pTcon->unix_ext) { | 669 | if (pTcon->unix_ext) { |
| 574 | if (nd && !(nd->flags & LOOKUP_DIRECTORY) && | 670 | rc = cifs_get_inode_info_unix(&newInode, full_path, |
| 575 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 671 | parent_dir_inode->i_sb, xid); |
| 576 | (nd->intent.open.file->f_flags & O_CREAT)) { | 672 | } else { |
| 577 | rc = cifs_posix_open(full_path, &newInode, | ||
| 578 | parent_dir_inode->i_sb, | ||
| 579 | nd->intent.open.create_mode, | ||
| 580 | nd->intent.open.file->f_flags, &oplock, | ||
| 581 | &fileHandle, xid); | ||
| 582 | /* | ||
| 583 | * The check below works around a bug in POSIX | ||
| 584 | * open in samba versions 3.3.1 and earlier where | ||
| 585 | * open could incorrectly fail with invalid parameter. | ||
| 586 | * If either that or op not supported returned, follow | ||
| 587 | * the normal lookup. | ||
| 588 | */ | ||
| 589 | switch (rc) { | ||
| 590 | case 0: | ||
| 591 | /* | ||
| 592 | * The server may allow us to open things like | ||
| 593 | * FIFOs, but the client isn't set up to deal | ||
| 594 | * with that. If it's not a regular file, just | ||
| 595 | * close it and proceed as if it were a normal | ||
| 596 | * lookup. | ||
| 597 | */ | ||
| 598 | if (newInode && !S_ISREG(newInode->i_mode)) { | ||
| 599 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
| 600 | break; | ||
| 601 | } | ||
| 602 | case -ENOENT: | ||
| 603 | posix_open = true; | ||
| 604 | case -EOPNOTSUPP: | ||
| 605 | break; | ||
| 606 | default: | ||
| 607 | pTcon->broken_posix_open = true; | ||
| 608 | } | ||
| 609 | } | ||
| 610 | if (!posix_open) | ||
| 611 | rc = cifs_get_inode_info_unix(&newInode, full_path, | ||
| 612 | parent_dir_inode->i_sb, xid); | ||
| 613 | } else | ||
| 614 | rc = cifs_get_inode_info(&newInode, full_path, NULL, | 673 | rc = cifs_get_inode_info(&newInode, full_path, NULL, |
| 615 | parent_dir_inode->i_sb, xid, NULL); | 674 | parent_dir_inode->i_sb, xid, NULL); |
| 675 | } | ||
| 616 | 676 | ||
| 617 | if ((rc == 0) && (newInode != NULL)) { | 677 | if ((rc == 0) && (newInode != NULL)) { |
| 618 | d_add(direntry, newInode); | 678 | d_add(direntry, newInode); |
| 619 | if (posix_open) { | ||
| 620 | filp = lookup_instantiate_filp(nd, direntry, | ||
| 621 | generic_file_open); | ||
| 622 | if (IS_ERR(filp)) { | ||
| 623 | rc = PTR_ERR(filp); | ||
| 624 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
| 625 | goto lookup_out; | ||
| 626 | } | ||
| 627 | |||
| 628 | cfile = cifs_new_fileinfo(fileHandle, filp, tlink, | ||
| 629 | oplock); | ||
| 630 | if (cfile == NULL) { | ||
| 631 | fput(filp); | ||
| 632 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
| 633 | rc = -ENOMEM; | ||
| 634 | goto lookup_out; | ||
| 635 | } | ||
| 636 | } | ||
| 637 | /* since paths are not looked up by component - the parent | 679 | /* since paths are not looked up by component - the parent |
| 638 | directories are presumed to be good here */ | 680 | directories are presumed to be good here */ |
| 639 | renew_parental_timestamps(direntry); | 681 | renew_parental_timestamps(direntry); |
| @@ -658,9 +700,9 @@ lookup_out: | |||
| 658 | } | 700 | } |
| 659 | 701 | ||
| 660 | static int | 702 | static int |
| 661 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | 703 | cifs_d_revalidate(struct dentry *direntry, unsigned int flags) |
| 662 | { | 704 | { |
| 663 | if (nd && (nd->flags & LOOKUP_RCU)) | 705 | if (flags & LOOKUP_RCU) |
| 664 | return -ECHILD; | 706 | return -ECHILD; |
| 665 | 707 | ||
| 666 | if (direntry->d_inode) { | 708 | if (direntry->d_inode) { |
| @@ -689,7 +731,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | |||
| 689 | * This may be nfsd (or something), anyway, we can't see the | 731 | * This may be nfsd (or something), anyway, we can't see the |
| 690 | * intent of this. So, since this can be for creation, drop it. | 732 | * intent of this. So, since this can be for creation, drop it. |
| 691 | */ | 733 | */ |
| 692 | if (!nd) | 734 | if (!flags) |
| 693 | return 0; | 735 | return 0; |
| 694 | 736 | ||
| 695 | /* | 737 | /* |
| @@ -697,7 +739,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | |||
| 697 | * case sensitive name which is specified by user if this is | 739 | * case sensitive name which is specified by user if this is |
| 698 | * for creation. | 740 | * for creation. |
| 699 | */ | 741 | */ |
| 700 | if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) | 742 | if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) |
| 701 | return 0; | 743 | return 0; |
| 702 | 744 | ||
| 703 | if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) | 745 | if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 745da3d0653e..8e8bb49112ff 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -800,7 +800,7 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
| 800 | return 0; | 800 | return 0; |
| 801 | 801 | ||
| 802 | /* if it's not a directory or has no dentries, then flag it */ | 802 | /* if it's not a directory or has no dentries, then flag it */ |
| 803 | if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) | 803 | if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) |
| 804 | fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; | 804 | fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; |
| 805 | 805 | ||
| 806 | return 1; | 806 | return 1; |
| @@ -825,9 +825,10 @@ static bool | |||
| 825 | inode_has_hashed_dentries(struct inode *inode) | 825 | inode_has_hashed_dentries(struct inode *inode) |
| 826 | { | 826 | { |
| 827 | struct dentry *dentry; | 827 | struct dentry *dentry; |
| 828 | struct hlist_node *p; | ||
| 828 | 829 | ||
| 829 | spin_lock(&inode->i_lock); | 830 | spin_lock(&inode->i_lock); |
| 830 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | 831 | hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) { |
| 831 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { | 832 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { |
| 832 | spin_unlock(&inode->i_lock); | 833 | spin_unlock(&inode->i_lock); |
| 833 | return true; | 834 | return true; |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 0a8224d1c4c5..a4217f02fab2 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -86,9 +86,12 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
| 86 | 86 | ||
| 87 | dentry = d_lookup(parent, name); | 87 | dentry = d_lookup(parent, name); |
| 88 | if (dentry) { | 88 | if (dentry) { |
| 89 | /* FIXME: check for inode number changes? */ | 89 | inode = dentry->d_inode; |
| 90 | if (dentry->d_inode != NULL) | 90 | /* update inode in place if i_ino didn't change */ |
| 91 | if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { | ||
| 92 | cifs_fattr_to_inode(inode, fattr); | ||
| 91 | return dentry; | 93 | return dentry; |
| 94 | } | ||
| 92 | d_drop(dentry); | 95 | d_drop(dentry); |
| 93 | dput(dentry); | 96 | dput(dentry); |
| 94 | } | 97 | } |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 3097ee58fd7d..f25d4ea14be4 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -365,16 +365,14 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov, | |||
| 365 | if (mid == NULL) | 365 | if (mid == NULL) |
| 366 | return -ENOMEM; | 366 | return -ENOMEM; |
| 367 | 367 | ||
| 368 | /* put it on the pending_mid_q */ | ||
| 369 | spin_lock(&GlobalMid_Lock); | ||
| 370 | list_add_tail(&mid->qhead, &server->pending_mid_q); | ||
| 371 | spin_unlock(&GlobalMid_Lock); | ||
| 372 | |||
| 373 | rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number); | 368 | rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number); |
| 374 | if (rc) | 369 | if (rc) { |
| 375 | delete_mid(mid); | 370 | DeleteMidQEntry(mid); |
| 371 | return rc; | ||
| 372 | } | ||
| 373 | |||
| 376 | *ret_mid = mid; | 374 | *ret_mid = mid; |
| 377 | return rc; | 375 | return 0; |
| 378 | } | 376 | } |
| 379 | 377 | ||
| 380 | /* | 378 | /* |
| @@ -407,17 +405,21 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | |||
| 407 | mid->callback_data = cbdata; | 405 | mid->callback_data = cbdata; |
| 408 | mid->mid_state = MID_REQUEST_SUBMITTED; | 406 | mid->mid_state = MID_REQUEST_SUBMITTED; |
| 409 | 407 | ||
| 408 | /* put it on the pending_mid_q */ | ||
| 409 | spin_lock(&GlobalMid_Lock); | ||
| 410 | list_add_tail(&mid->qhead, &server->pending_mid_q); | ||
| 411 | spin_unlock(&GlobalMid_Lock); | ||
| 412 | |||
| 413 | |||
| 410 | cifs_in_send_inc(server); | 414 | cifs_in_send_inc(server); |
| 411 | rc = smb_sendv(server, iov, nvec); | 415 | rc = smb_sendv(server, iov, nvec); |
| 412 | cifs_in_send_dec(server); | 416 | cifs_in_send_dec(server); |
| 413 | cifs_save_when_sent(mid); | 417 | cifs_save_when_sent(mid); |
| 414 | mutex_unlock(&server->srv_mutex); | 418 | mutex_unlock(&server->srv_mutex); |
| 415 | 419 | ||
| 416 | if (rc) | 420 | if (rc == 0) |
| 417 | goto out_err; | 421 | return 0; |
| 418 | 422 | ||
| 419 | return rc; | ||
| 420 | out_err: | ||
| 421 | delete_mid(mid); | 423 | delete_mid(mid); |
| 422 | add_credits(server, 1); | 424 | add_credits(server, 1); |
| 423 | wake_up(&server->request_q); | 425 | wake_up(&server->request_q); |
