cifs: eliminate pfile pointer from cifsFileInfo
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / dir.c
blob600eac18cb21242bffd599fe106fa0adb971c2f0
1 /*
2 * fs/cifs/dir.c
4 * vfs operations that deal with dentries
6 * Copyright (C) International Business Machines Corp., 2002,2009
7 * Author(s): Steve French (sfrench@us.ibm.com)
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/fs.h>
24 #include <linux/stat.h>
25 #include <linux/slab.h>
26 #include <linux/namei.h>
27 #include <linux/mount.h>
28 #include <linux/file.h>
29 #include "cifsfs.h"
30 #include "cifspdu.h"
31 #include "cifsglob.h"
32 #include "cifsproto.h"
33 #include "cifs_debug.h"
34 #include "cifs_fs_sb.h"
36 static void
37 renew_parental_timestamps(struct dentry *direntry)
39 /* BB check if there is a way to get the kernel to do this or if we
40 really need this */
41 do {
42 direntry->d_time = jiffies;
43 direntry = direntry->d_parent;
44 } while (!IS_ROOT(direntry));
47 /* Note: caller must free return buffer */
48 char *
49 build_path_from_dentry(struct dentry *direntry)
51 struct dentry *temp;
52 int namelen;
53 int pplen;
54 int dfsplen;
55 char *full_path;
56 char dirsep;
57 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
58 struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
60 if (direntry == NULL)
61 return NULL; /* not much we can do if dentry is freed and
62 we need to reopen the file after it was closed implicitly
63 when the server crashed */
65 dirsep = CIFS_DIR_SEP(cifs_sb);
66 pplen = cifs_sb->prepathlen;
67 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
68 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
69 else
70 dfsplen = 0;
71 cifs_bp_rename_retry:
72 namelen = pplen + dfsplen;
73 for (temp = direntry; !IS_ROOT(temp);) {
74 namelen += (1 + temp->d_name.len);
75 temp = temp->d_parent;
76 if (temp == NULL) {
77 cERROR(1, "corrupt dentry");
78 return NULL;
82 full_path = kmalloc(namelen+1, GFP_KERNEL);
83 if (full_path == NULL)
84 return full_path;
85 full_path[namelen] = 0; /* trailing null */
86 for (temp = direntry; !IS_ROOT(temp);) {
87 namelen -= 1 + temp->d_name.len;
88 if (namelen < 0) {
89 break;
90 } else {
91 full_path[namelen] = dirsep;
92 strncpy(full_path + namelen + 1, temp->d_name.name,
93 temp->d_name.len);
94 cFYI(0, "name: %s", full_path + namelen);
96 temp = temp->d_parent;
97 if (temp == NULL) {
98 cERROR(1, "corrupt dentry");
99 kfree(full_path);
100 return NULL;
103 if (namelen != pplen + dfsplen) {
104 cERROR(1, "did not end path lookup where expected namelen is %d",
105 namelen);
106 /* presumably this is only possible if racing with a rename
107 of one of the parent directories (we can not lock the dentries
108 above us to prevent this, but retrying should be harmless) */
109 kfree(full_path);
110 goto cifs_bp_rename_retry;
112 /* DIR_SEP already set for byte 0 / vs \ but not for
113 subsequent slashes in prepath which currently must
114 be entered the right way - not sure if there is an alternative
115 since the '\' is a valid posix character so we can not switch
116 those safely to '/' if any are found in the middle of the prepath */
117 /* BB test paths to Windows with '/' in the midst of prepath */
119 if (dfsplen) {
120 strncpy(full_path, tcon->treeName, dfsplen);
121 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
122 int i;
123 for (i = 0; i < dfsplen; i++) {
124 if (full_path[i] == '\\')
125 full_path[i] = '/';
129 strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
130 return full_path;
133 struct cifsFileInfo *
134 cifs_new_fileinfo(__u16 fileHandle, struct file *file,
135 struct tcon_link *tlink, __u32 oplock)
137 struct dentry *dentry = file->f_path.dentry;
138 struct inode *inode = dentry->d_inode;
139 struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
140 struct cifsFileInfo *pCifsFile;
142 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
143 if (pCifsFile == NULL)
144 return pCifsFile;
146 pCifsFile->netfid = fileHandle;
147 pCifsFile->pid = current->tgid;
148 pCifsFile->uid = current_fsuid();
149 pCifsFile->dentry = dget(dentry);
150 pCifsFile->f_flags = file->f_flags;
151 pCifsFile->invalidHandle = false;
152 pCifsFile->closePend = false;
153 pCifsFile->tlink = cifs_get_tlink(tlink);
154 mutex_init(&pCifsFile->fh_mutex);
155 mutex_init(&pCifsFile->lock_mutex);
156 INIT_LIST_HEAD(&pCifsFile->llist);
157 atomic_set(&pCifsFile->count, 1);
158 INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
160 write_lock(&GlobalSMBSeslock);
161 list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
162 /* if readable file instance put first in list*/
163 if (file->f_mode & FMODE_READ)
164 list_add(&pCifsFile->flist, &pCifsInode->openFileList);
165 else
166 list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
167 write_unlock(&GlobalSMBSeslock);
169 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
170 pCifsInode->clientCanCacheAll = true;
171 pCifsInode->clientCanCacheRead = true;
172 cFYI(1, "Exclusive Oplock inode %p", inode);
173 } else if ((oplock & 0xF) == OPLOCK_READ)
174 pCifsInode->clientCanCacheRead = true;
176 file->private_data = pCifsFile;
178 return pCifsFile;
181 static void setup_cifs_dentry(struct cifsTconInfo *tcon,
182 struct dentry *direntry,
183 struct inode *newinode)
185 if (tcon->nocase)
186 direntry->d_op = &cifs_ci_dentry_ops;
187 else
188 direntry->d_op = &cifs_dentry_ops;
189 d_instantiate(direntry, newinode);
192 /* Inode operations in similar order to how they appear in Linux file fs.h */
195 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
196 struct nameidata *nd)
198 int rc = -ENOENT;
199 int xid;
200 int create_options = CREATE_NOT_DIR;
201 __u32 oplock = 0;
202 int oflags;
204 * BB below access is probably too much for mknod to request
205 * but we have to do query and setpathinfo so requesting
206 * less could fail (unless we want to request getatr and setatr
207 * permissions (only). At least for POSIX we do not have to
208 * request so much.
210 int desiredAccess = GENERIC_READ | GENERIC_WRITE;
211 __u16 fileHandle;
212 struct cifs_sb_info *cifs_sb;
213 struct tcon_link *tlink;
214 struct cifsTconInfo *tcon;
215 char *full_path = NULL;
216 FILE_ALL_INFO *buf = NULL;
217 struct inode *newinode = NULL;
218 int disposition = FILE_OVERWRITE_IF;
220 xid = GetXid();
222 cifs_sb = CIFS_SB(inode->i_sb);
223 tlink = cifs_sb_tlink(cifs_sb);
224 if (IS_ERR(tlink)) {
225 FreeXid(xid);
226 return PTR_ERR(tlink);
228 tcon = tlink_tcon(tlink);
230 if (oplockEnabled)
231 oplock = REQ_OPLOCK;
233 if (nd && (nd->flags & LOOKUP_OPEN))
234 oflags = nd->intent.open.file->f_flags;
235 else
236 oflags = O_RDONLY | O_CREAT;
238 full_path = build_path_from_dentry(direntry);
239 if (full_path == NULL) {
240 rc = -ENOMEM;
241 goto cifs_create_out;
244 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
245 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
246 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
247 rc = cifs_posix_open(full_path, &newinode,
248 inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
249 /* EIO could indicate that (posix open) operation is not
250 supported, despite what server claimed in capability
251 negotation. EREMOTE indicates DFS junction, which is not
252 handled in posix open */
254 if (rc == 0) {
255 if (newinode == NULL) /* query inode info */
256 goto cifs_create_get_file_info;
257 else /* success, no need to query */
258 goto cifs_create_set_dentry;
259 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
260 (rc != -EOPNOTSUPP) && (rc != -EINVAL))
261 goto cifs_create_out;
262 /* else fallthrough to retry, using older open call, this is
263 case where server does not support this SMB level, and
264 falsely claims capability (also get here for DFS case
265 which should be rare for path not covered on files) */
268 if (nd && (nd->flags & LOOKUP_OPEN)) {
269 /* if the file is going to stay open, then we
270 need to set the desired access properly */
271 desiredAccess = 0;
272 if (OPEN_FMODE(oflags) & FMODE_READ)
273 desiredAccess |= GENERIC_READ; /* is this too little? */
274 if (OPEN_FMODE(oflags) & FMODE_WRITE)
275 desiredAccess |= GENERIC_WRITE;
277 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
278 disposition = FILE_CREATE;
279 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
280 disposition = FILE_OVERWRITE_IF;
281 else if ((oflags & O_CREAT) == O_CREAT)
282 disposition = FILE_OPEN_IF;
283 else
284 cFYI(1, "Create flag not set in create function");
287 /* BB add processing to set equivalent of mode - e.g. via CreateX with
288 ACLs */
290 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
291 if (buf == NULL) {
292 rc = -ENOMEM;
293 goto cifs_create_out;
297 * if we're not using unix extensions, see if we need to set
298 * ATTR_READONLY on the create call
300 if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
301 create_options |= CREATE_OPTION_READONLY;
303 if (tcon->ses->capabilities & CAP_NT_SMBS)
304 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
305 desiredAccess, create_options,
306 &fileHandle, &oplock, buf, cifs_sb->local_nls,
307 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
308 else
309 rc = -EIO; /* no NT SMB support fall into legacy open below */
311 if (rc == -EIO) {
312 /* old server, retry the open legacy style */
313 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
314 desiredAccess, create_options,
315 &fileHandle, &oplock, buf, cifs_sb->local_nls,
316 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
318 if (rc) {
319 cFYI(1, "cifs_create returned 0x%x", rc);
320 goto cifs_create_out;
323 /* If Open reported that we actually created a file
324 then we now have to set the mode if possible */
325 if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
326 struct cifs_unix_set_info_args args = {
327 .mode = mode,
328 .ctime = NO_CHANGE_64,
329 .atime = NO_CHANGE_64,
330 .mtime = NO_CHANGE_64,
331 .device = 0,
334 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
335 args.uid = (__u64) current_fsuid();
336 if (inode->i_mode & S_ISGID)
337 args.gid = (__u64) inode->i_gid;
338 else
339 args.gid = (__u64) current_fsgid();
340 } else {
341 args.uid = NO_CHANGE_64;
342 args.gid = NO_CHANGE_64;
344 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
345 cifs_sb->local_nls,
346 cifs_sb->mnt_cifs_flags &
347 CIFS_MOUNT_MAP_SPECIAL_CHR);
348 } else {
349 /* BB implement mode setting via Windows security
350 descriptors e.g. */
351 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
353 /* Could set r/o dos attribute if mode & 0222 == 0 */
356 cifs_create_get_file_info:
357 /* server might mask mode so we have to query for it */
358 if (tcon->unix_ext)
359 rc = cifs_get_inode_info_unix(&newinode, full_path,
360 inode->i_sb, xid);
361 else {
362 rc = cifs_get_inode_info(&newinode, full_path, buf,
363 inode->i_sb, xid, &fileHandle);
364 if (newinode) {
365 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
366 newinode->i_mode = mode;
367 if ((oplock & CIFS_CREATE_ACTION) &&
368 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
369 newinode->i_uid = current_fsuid();
370 if (inode->i_mode & S_ISGID)
371 newinode->i_gid = inode->i_gid;
372 else
373 newinode->i_gid = current_fsgid();
378 cifs_create_set_dentry:
379 if (rc == 0)
380 setup_cifs_dentry(tcon, direntry, newinode);
381 else
382 cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
384 if (newinode && nd && (nd->flags & LOOKUP_OPEN)) {
385 struct cifsFileInfo *pfile_info;
386 struct file *filp;
388 filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
389 if (IS_ERR(filp)) {
390 rc = PTR_ERR(filp);
391 CIFSSMBClose(xid, tcon, fileHandle);
392 goto cifs_create_out;
395 pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
396 if (pfile_info == NULL) {
397 fput(filp);
398 CIFSSMBClose(xid, tcon, fileHandle);
399 rc = -ENOMEM;
401 } else {
402 CIFSSMBClose(xid, tcon, fileHandle);
405 cifs_create_out:
406 kfree(buf);
407 kfree(full_path);
408 cifs_put_tlink(tlink);
409 FreeXid(xid);
410 return rc;
413 int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
414 dev_t device_number)
416 int rc = -EPERM;
417 int xid;
418 struct cifs_sb_info *cifs_sb;
419 struct tcon_link *tlink;
420 struct cifsTconInfo *pTcon;
421 char *full_path = NULL;
422 struct inode *newinode = NULL;
423 int oplock = 0;
424 u16 fileHandle;
425 FILE_ALL_INFO *buf = NULL;
426 unsigned int bytes_written;
427 struct win_dev *pdev;
429 if (!old_valid_dev(device_number))
430 return -EINVAL;
432 cifs_sb = CIFS_SB(inode->i_sb);
433 tlink = cifs_sb_tlink(cifs_sb);
434 if (IS_ERR(tlink))
435 return PTR_ERR(tlink);
437 pTcon = tlink_tcon(tlink);
439 xid = GetXid();
441 full_path = build_path_from_dentry(direntry);
442 if (full_path == NULL) {
443 rc = -ENOMEM;
444 goto mknod_out;
447 if (pTcon->unix_ext) {
448 struct cifs_unix_set_info_args args = {
449 .mode = mode & ~current_umask(),
450 .ctime = NO_CHANGE_64,
451 .atime = NO_CHANGE_64,
452 .mtime = NO_CHANGE_64,
453 .device = device_number,
455 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
456 args.uid = (__u64) current_fsuid();
457 args.gid = (__u64) current_fsgid();
458 } else {
459 args.uid = NO_CHANGE_64;
460 args.gid = NO_CHANGE_64;
462 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
463 cifs_sb->local_nls,
464 cifs_sb->mnt_cifs_flags &
465 CIFS_MOUNT_MAP_SPECIAL_CHR);
466 if (rc)
467 goto mknod_out;
469 rc = cifs_get_inode_info_unix(&newinode, full_path,
470 inode->i_sb, xid);
471 if (pTcon->nocase)
472 direntry->d_op = &cifs_ci_dentry_ops;
473 else
474 direntry->d_op = &cifs_dentry_ops;
476 if (rc == 0)
477 d_instantiate(direntry, newinode);
478 goto mknod_out;
481 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
482 goto mknod_out;
485 cFYI(1, "sfu compat create special file");
487 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
488 if (buf == NULL) {
489 kfree(full_path);
490 rc = -ENOMEM;
491 FreeXid(xid);
492 return rc;
495 /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */
496 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
497 GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
498 &fileHandle, &oplock, buf, cifs_sb->local_nls,
499 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
500 if (rc)
501 goto mknod_out;
503 /* BB Do not bother to decode buf since no local inode yet to put
504 * timestamps in, but we can reuse it safely */
506 pdev = (struct win_dev *)buf;
507 if (S_ISCHR(mode)) {
508 memcpy(pdev->type, "IntxCHR", 8);
509 pdev->major =
510 cpu_to_le64(MAJOR(device_number));
511 pdev->minor =
512 cpu_to_le64(MINOR(device_number));
513 rc = CIFSSMBWrite(xid, pTcon,
514 fileHandle,
515 sizeof(struct win_dev),
516 0, &bytes_written, (char *)pdev,
517 NULL, 0);
518 } else if (S_ISBLK(mode)) {
519 memcpy(pdev->type, "IntxBLK", 8);
520 pdev->major =
521 cpu_to_le64(MAJOR(device_number));
522 pdev->minor =
523 cpu_to_le64(MINOR(device_number));
524 rc = CIFSSMBWrite(xid, pTcon,
525 fileHandle,
526 sizeof(struct win_dev),
527 0, &bytes_written, (char *)pdev,
528 NULL, 0);
529 } /* else if (S_ISFIFO) */
530 CIFSSMBClose(xid, pTcon, fileHandle);
531 d_drop(direntry);
533 /* FIXME: add code here to set EAs */
535 mknod_out:
536 kfree(full_path);
537 kfree(buf);
538 FreeXid(xid);
539 cifs_put_tlink(tlink);
540 return rc;
543 struct dentry *
544 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
545 struct nameidata *nd)
547 int xid;
548 int rc = 0; /* to get around spurious gcc warning, set to zero here */
549 __u32 oplock = 0;
550 __u16 fileHandle = 0;
551 bool posix_open = false;
552 struct cifs_sb_info *cifs_sb;
553 struct tcon_link *tlink;
554 struct cifsTconInfo *pTcon;
555 struct cifsFileInfo *cfile;
556 struct inode *newInode = NULL;
557 char *full_path = NULL;
558 struct file *filp;
560 xid = GetXid();
562 cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
563 parent_dir_inode, direntry->d_name.name, direntry);
565 /* check whether path exists */
567 cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
568 tlink = cifs_sb_tlink(cifs_sb);
569 if (IS_ERR(tlink)) {
570 FreeXid(xid);
571 return (struct dentry *)tlink;
573 pTcon = tlink_tcon(tlink);
576 * Don't allow the separator character in a path component.
577 * The VFS will not allow "/", but "\" is allowed by posix.
579 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
580 int i;
581 for (i = 0; i < direntry->d_name.len; i++)
582 if (direntry->d_name.name[i] == '\\') {
583 cFYI(1, "Invalid file name");
584 rc = -EINVAL;
585 goto lookup_out;
590 * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
591 * the VFS handle the create.
593 if (nd && (nd->flags & LOOKUP_EXCL)) {
594 d_instantiate(direntry, NULL);
595 rc = 0;
596 goto lookup_out;
599 /* can not grab the rename sem here since it would
600 deadlock in the cases (beginning of sys_rename itself)
601 in which we already have the sb rename sem */
602 full_path = build_path_from_dentry(direntry);
603 if (full_path == NULL) {
604 rc = -ENOMEM;
605 goto lookup_out;
608 if (direntry->d_inode != NULL) {
609 cFYI(1, "non-NULL inode in lookup");
610 } else {
611 cFYI(1, "NULL inode in lookup");
613 cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
615 /* Posix open is only called (at lookup time) for file create now.
616 * For opens (rather than creates), because we do not know if it
617 * is a file or directory yet, and current Samba no longer allows
618 * us to do posix open on dirs, we could end up wasting an open call
619 * on what turns out to be a dir. For file opens, we wait to call posix
620 * open till cifs_open. It could be added here (lookup) in the future
621 * but the performance tradeoff of the extra network request when EISDIR
622 * or EACCES is returned would have to be weighed against the 50%
623 * reduction in network traffic in the other paths.
625 if (pTcon->unix_ext) {
626 if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
627 (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
628 (nd->intent.open.file->f_flags & O_CREAT)) {
629 rc = cifs_posix_open(full_path, &newInode,
630 parent_dir_inode->i_sb,
631 nd->intent.open.create_mode,
632 nd->intent.open.file->f_flags, &oplock,
633 &fileHandle, xid);
635 * The check below works around a bug in POSIX
636 * open in samba versions 3.3.1 and earlier where
637 * open could incorrectly fail with invalid parameter.
638 * If either that or op not supported returned, follow
639 * the normal lookup.
641 if ((rc == 0) || (rc == -ENOENT))
642 posix_open = true;
643 else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
644 pTcon->broken_posix_open = true;
646 if (!posix_open)
647 rc = cifs_get_inode_info_unix(&newInode, full_path,
648 parent_dir_inode->i_sb, xid);
649 } else
650 rc = cifs_get_inode_info(&newInode, full_path, NULL,
651 parent_dir_inode->i_sb, xid, NULL);
653 if ((rc == 0) && (newInode != NULL)) {
654 if (pTcon->nocase)
655 direntry->d_op = &cifs_ci_dentry_ops;
656 else
657 direntry->d_op = &cifs_dentry_ops;
658 d_add(direntry, newInode);
659 if (posix_open) {
660 filp = lookup_instantiate_filp(nd, direntry,
661 generic_file_open);
662 if (IS_ERR(filp)) {
663 rc = PTR_ERR(filp);
664 CIFSSMBClose(xid, pTcon, fileHandle);
665 goto lookup_out;
668 cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
669 oplock);
670 if (cfile == NULL) {
671 fput(filp);
672 CIFSSMBClose(xid, pTcon, fileHandle);
673 rc = -ENOMEM;
674 goto lookup_out;
677 /* since paths are not looked up by component - the parent
678 directories are presumed to be good here */
679 renew_parental_timestamps(direntry);
681 } else if (rc == -ENOENT) {
682 rc = 0;
683 direntry->d_time = jiffies;
684 if (pTcon->nocase)
685 direntry->d_op = &cifs_ci_dentry_ops;
686 else
687 direntry->d_op = &cifs_dentry_ops;
688 d_add(direntry, NULL);
689 /* if it was once a directory (but how can we tell?) we could do
690 shrink_dcache_parent(direntry); */
691 } else if (rc != -EACCES) {
692 cERROR(1, "Unexpected lookup error %d", rc);
693 /* We special case check for Access Denied - since that
694 is a common return code */
697 lookup_out:
698 kfree(full_path);
699 cifs_put_tlink(tlink);
700 FreeXid(xid);
701 return ERR_PTR(rc);
704 static int
705 cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
707 int isValid = 1;
709 if (direntry->d_inode) {
710 if (cifs_revalidate_dentry(direntry))
711 return 0;
712 } else {
713 cFYI(1, "neg dentry 0x%p name = %s",
714 direntry, direntry->d_name.name);
715 if (time_after(jiffies, direntry->d_time + HZ) ||
716 !lookupCacheEnabled) {
717 d_drop(direntry);
718 isValid = 0;
722 return isValid;
725 /* static int cifs_d_delete(struct dentry *direntry)
727 int rc = 0;
729 cFYI(1, "In cifs d_delete, name = %s", direntry->d_name.name);
731 return rc;
732 } */
734 const struct dentry_operations cifs_dentry_ops = {
735 .d_revalidate = cifs_d_revalidate,
736 /* d_delete: cifs_d_delete, */ /* not needed except for debugging */
739 static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
741 struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
742 unsigned long hash;
743 int i;
745 hash = init_name_hash();
746 for (i = 0; i < q->len; i++)
747 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
748 hash);
749 q->hash = end_name_hash(hash);
751 return 0;
754 static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
755 struct qstr *b)
757 struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
759 if ((a->len == b->len) &&
760 (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
762 * To preserve case, don't let an existing negative dentry's
763 * case take precedence. If a is not a negative dentry, this
764 * should have no side effects
766 memcpy((void *)a->name, b->name, a->len);
767 return 0;
769 return 1;
772 const struct dentry_operations cifs_ci_dentry_ops = {
773 .d_revalidate = cifs_d_revalidate,
774 .d_hash = cifs_ci_hash,
775 .d_compare = cifs_ci_compare,