diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/cifs/dir.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r-- | fs/cifs/dir.c | 350 |
1 files changed, 119 insertions, 231 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f9ed0751cc12..fa8c21d913bc 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -50,42 +50,48 @@ build_path_from_dentry(struct dentry *direntry) | |||
50 | { | 50 | { |
51 | struct dentry *temp; | 51 | struct dentry *temp; |
52 | int namelen; | 52 | int namelen; |
53 | int pplen; | ||
54 | int dfsplen; | 53 | int dfsplen; |
55 | char *full_path; | 54 | char *full_path; |
56 | char dirsep; | 55 | char dirsep; |
57 | struct cifs_sb_info *cifs_sb; | 56 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); |
57 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); | ||
58 | unsigned seq; | ||
58 | 59 | ||
59 | if (direntry == NULL) | 60 | if (direntry == NULL) |
60 | return NULL; /* not much we can do if dentry is freed and | 61 | return NULL; /* not much we can do if dentry is freed and |
61 | we need to reopen the file after it was closed implicitly | 62 | we need to reopen the file after it was closed implicitly |
62 | when the server crashed */ | 63 | when the server crashed */ |
63 | 64 | ||
64 | cifs_sb = CIFS_SB(direntry->d_sb); | ||
65 | dirsep = CIFS_DIR_SEP(cifs_sb); | 65 | dirsep = CIFS_DIR_SEP(cifs_sb); |
66 | pplen = cifs_sb->prepathlen; | 66 | if (tcon->Flags & SMB_SHARE_IS_IN_DFS) |
67 | if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) | 67 | dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); |
68 | dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); | ||
69 | else | 68 | else |
70 | dfsplen = 0; | 69 | dfsplen = 0; |
71 | cifs_bp_rename_retry: | 70 | cifs_bp_rename_retry: |
72 | namelen = pplen + dfsplen; | 71 | namelen = dfsplen; |
72 | seq = read_seqbegin(&rename_lock); | ||
73 | rcu_read_lock(); | ||
73 | for (temp = direntry; !IS_ROOT(temp);) { | 74 | for (temp = direntry; !IS_ROOT(temp);) { |
74 | namelen += (1 + temp->d_name.len); | 75 | namelen += (1 + temp->d_name.len); |
75 | temp = temp->d_parent; | 76 | temp = temp->d_parent; |
76 | if (temp == NULL) { | 77 | if (temp == NULL) { |
77 | cERROR(1, "corrupt dentry"); | 78 | cERROR(1, "corrupt dentry"); |
79 | rcu_read_unlock(); | ||
78 | return NULL; | 80 | return NULL; |
79 | } | 81 | } |
80 | } | 82 | } |
83 | rcu_read_unlock(); | ||
81 | 84 | ||
82 | full_path = kmalloc(namelen+1, GFP_KERNEL); | 85 | full_path = kmalloc(namelen+1, GFP_KERNEL); |
83 | if (full_path == NULL) | 86 | if (full_path == NULL) |
84 | return full_path; | 87 | return full_path; |
85 | full_path[namelen] = 0; /* trailing null */ | 88 | full_path[namelen] = 0; /* trailing null */ |
89 | rcu_read_lock(); | ||
86 | for (temp = direntry; !IS_ROOT(temp);) { | 90 | for (temp = direntry; !IS_ROOT(temp);) { |
91 | spin_lock(&temp->d_lock); | ||
87 | namelen -= 1 + temp->d_name.len; | 92 | namelen -= 1 + temp->d_name.len; |
88 | if (namelen < 0) { | 93 | if (namelen < 0) { |
94 | spin_unlock(&temp->d_lock); | ||
89 | break; | 95 | break; |
90 | } else { | 96 | } else { |
91 | full_path[namelen] = dirsep; | 97 | full_path[namelen] = dirsep; |
@@ -93,14 +99,17 @@ cifs_bp_rename_retry: | |||
93 | temp->d_name.len); | 99 | temp->d_name.len); |
94 | cFYI(0, "name: %s", full_path + namelen); | 100 | cFYI(0, "name: %s", full_path + namelen); |
95 | } | 101 | } |
102 | spin_unlock(&temp->d_lock); | ||
96 | temp = temp->d_parent; | 103 | temp = temp->d_parent; |
97 | if (temp == NULL) { | 104 | if (temp == NULL) { |
98 | cERROR(1, "corrupt dentry"); | 105 | cERROR(1, "corrupt dentry"); |
106 | rcu_read_unlock(); | ||
99 | kfree(full_path); | 107 | kfree(full_path); |
100 | return NULL; | 108 | return NULL; |
101 | } | 109 | } |
102 | } | 110 | } |
103 | if (namelen != pplen + dfsplen) { | 111 | rcu_read_unlock(); |
112 | if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) { | ||
104 | cERROR(1, "did not end path lookup where expected namelen is %d", | 113 | cERROR(1, "did not end path lookup where expected namelen is %d", |
105 | namelen); | 114 | namelen); |
106 | /* presumably this is only possible if racing with a rename | 115 | /* presumably this is only possible if racing with a rename |
@@ -117,7 +126,7 @@ cifs_bp_rename_retry: | |||
117 | /* BB test paths to Windows with '/' in the midst of prepath */ | 126 | /* BB test paths to Windows with '/' in the midst of prepath */ |
118 | 127 | ||
119 | if (dfsplen) { | 128 | if (dfsplen) { |
120 | strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); | 129 | strncpy(full_path, tcon->treeName, dfsplen); |
121 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | 130 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { |
122 | int i; | 131 | int i; |
123 | for (i = 0; i < dfsplen; i++) { | 132 | for (i = 0; i < dfsplen; i++) { |
@@ -126,150 +135,9 @@ cifs_bp_rename_retry: | |||
126 | } | 135 | } |
127 | } | 136 | } |
128 | } | 137 | } |
129 | strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen); | ||
130 | return full_path; | 138 | return full_path; |
131 | } | 139 | } |
132 | 140 | ||
133 | struct cifsFileInfo * | ||
134 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | ||
135 | struct file *file, struct vfsmount *mnt, unsigned int oflags) | ||
136 | { | ||
137 | int oplock = 0; | ||
138 | struct cifsFileInfo *pCifsFile; | ||
139 | struct cifsInodeInfo *pCifsInode; | ||
140 | struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); | ||
141 | |||
142 | pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
143 | if (pCifsFile == NULL) | ||
144 | return pCifsFile; | ||
145 | |||
146 | if (oplockEnabled) | ||
147 | oplock = REQ_OPLOCK; | ||
148 | |||
149 | pCifsFile->netfid = fileHandle; | ||
150 | pCifsFile->pid = current->tgid; | ||
151 | pCifsFile->pInode = igrab(newinode); | ||
152 | pCifsFile->mnt = mnt; | ||
153 | pCifsFile->pfile = file; | ||
154 | pCifsFile->invalidHandle = false; | ||
155 | pCifsFile->closePend = false; | ||
156 | mutex_init(&pCifsFile->fh_mutex); | ||
157 | mutex_init(&pCifsFile->lock_mutex); | ||
158 | INIT_LIST_HEAD(&pCifsFile->llist); | ||
159 | atomic_set(&pCifsFile->count, 1); | ||
160 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); | ||
161 | |||
162 | write_lock(&GlobalSMBSeslock); | ||
163 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | ||
164 | pCifsInode = CIFS_I(newinode); | ||
165 | if (pCifsInode) { | ||
166 | /* if readable file instance put first in list*/ | ||
167 | if (oflags & FMODE_READ) | ||
168 | list_add(&pCifsFile->flist, &pCifsInode->openFileList); | ||
169 | else | ||
170 | list_add_tail(&pCifsFile->flist, | ||
171 | &pCifsInode->openFileList); | ||
172 | |||
173 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
174 | pCifsInode->clientCanCacheAll = true; | ||
175 | pCifsInode->clientCanCacheRead = true; | ||
176 | cFYI(1, "Exclusive Oplock inode %p", newinode); | ||
177 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
178 | pCifsInode->clientCanCacheRead = true; | ||
179 | } | ||
180 | write_unlock(&GlobalSMBSeslock); | ||
181 | |||
182 | file->private_data = pCifsFile; | ||
183 | |||
184 | return pCifsFile; | ||
185 | } | ||
186 | |||
187 | int cifs_posix_open(char *full_path, struct inode **pinode, | ||
188 | struct super_block *sb, int mode, int oflags, | ||
189 | __u32 *poplock, __u16 *pnetfid, int xid) | ||
190 | { | ||
191 | int rc; | ||
192 | FILE_UNIX_BASIC_INFO *presp_data; | ||
193 | __u32 posix_flags = 0; | ||
194 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
195 | struct cifs_fattr fattr; | ||
196 | |||
197 | cFYI(1, "posix open %s", full_path); | ||
198 | |||
199 | presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
200 | if (presp_data == NULL) | ||
201 | return -ENOMEM; | ||
202 | |||
203 | /* So far cifs posix extensions can only map the following flags. | ||
204 | There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but | ||
205 | so far we do not seem to need them, and we can treat them as local only */ | ||
206 | if ((oflags & (FMODE_READ | FMODE_WRITE)) == | ||
207 | (FMODE_READ | FMODE_WRITE)) | ||
208 | posix_flags = SMB_O_RDWR; | ||
209 | else if (oflags & FMODE_READ) | ||
210 | posix_flags = SMB_O_RDONLY; | ||
211 | else if (oflags & FMODE_WRITE) | ||
212 | posix_flags = SMB_O_WRONLY; | ||
213 | if (oflags & O_CREAT) | ||
214 | posix_flags |= SMB_O_CREAT; | ||
215 | if (oflags & O_EXCL) | ||
216 | posix_flags |= SMB_O_EXCL; | ||
217 | if (oflags & O_TRUNC) | ||
218 | posix_flags |= SMB_O_TRUNC; | ||
219 | /* be safe and imply O_SYNC for O_DSYNC */ | ||
220 | if (oflags & O_DSYNC) | ||
221 | posix_flags |= SMB_O_SYNC; | ||
222 | if (oflags & O_DIRECTORY) | ||
223 | posix_flags |= SMB_O_DIRECTORY; | ||
224 | if (oflags & O_NOFOLLOW) | ||
225 | posix_flags |= SMB_O_NOFOLLOW; | ||
226 | if (oflags & O_DIRECT) | ||
227 | posix_flags |= SMB_O_DIRECT; | ||
228 | |||
229 | mode &= ~current_umask(); | ||
230 | rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, | ||
231 | pnetfid, presp_data, poplock, full_path, | ||
232 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
233 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
234 | if (rc) | ||
235 | goto posix_open_ret; | ||
236 | |||
237 | if (presp_data->Type == cpu_to_le32(-1)) | ||
238 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | ||
239 | |||
240 | if (!pinode) | ||
241 | goto posix_open_ret; /* caller does not need info */ | ||
242 | |||
243 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | ||
244 | |||
245 | /* get new inode and set it up */ | ||
246 | if (*pinode == NULL) { | ||
247 | cifs_fill_uniqueid(sb, &fattr); | ||
248 | *pinode = cifs_iget(sb, &fattr); | ||
249 | if (!*pinode) { | ||
250 | rc = -ENOMEM; | ||
251 | goto posix_open_ret; | ||
252 | } | ||
253 | } else { | ||
254 | cifs_fattr_to_inode(*pinode, &fattr); | ||
255 | } | ||
256 | |||
257 | posix_open_ret: | ||
258 | kfree(presp_data); | ||
259 | return rc; | ||
260 | } | ||
261 | |||
262 | static void setup_cifs_dentry(struct cifsTconInfo *tcon, | ||
263 | struct dentry *direntry, | ||
264 | struct inode *newinode) | ||
265 | { | ||
266 | if (tcon->nocase) | ||
267 | direntry->d_op = &cifs_ci_dentry_ops; | ||
268 | else | ||
269 | direntry->d_op = &cifs_dentry_ops; | ||
270 | d_instantiate(direntry, newinode); | ||
271 | } | ||
272 | |||
273 | /* Inode operations in similar order to how they appear in Linux file fs.h */ | 141 | /* Inode operations in similar order to how they appear in Linux file fs.h */ |
274 | 142 | ||
275 | int | 143 | int |
@@ -291,7 +159,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
291 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; | 159 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; |
292 | __u16 fileHandle; | 160 | __u16 fileHandle; |
293 | struct cifs_sb_info *cifs_sb; | 161 | struct cifs_sb_info *cifs_sb; |
294 | struct cifsTconInfo *tcon; | 162 | struct tcon_link *tlink; |
163 | struct cifs_tcon *tcon; | ||
295 | char *full_path = NULL; | 164 | char *full_path = NULL; |
296 | FILE_ALL_INFO *buf = NULL; | 165 | FILE_ALL_INFO *buf = NULL; |
297 | struct inode *newinode = NULL; | 166 | struct inode *newinode = NULL; |
@@ -300,21 +169,26 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
300 | xid = GetXid(); | 169 | xid = GetXid(); |
301 | 170 | ||
302 | cifs_sb = CIFS_SB(inode->i_sb); | 171 | cifs_sb = CIFS_SB(inode->i_sb); |
303 | tcon = cifs_sb->tcon; | 172 | tlink = cifs_sb_tlink(cifs_sb); |
304 | 173 | if (IS_ERR(tlink)) { | |
305 | full_path = build_path_from_dentry(direntry); | 174 | FreeXid(xid); |
306 | if (full_path == NULL) { | 175 | return PTR_ERR(tlink); |
307 | rc = -ENOMEM; | ||
308 | goto cifs_create_out; | ||
309 | } | 176 | } |
177 | tcon = tlink_tcon(tlink); | ||
310 | 178 | ||
311 | if (oplockEnabled) | 179 | if (oplockEnabled) |
312 | oplock = REQ_OPLOCK; | 180 | oplock = REQ_OPLOCK; |
313 | 181 | ||
314 | if (nd && (nd->flags & LOOKUP_OPEN)) | 182 | if (nd && (nd->flags & LOOKUP_OPEN)) |
315 | oflags = nd->intent.open.flags; | 183 | oflags = nd->intent.open.file->f_flags; |
316 | else | 184 | else |
317 | oflags = FMODE_READ | SMB_O_CREAT; | 185 | oflags = O_RDONLY | O_CREAT; |
186 | |||
187 | full_path = build_path_from_dentry(direntry); | ||
188 | if (full_path == NULL) { | ||
189 | rc = -ENOMEM; | ||
190 | goto cifs_create_out; | ||
191 | } | ||
318 | 192 | ||
319 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 193 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
320 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 194 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
@@ -323,7 +197,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
323 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); | 197 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); |
324 | /* EIO could indicate that (posix open) operation is not | 198 | /* EIO could indicate that (posix open) operation is not |
325 | supported, despite what server claimed in capability | 199 | supported, despite what server claimed in capability |
326 | negotation. EREMOTE indicates DFS junction, which is not | 200 | negotiation. EREMOTE indicates DFS junction, which is not |
327 | handled in posix open */ | 201 | handled in posix open */ |
328 | 202 | ||
329 | if (rc == 0) { | 203 | if (rc == 0) { |
@@ -344,9 +218,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
344 | /* if the file is going to stay open, then we | 218 | /* if the file is going to stay open, then we |
345 | need to set the desired access properly */ | 219 | need to set the desired access properly */ |
346 | desiredAccess = 0; | 220 | desiredAccess = 0; |
347 | if (oflags & FMODE_READ) | 221 | if (OPEN_FMODE(oflags) & FMODE_READ) |
348 | desiredAccess |= GENERIC_READ; /* is this too little? */ | 222 | desiredAccess |= GENERIC_READ; /* is this too little? */ |
349 | if (oflags & FMODE_WRITE) | 223 | if (OPEN_FMODE(oflags) & FMODE_WRITE) |
350 | desiredAccess |= GENERIC_WRITE; | 224 | desiredAccess |= GENERIC_WRITE; |
351 | 225 | ||
352 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | 226 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) |
@@ -375,7 +249,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
375 | if (!tcon->unix_ext && (mode & S_IWUGO) == 0) | 249 | if (!tcon->unix_ext && (mode & S_IWUGO) == 0) |
376 | create_options |= CREATE_OPTION_READONLY; | 250 | create_options |= CREATE_OPTION_READONLY; |
377 | 251 | ||
378 | if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) | 252 | if (tcon->ses->capabilities & CAP_NT_SMBS) |
379 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | 253 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, |
380 | desiredAccess, create_options, | 254 | desiredAccess, create_options, |
381 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 255 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
@@ -416,10 +290,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
416 | args.uid = NO_CHANGE_64; | 290 | args.uid = NO_CHANGE_64; |
417 | args.gid = NO_CHANGE_64; | 291 | args.gid = NO_CHANGE_64; |
418 | } | 292 | } |
419 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 293 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle, |
420 | cifs_sb->local_nls, | 294 | current->tgid); |
421 | cifs_sb->mnt_cifs_flags & | ||
422 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
423 | } else { | 295 | } else { |
424 | /* BB implement mode setting via Windows security | 296 | /* BB implement mode setting via Windows security |
425 | descriptors e.g. */ | 297 | descriptors e.g. */ |
@@ -452,7 +324,7 @@ cifs_create_get_file_info: | |||
452 | 324 | ||
453 | cifs_create_set_dentry: | 325 | cifs_create_set_dentry: |
454 | if (rc == 0) | 326 | if (rc == 0) |
455 | setup_cifs_dentry(tcon, direntry, newinode); | 327 | d_instantiate(direntry, newinode); |
456 | else | 328 | else |
457 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); | 329 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); |
458 | 330 | ||
@@ -467,8 +339,7 @@ cifs_create_set_dentry: | |||
467 | goto cifs_create_out; | 339 | goto cifs_create_out; |
468 | } | 340 | } |
469 | 341 | ||
470 | pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp, | 342 | pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); |
471 | nd->path.mnt, oflags); | ||
472 | if (pfile_info == NULL) { | 343 | if (pfile_info == NULL) { |
473 | fput(filp); | 344 | fput(filp); |
474 | CIFSSMBClose(xid, tcon, fileHandle); | 345 | CIFSSMBClose(xid, tcon, fileHandle); |
@@ -481,6 +352,7 @@ cifs_create_set_dentry: | |||
481 | cifs_create_out: | 352 | cifs_create_out: |
482 | kfree(buf); | 353 | kfree(buf); |
483 | kfree(full_path); | 354 | kfree(full_path); |
355 | cifs_put_tlink(tlink); | ||
484 | FreeXid(xid); | 356 | FreeXid(xid); |
485 | return rc; | 357 | return rc; |
486 | } | 358 | } |
@@ -491,7 +363,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
491 | int rc = -EPERM; | 363 | int rc = -EPERM; |
492 | int xid; | 364 | int xid; |
493 | struct cifs_sb_info *cifs_sb; | 365 | struct cifs_sb_info *cifs_sb; |
494 | struct cifsTconInfo *pTcon; | 366 | struct tcon_link *tlink; |
367 | struct cifs_tcon *pTcon; | ||
368 | struct cifs_io_parms io_parms; | ||
495 | char *full_path = NULL; | 369 | char *full_path = NULL; |
496 | struct inode *newinode = NULL; | 370 | struct inode *newinode = NULL; |
497 | int oplock = 0; | 371 | int oplock = 0; |
@@ -503,10 +377,14 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
503 | if (!old_valid_dev(device_number)) | 377 | if (!old_valid_dev(device_number)) |
504 | return -EINVAL; | 378 | return -EINVAL; |
505 | 379 | ||
506 | xid = GetXid(); | ||
507 | |||
508 | cifs_sb = CIFS_SB(inode->i_sb); | 380 | cifs_sb = CIFS_SB(inode->i_sb); |
509 | pTcon = cifs_sb->tcon; | 381 | tlink = cifs_sb_tlink(cifs_sb); |
382 | if (IS_ERR(tlink)) | ||
383 | return PTR_ERR(tlink); | ||
384 | |||
385 | pTcon = tlink_tcon(tlink); | ||
386 | |||
387 | xid = GetXid(); | ||
510 | 388 | ||
511 | full_path = build_path_from_dentry(direntry); | 389 | full_path = build_path_from_dentry(direntry); |
512 | if (full_path == NULL) { | 390 | if (full_path == NULL) { |
@@ -538,10 +416,6 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
538 | 416 | ||
539 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 417 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
540 | inode->i_sb, xid); | 418 | inode->i_sb, xid); |
541 | if (pTcon->nocase) | ||
542 | direntry->d_op = &cifs_ci_dentry_ops; | ||
543 | else | ||
544 | direntry->d_op = &cifs_dentry_ops; | ||
545 | 419 | ||
546 | if (rc == 0) | 420 | if (rc == 0) |
547 | d_instantiate(direntry, newinode); | 421 | d_instantiate(direntry, newinode); |
@@ -574,16 +448,19 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
574 | * timestamps in, but we can reuse it safely */ | 448 | * timestamps in, but we can reuse it safely */ |
575 | 449 | ||
576 | pdev = (struct win_dev *)buf; | 450 | pdev = (struct win_dev *)buf; |
451 | io_parms.netfid = fileHandle; | ||
452 | io_parms.pid = current->tgid; | ||
453 | io_parms.tcon = pTcon; | ||
454 | io_parms.offset = 0; | ||
455 | io_parms.length = sizeof(struct win_dev); | ||
577 | if (S_ISCHR(mode)) { | 456 | if (S_ISCHR(mode)) { |
578 | memcpy(pdev->type, "IntxCHR", 8); | 457 | memcpy(pdev->type, "IntxCHR", 8); |
579 | pdev->major = | 458 | pdev->major = |
580 | cpu_to_le64(MAJOR(device_number)); | 459 | cpu_to_le64(MAJOR(device_number)); |
581 | pdev->minor = | 460 | pdev->minor = |
582 | cpu_to_le64(MINOR(device_number)); | 461 | cpu_to_le64(MINOR(device_number)); |
583 | rc = CIFSSMBWrite(xid, pTcon, | 462 | rc = CIFSSMBWrite(xid, &io_parms, |
584 | fileHandle, | 463 | &bytes_written, (char *)pdev, |
585 | sizeof(struct win_dev), | ||
586 | 0, &bytes_written, (char *)pdev, | ||
587 | NULL, 0); | 464 | NULL, 0); |
588 | } else if (S_ISBLK(mode)) { | 465 | } else if (S_ISBLK(mode)) { |
589 | memcpy(pdev->type, "IntxBLK", 8); | 466 | memcpy(pdev->type, "IntxBLK", 8); |
@@ -591,10 +468,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
591 | cpu_to_le64(MAJOR(device_number)); | 468 | cpu_to_le64(MAJOR(device_number)); |
592 | pdev->minor = | 469 | pdev->minor = |
593 | cpu_to_le64(MINOR(device_number)); | 470 | cpu_to_le64(MINOR(device_number)); |
594 | rc = CIFSSMBWrite(xid, pTcon, | 471 | rc = CIFSSMBWrite(xid, &io_parms, |
595 | fileHandle, | 472 | &bytes_written, (char *)pdev, |
596 | sizeof(struct win_dev), | ||
597 | 0, &bytes_written, (char *)pdev, | ||
598 | NULL, 0); | 473 | NULL, 0); |
599 | } /* else if (S_ISFIFO) */ | 474 | } /* else if (S_ISFIFO) */ |
600 | CIFSSMBClose(xid, pTcon, fileHandle); | 475 | CIFSSMBClose(xid, pTcon, fileHandle); |
@@ -606,6 +481,7 @@ mknod_out: | |||
606 | kfree(full_path); | 481 | kfree(full_path); |
607 | kfree(buf); | 482 | kfree(buf); |
608 | FreeXid(xid); | 483 | FreeXid(xid); |
484 | cifs_put_tlink(tlink); | ||
609 | return rc; | 485 | return rc; |
610 | } | 486 | } |
611 | 487 | ||
@@ -619,7 +495,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
619 | __u16 fileHandle = 0; | 495 | __u16 fileHandle = 0; |
620 | bool posix_open = false; | 496 | bool posix_open = false; |
621 | struct cifs_sb_info *cifs_sb; | 497 | struct cifs_sb_info *cifs_sb; |
622 | struct cifsTconInfo *pTcon; | 498 | struct tcon_link *tlink; |
499 | struct cifs_tcon *pTcon; | ||
623 | struct cifsFileInfo *cfile; | 500 | struct cifsFileInfo *cfile; |
624 | struct inode *newInode = NULL; | 501 | struct inode *newInode = NULL; |
625 | char *full_path = NULL; | 502 | char *full_path = NULL; |
@@ -633,7 +510,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
633 | /* check whether path exists */ | 510 | /* check whether path exists */ |
634 | 511 | ||
635 | cifs_sb = CIFS_SB(parent_dir_inode->i_sb); | 512 | cifs_sb = CIFS_SB(parent_dir_inode->i_sb); |
636 | pTcon = cifs_sb->tcon; | 513 | tlink = cifs_sb_tlink(cifs_sb); |
514 | if (IS_ERR(tlink)) { | ||
515 | FreeXid(xid); | ||
516 | return (struct dentry *)tlink; | ||
517 | } | ||
518 | pTcon = tlink_tcon(tlink); | ||
637 | 519 | ||
638 | /* | 520 | /* |
639 | * Don't allow the separator character in a path component. | 521 | * Don't allow the separator character in a path component. |
@@ -644,8 +526,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
644 | for (i = 0; i < direntry->d_name.len; i++) | 526 | for (i = 0; i < direntry->d_name.len; i++) |
645 | if (direntry->d_name.name[i] == '\\') { | 527 | if (direntry->d_name.name[i] == '\\') { |
646 | cFYI(1, "Invalid file name"); | 528 | cFYI(1, "Invalid file name"); |
647 | FreeXid(xid); | 529 | rc = -EINVAL; |
648 | return ERR_PTR(-EINVAL); | 530 | goto lookup_out; |
649 | } | 531 | } |
650 | } | 532 | } |
651 | 533 | ||
@@ -655,7 +537,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
655 | */ | 537 | */ |
656 | if (nd && (nd->flags & LOOKUP_EXCL)) { | 538 | if (nd && (nd->flags & LOOKUP_EXCL)) { |
657 | d_instantiate(direntry, NULL); | 539 | d_instantiate(direntry, NULL); |
658 | return NULL; | 540 | rc = 0; |
541 | goto lookup_out; | ||
659 | } | 542 | } |
660 | 543 | ||
661 | /* can not grab the rename sem here since it would | 544 | /* can not grab the rename sem here since it would |
@@ -663,8 +546,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
663 | in which we already have the sb rename sem */ | 546 | in which we already have the sb rename sem */ |
664 | full_path = build_path_from_dentry(direntry); | 547 | full_path = build_path_from_dentry(direntry); |
665 | if (full_path == NULL) { | 548 | if (full_path == NULL) { |
666 | FreeXid(xid); | 549 | rc = -ENOMEM; |
667 | return ERR_PTR(-ENOMEM); | 550 | goto lookup_out; |
668 | } | 551 | } |
669 | 552 | ||
670 | if (direntry->d_inode != NULL) { | 553 | if (direntry->d_inode != NULL) { |
@@ -687,11 +570,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
687 | if (pTcon->unix_ext) { | 570 | if (pTcon->unix_ext) { |
688 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | 571 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
689 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 572 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && |
690 | (nd->intent.open.flags & O_CREAT)) { | 573 | (nd->intent.open.file->f_flags & O_CREAT)) { |
691 | rc = cifs_posix_open(full_path, &newInode, | 574 | rc = cifs_posix_open(full_path, &newInode, |
692 | parent_dir_inode->i_sb, | 575 | parent_dir_inode->i_sb, |
693 | nd->intent.open.create_mode, | 576 | nd->intent.open.create_mode, |
694 | nd->intent.open.flags, &oplock, | 577 | nd->intent.open.file->f_flags, &oplock, |
695 | &fileHandle, xid); | 578 | &fileHandle, xid); |
696 | /* | 579 | /* |
697 | * The check below works around a bug in POSIX | 580 | * The check below works around a bug in POSIX |
@@ -713,10 +596,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
713 | parent_dir_inode->i_sb, xid, NULL); | 596 | parent_dir_inode->i_sb, xid, NULL); |
714 | 597 | ||
715 | if ((rc == 0) && (newInode != NULL)) { | 598 | if ((rc == 0) && (newInode != NULL)) { |
716 | if (pTcon->nocase) | ||
717 | direntry->d_op = &cifs_ci_dentry_ops; | ||
718 | else | ||
719 | direntry->d_op = &cifs_dentry_ops; | ||
720 | d_add(direntry, newInode); | 599 | d_add(direntry, newInode); |
721 | if (posix_open) { | 600 | if (posix_open) { |
722 | filp = lookup_instantiate_filp(nd, direntry, | 601 | filp = lookup_instantiate_filp(nd, direntry, |
@@ -727,9 +606,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
727 | goto lookup_out; | 606 | goto lookup_out; |
728 | } | 607 | } |
729 | 608 | ||
730 | cfile = cifs_new_fileinfo(newInode, fileHandle, filp, | 609 | cfile = cifs_new_fileinfo(fileHandle, filp, tlink, |
731 | nd->path.mnt, | 610 | oplock); |
732 | nd->intent.open.flags); | ||
733 | if (cfile == NULL) { | 611 | if (cfile == NULL) { |
734 | fput(filp); | 612 | fput(filp); |
735 | CIFSSMBClose(xid, pTcon, fileHandle); | 613 | CIFSSMBClose(xid, pTcon, fileHandle); |
@@ -744,10 +622,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
744 | } else if (rc == -ENOENT) { | 622 | } else if (rc == -ENOENT) { |
745 | rc = 0; | 623 | rc = 0; |
746 | direntry->d_time = jiffies; | 624 | direntry->d_time = jiffies; |
747 | if (pTcon->nocase) | ||
748 | direntry->d_op = &cifs_ci_dentry_ops; | ||
749 | else | ||
750 | direntry->d_op = &cifs_dentry_ops; | ||
751 | d_add(direntry, NULL); | 625 | d_add(direntry, NULL); |
752 | /* if it was once a directory (but how can we tell?) we could do | 626 | /* if it was once a directory (but how can we tell?) we could do |
753 | shrink_dcache_parent(direntry); */ | 627 | shrink_dcache_parent(direntry); */ |
@@ -759,6 +633,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
759 | 633 | ||
760 | lookup_out: | 634 | lookup_out: |
761 | kfree(full_path); | 635 | kfree(full_path); |
636 | cifs_put_tlink(tlink); | ||
762 | FreeXid(xid); | 637 | FreeXid(xid); |
763 | return ERR_PTR(rc); | 638 | return ERR_PTR(rc); |
764 | } | 639 | } |
@@ -766,22 +641,37 @@ lookup_out: | |||
766 | static int | 641 | static int |
767 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | 642 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) |
768 | { | 643 | { |
769 | int isValid = 1; | 644 | if (nd->flags & LOOKUP_RCU) |
645 | return -ECHILD; | ||
770 | 646 | ||
771 | if (direntry->d_inode) { | 647 | if (direntry->d_inode) { |
772 | if (cifs_revalidate_dentry(direntry)) | 648 | if (cifs_revalidate_dentry(direntry)) |
773 | return 0; | 649 | return 0; |
774 | } else { | 650 | else |
775 | cFYI(1, "neg dentry 0x%p name = %s", | 651 | return 1; |
776 | direntry, direntry->d_name.name); | ||
777 | if (time_after(jiffies, direntry->d_time + HZ) || | ||
778 | !lookupCacheEnabled) { | ||
779 | d_drop(direntry); | ||
780 | isValid = 0; | ||
781 | } | ||
782 | } | 652 | } |
783 | 653 | ||
784 | return isValid; | 654 | /* |
655 | * This may be nfsd (or something), anyway, we can't see the | ||
656 | * intent of this. So, since this can be for creation, drop it. | ||
657 | */ | ||
658 | if (!nd) | ||
659 | return 0; | ||
660 | |||
661 | /* | ||
662 | * Drop the negative dentry, in order to make sure to use the | ||
663 | * case sensitive name which is specified by user if this is | ||
664 | * for creation. | ||
665 | */ | ||
666 | if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { | ||
667 | if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) | ||
672 | return 0; | ||
673 | |||
674 | return 1; | ||
785 | } | 675 | } |
786 | 676 | ||
787 | /* static int cifs_d_delete(struct dentry *direntry) | 677 | /* static int cifs_d_delete(struct dentry *direntry) |
@@ -795,12 +685,14 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | |||
795 | 685 | ||
796 | const struct dentry_operations cifs_dentry_ops = { | 686 | const struct dentry_operations cifs_dentry_ops = { |
797 | .d_revalidate = cifs_d_revalidate, | 687 | .d_revalidate = cifs_d_revalidate, |
688 | .d_automount = cifs_dfs_d_automount, | ||
798 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ | 689 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ |
799 | }; | 690 | }; |
800 | 691 | ||
801 | static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | 692 | static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode, |
693 | struct qstr *q) | ||
802 | { | 694 | { |
803 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | 695 | struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; |
804 | unsigned long hash; | 696 | unsigned long hash; |
805 | int i; | 697 | int i; |
806 | 698 | ||
@@ -813,21 +705,16 @@ static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | |||
813 | return 0; | 705 | return 0; |
814 | } | 706 | } |
815 | 707 | ||
816 | static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, | 708 | static int cifs_ci_compare(const struct dentry *parent, |
817 | struct qstr *b) | 709 | const struct inode *pinode, |
710 | const struct dentry *dentry, const struct inode *inode, | ||
711 | unsigned int len, const char *str, const struct qstr *name) | ||
818 | { | 712 | { |
819 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | 713 | struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls; |
820 | 714 | ||
821 | if ((a->len == b->len) && | 715 | if ((name->len == len) && |
822 | (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) { | 716 | (nls_strnicmp(codepage, name->name, str, len) == 0)) |
823 | /* | ||
824 | * To preserve case, don't let an existing negative dentry's | ||
825 | * case take precedence. If a is not a negative dentry, this | ||
826 | * should have no side effects | ||
827 | */ | ||
828 | memcpy((void *)a->name, b->name, a->len); | ||
829 | return 0; | 717 | return 0; |
830 | } | ||
831 | return 1; | 718 | return 1; |
832 | } | 719 | } |
833 | 720 | ||
@@ -835,4 +722,5 @@ const struct dentry_operations cifs_ci_dentry_ops = { | |||
835 | .d_revalidate = cifs_d_revalidate, | 722 | .d_revalidate = cifs_d_revalidate, |
836 | .d_hash = cifs_ci_hash, | 723 | .d_hash = cifs_ci_hash, |
837 | .d_compare = cifs_ci_compare, | 724 | .d_compare = cifs_ci_compare, |
725 | .d_automount = cifs_dfs_d_automount, | ||
838 | }; | 726 | }; |