mtd: provide an alias for the redboot module name
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / cifs / dir.c
blob16cdd6da227a7a3303e2ded6531b7a73914156db
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 dfsplen;
54 char *full_path;
55 char dirsep;
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;
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 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
67 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
68 else
69 dfsplen = 0;
70 cifs_bp_rename_retry:
71 namelen = dfsplen;
72 seq = read_seqbegin(&rename_lock);
73 rcu_read_lock();
74 for (temp = direntry; !IS_ROOT(temp);) {
75 namelen += (1 + temp->d_name.len);
76 temp = temp->d_parent;
77 if (temp == NULL) {
78 cERROR(1, "corrupt dentry");
79 rcu_read_unlock();
80 return NULL;
83 rcu_read_unlock();
85 full_path = kmalloc(namelen+1, GFP_KERNEL);
86 if (full_path == NULL)
87 return full_path;
88 full_path[namelen] = 0; /* trailing null */
89 rcu_read_lock();
90 for (temp = direntry; !IS_ROOT(temp);) {
91 spin_lock(&temp->d_lock);
92 namelen -= 1 + temp->d_name.len;
93 if (namelen < 0) {
94 spin_unlock(&temp->d_lock);
95 break;
96 } else {
97 full_path[namelen] = dirsep;
98 strncpy(full_path + namelen + 1, temp->d_name.name,
99 temp->d_name.len);
100 cFYI(0, "name: %s", full_path + namelen);
102 spin_unlock(&temp->d_lock);
103 temp = temp->d_parent;
104 if (temp == NULL) {
105 cERROR(1, "corrupt dentry");
106 rcu_read_unlock();
107 kfree(full_path);
108 return NULL;
111 rcu_read_unlock();
112 if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
113 cFYI(1, "did not end path lookup where expected. namelen=%d "
114 "dfsplen=%d", namelen, dfsplen);
115 /* presumably this is only possible if racing with a rename
116 of one of the parent directories (we can not lock the dentries
117 above us to prevent this, but retrying should be harmless) */
118 kfree(full_path);
119 goto cifs_bp_rename_retry;
121 /* DIR_SEP already set for byte 0 / vs \ but not for
122 subsequent slashes in prepath which currently must
123 be entered the right way - not sure if there is an alternative
124 since the '\' is a valid posix character so we can not switch
125 those safely to '/' if any are found in the middle of the prepath */
126 /* BB test paths to Windows with '/' in the midst of prepath */
128 if (dfsplen) {
129 strncpy(full_path, tcon->treeName, dfsplen);
130 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
131 int i;
132 for (i = 0; i < dfsplen; i++) {
133 if (full_path[i] == '\\')
134 full_path[i] = '/';
138 return full_path;
141 /* Inode operations in similar order to how they appear in Linux file fs.h */
144 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
145 struct nameidata *nd)
147 int rc = -ENOENT;
148 int xid;
149 int create_options = CREATE_NOT_DIR;
150 __u32 oplock = 0;
151 int oflags;
153 * BB below access is probably too much for mknod to request
154 * but we have to do query and setpathinfo so requesting
155 * less could fail (unless we want to request getatr and setatr
156 * permissions (only). At least for POSIX we do not have to
157 * request so much.
159 int desiredAccess = GENERIC_READ | GENERIC_WRITE;
160 __u16 fileHandle;
161 struct cifs_sb_info *cifs_sb;
162 struct tcon_link *tlink;
163 struct cifs_tcon *tcon;
164 char *full_path = NULL;
165 FILE_ALL_INFO *buf = NULL;
166 struct inode *newinode = NULL;
167 int disposition = FILE_OVERWRITE_IF;
169 xid = GetXid();
171 cifs_sb = CIFS_SB(inode->i_sb);
172 tlink = cifs_sb_tlink(cifs_sb);
173 if (IS_ERR(tlink)) {
174 FreeXid(xid);
175 return PTR_ERR(tlink);
177 tcon = tlink_tcon(tlink);
179 if (oplockEnabled)
180 oplock = REQ_OPLOCK;
182 if (nd && (nd->flags & LOOKUP_OPEN))
183 oflags = nd->intent.open.file->f_flags;
184 else
185 oflags = O_RDONLY | O_CREAT;
187 full_path = build_path_from_dentry(direntry);
188 if (full_path == NULL) {
189 rc = -ENOMEM;
190 goto cifs_create_out;
193 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
194 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
195 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
196 rc = cifs_posix_open(full_path, &newinode,
197 inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
198 /* EIO could indicate that (posix open) operation is not
199 supported, despite what server claimed in capability
200 negotiation. EREMOTE indicates DFS junction, which is not
201 handled in posix open */
203 if (rc == 0) {
204 if (newinode == NULL) /* query inode info */
205 goto cifs_create_get_file_info;
206 else /* success, no need to query */
207 goto cifs_create_set_dentry;
208 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
209 (rc != -EOPNOTSUPP) && (rc != -EINVAL))
210 goto cifs_create_out;
211 /* else fallthrough to retry, using older open call, this is
212 case where server does not support this SMB level, and
213 falsely claims capability (also get here for DFS case
214 which should be rare for path not covered on files) */
217 if (nd && (nd->flags & LOOKUP_OPEN)) {
218 /* if the file is going to stay open, then we
219 need to set the desired access properly */
220 desiredAccess = 0;
221 if (OPEN_FMODE(oflags) & FMODE_READ)
222 desiredAccess |= GENERIC_READ; /* is this too little? */
223 if (OPEN_FMODE(oflags) & FMODE_WRITE)
224 desiredAccess |= GENERIC_WRITE;
226 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
227 disposition = FILE_CREATE;
228 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
229 disposition = FILE_OVERWRITE_IF;
230 else if ((oflags & O_CREAT) == O_CREAT)
231 disposition = FILE_OPEN_IF;
232 else
233 cFYI(1, "Create flag not set in create function");
236 /* BB add processing to set equivalent of mode - e.g. via CreateX with
237 ACLs */
239 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
240 if (buf == NULL) {
241 rc = -ENOMEM;
242 goto cifs_create_out;
246 * if we're not using unix extensions, see if we need to set
247 * ATTR_READONLY on the create call
249 if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
250 create_options |= CREATE_OPTION_READONLY;
252 if (tcon->ses->capabilities & CAP_NT_SMBS)
253 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
254 desiredAccess, create_options,
255 &fileHandle, &oplock, buf, cifs_sb->local_nls,
256 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
257 else
258 rc = -EIO; /* no NT SMB support fall into legacy open below */
260 if (rc == -EIO) {
261 /* old server, retry the open legacy style */
262 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
263 desiredAccess, create_options,
264 &fileHandle, &oplock, buf, cifs_sb->local_nls,
265 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
267 if (rc) {
268 cFYI(1, "cifs_create returned 0x%x", rc);
269 goto cifs_create_out;
272 /* If Open reported that we actually created a file
273 then we now have to set the mode if possible */
274 if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
275 struct cifs_unix_set_info_args args = {
276 .mode = mode,
277 .ctime = NO_CHANGE_64,
278 .atime = NO_CHANGE_64,
279 .mtime = NO_CHANGE_64,
280 .device = 0,
283 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
284 args.uid = (__u64) current_fsuid();
285 if (inode->i_mode & S_ISGID)
286 args.gid = (__u64) inode->i_gid;
287 else
288 args.gid = (__u64) current_fsgid();
289 } else {
290 args.uid = NO_CHANGE_64;
291 args.gid = NO_CHANGE_64;
293 CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
294 current->tgid);
295 } else {
296 /* BB implement mode setting via Windows security
297 descriptors e.g. */
298 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
300 /* Could set r/o dos attribute if mode & 0222 == 0 */
303 cifs_create_get_file_info:
304 /* server might mask mode so we have to query for it */
305 if (tcon->unix_ext)
306 rc = cifs_get_inode_info_unix(&newinode, full_path,
307 inode->i_sb, xid);
308 else {
309 rc = cifs_get_inode_info(&newinode, full_path, buf,
310 inode->i_sb, xid, &fileHandle);
311 if (newinode) {
312 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
313 newinode->i_mode = mode;
314 if ((oplock & CIFS_CREATE_ACTION) &&
315 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
316 newinode->i_uid = current_fsuid();
317 if (inode->i_mode & S_ISGID)
318 newinode->i_gid = inode->i_gid;
319 else
320 newinode->i_gid = current_fsgid();
325 cifs_create_set_dentry:
326 if (rc == 0)
327 d_instantiate(direntry, newinode);
328 else
329 cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
331 if (newinode && nd && (nd->flags & LOOKUP_OPEN)) {
332 struct cifsFileInfo *pfile_info;
333 struct file *filp;
335 filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
336 if (IS_ERR(filp)) {
337 rc = PTR_ERR(filp);
338 CIFSSMBClose(xid, tcon, fileHandle);
339 goto cifs_create_out;
342 pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
343 if (pfile_info == NULL) {
344 fput(filp);
345 CIFSSMBClose(xid, tcon, fileHandle);
346 rc = -ENOMEM;
348 } else {
349 CIFSSMBClose(xid, tcon, fileHandle);
352 cifs_create_out:
353 kfree(buf);
354 kfree(full_path);
355 cifs_put_tlink(tlink);
356 FreeXid(xid);
357 return rc;
360 int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
361 dev_t device_number)
363 int rc = -EPERM;
364 int xid;
365 struct cifs_sb_info *cifs_sb;
366 struct tcon_link *tlink;
367 struct cifs_tcon *pTcon;
368 struct cifs_io_parms io_parms;
369 char *full_path = NULL;
370 struct inode *newinode = NULL;
371 int oplock = 0;
372 u16 fileHandle;
373 FILE_ALL_INFO *buf = NULL;
374 unsigned int bytes_written;
375 struct win_dev *pdev;
377 if (!old_valid_dev(device_number))
378 return -EINVAL;
380 cifs_sb = CIFS_SB(inode->i_sb);
381 tlink = cifs_sb_tlink(cifs_sb);
382 if (IS_ERR(tlink))
383 return PTR_ERR(tlink);
385 pTcon = tlink_tcon(tlink);
387 xid = GetXid();
389 full_path = build_path_from_dentry(direntry);
390 if (full_path == NULL) {
391 rc = -ENOMEM;
392 goto mknod_out;
395 if (pTcon->unix_ext) {
396 struct cifs_unix_set_info_args args = {
397 .mode = mode & ~current_umask(),
398 .ctime = NO_CHANGE_64,
399 .atime = NO_CHANGE_64,
400 .mtime = NO_CHANGE_64,
401 .device = device_number,
403 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
404 args.uid = (__u64) current_fsuid();
405 args.gid = (__u64) current_fsgid();
406 } else {
407 args.uid = NO_CHANGE_64;
408 args.gid = NO_CHANGE_64;
410 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
411 cifs_sb->local_nls,
412 cifs_sb->mnt_cifs_flags &
413 CIFS_MOUNT_MAP_SPECIAL_CHR);
414 if (rc)
415 goto mknod_out;
417 rc = cifs_get_inode_info_unix(&newinode, full_path,
418 inode->i_sb, xid);
420 if (rc == 0)
421 d_instantiate(direntry, newinode);
422 goto mknod_out;
425 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
426 goto mknod_out;
429 cFYI(1, "sfu compat create special file");
431 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
432 if (buf == NULL) {
433 kfree(full_path);
434 rc = -ENOMEM;
435 FreeXid(xid);
436 return rc;
439 /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */
440 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
441 GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
442 &fileHandle, &oplock, buf, cifs_sb->local_nls,
443 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
444 if (rc)
445 goto mknod_out;
447 /* BB Do not bother to decode buf since no local inode yet to put
448 * timestamps in, but we can reuse it safely */
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);
456 if (S_ISCHR(mode)) {
457 memcpy(pdev->type, "IntxCHR", 8);
458 pdev->major =
459 cpu_to_le64(MAJOR(device_number));
460 pdev->minor =
461 cpu_to_le64(MINOR(device_number));
462 rc = CIFSSMBWrite(xid, &io_parms,
463 &bytes_written, (char *)pdev,
464 NULL, 0);
465 } else if (S_ISBLK(mode)) {
466 memcpy(pdev->type, "IntxBLK", 8);
467 pdev->major =
468 cpu_to_le64(MAJOR(device_number));
469 pdev->minor =
470 cpu_to_le64(MINOR(device_number));
471 rc = CIFSSMBWrite(xid, &io_parms,
472 &bytes_written, (char *)pdev,
473 NULL, 0);
474 } /* else if (S_ISFIFO) */
475 CIFSSMBClose(xid, pTcon, fileHandle);
476 d_drop(direntry);
478 /* FIXME: add code here to set EAs */
480 mknod_out:
481 kfree(full_path);
482 kfree(buf);
483 FreeXid(xid);
484 cifs_put_tlink(tlink);
485 return rc;
488 struct dentry *
489 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
490 struct nameidata *nd)
492 int xid;
493 int rc = 0; /* to get around spurious gcc warning, set to zero here */
494 __u32 oplock = 0;
495 __u16 fileHandle = 0;
496 bool posix_open = false;
497 struct cifs_sb_info *cifs_sb;
498 struct tcon_link *tlink;
499 struct cifs_tcon *pTcon;
500 struct cifsFileInfo *cfile;
501 struct inode *newInode = NULL;
502 char *full_path = NULL;
503 struct file *filp;
505 xid = GetXid();
507 cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
508 parent_dir_inode, direntry->d_name.name, direntry);
510 /* check whether path exists */
512 cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
513 tlink = cifs_sb_tlink(cifs_sb);
514 if (IS_ERR(tlink)) {
515 FreeXid(xid);
516 return (struct dentry *)tlink;
518 pTcon = tlink_tcon(tlink);
521 * Don't allow the separator character in a path component.
522 * The VFS will not allow "/", but "\" is allowed by posix.
524 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
525 int i;
526 for (i = 0; i < direntry->d_name.len; i++)
527 if (direntry->d_name.name[i] == '\\') {
528 cFYI(1, "Invalid file name");
529 rc = -EINVAL;
530 goto lookup_out;
535 * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
536 * the VFS handle the create.
538 if (nd && (nd->flags & LOOKUP_EXCL)) {
539 d_instantiate(direntry, NULL);
540 rc = 0;
541 goto lookup_out;
544 /* can not grab the rename sem here since it would
545 deadlock in the cases (beginning of sys_rename itself)
546 in which we already have the sb rename sem */
547 full_path = build_path_from_dentry(direntry);
548 if (full_path == NULL) {
549 rc = -ENOMEM;
550 goto lookup_out;
553 if (direntry->d_inode != NULL) {
554 cFYI(1, "non-NULL inode in lookup");
555 } else {
556 cFYI(1, "NULL inode in lookup");
558 cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
560 /* Posix open is only called (at lookup time) for file create now.
561 * For opens (rather than creates), because we do not know if it
562 * is a file or directory yet, and current Samba no longer allows
563 * us to do posix open on dirs, we could end up wasting an open call
564 * on what turns out to be a dir. For file opens, we wait to call posix
565 * open till cifs_open. It could be added here (lookup) in the future
566 * but the performance tradeoff of the extra network request when EISDIR
567 * or EACCES is returned would have to be weighed against the 50%
568 * reduction in network traffic in the other paths.
570 if (pTcon->unix_ext) {
571 if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
572 (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
573 (nd->intent.open.file->f_flags & O_CREAT)) {
574 rc = cifs_posix_open(full_path, &newInode,
575 parent_dir_inode->i_sb,
576 nd->intent.open.create_mode,
577 nd->intent.open.file->f_flags, &oplock,
578 &fileHandle, xid);
580 * The check below works around a bug in POSIX
581 * open in samba versions 3.3.1 and earlier where
582 * open could incorrectly fail with invalid parameter.
583 * If either that or op not supported returned, follow
584 * the normal lookup.
586 if ((rc == 0) || (rc == -ENOENT))
587 posix_open = true;
588 else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
589 pTcon->broken_posix_open = true;
591 if (!posix_open)
592 rc = cifs_get_inode_info_unix(&newInode, full_path,
593 parent_dir_inode->i_sb, xid);
594 } else
595 rc = cifs_get_inode_info(&newInode, full_path, NULL,
596 parent_dir_inode->i_sb, xid, NULL);
598 if ((rc == 0) && (newInode != NULL)) {
599 d_add(direntry, newInode);
600 if (posix_open) {
601 filp = lookup_instantiate_filp(nd, direntry,
602 generic_file_open);
603 if (IS_ERR(filp)) {
604 rc = PTR_ERR(filp);
605 CIFSSMBClose(xid, pTcon, fileHandle);
606 goto lookup_out;
609 cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
610 oplock);
611 if (cfile == NULL) {
612 fput(filp);
613 CIFSSMBClose(xid, pTcon, fileHandle);
614 rc = -ENOMEM;
615 goto lookup_out;
618 /* since paths are not looked up by component - the parent
619 directories are presumed to be good here */
620 renew_parental_timestamps(direntry);
622 } else if (rc == -ENOENT) {
623 rc = 0;
624 direntry->d_time = jiffies;
625 d_add(direntry, NULL);
626 /* if it was once a directory (but how can we tell?) we could do
627 shrink_dcache_parent(direntry); */
628 } else if (rc != -EACCES) {
629 cERROR(1, "Unexpected lookup error %d", rc);
630 /* We special case check for Access Denied - since that
631 is a common return code */
634 lookup_out:
635 kfree(full_path);
636 cifs_put_tlink(tlink);
637 FreeXid(xid);
638 return ERR_PTR(rc);
641 static int
642 cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
644 if (nd && (nd->flags & LOOKUP_RCU))
645 return -ECHILD;
647 if (direntry->d_inode) {
648 if (cifs_revalidate_dentry(direntry))
649 return 0;
650 else
651 return 1;
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.
658 if (!nd)
659 return 0;
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.
666 if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
667 if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
668 return 0;
671 if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
672 return 0;
674 return 1;
677 /* static int cifs_d_delete(struct dentry *direntry)
679 int rc = 0;
681 cFYI(1, "In cifs d_delete, name = %s", direntry->d_name.name);
683 return rc;
684 } */
686 const struct dentry_operations cifs_dentry_ops = {
687 .d_revalidate = cifs_d_revalidate,
688 .d_automount = cifs_dfs_d_automount,
689 /* d_delete: cifs_d_delete, */ /* not needed except for debugging */
692 static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
693 struct qstr *q)
695 struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
696 unsigned long hash;
697 int i;
699 hash = init_name_hash();
700 for (i = 0; i < q->len; i++)
701 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
702 hash);
703 q->hash = end_name_hash(hash);
705 return 0;
708 static int cifs_ci_compare(const struct dentry *parent,
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)
713 struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
715 if ((name->len == len) &&
716 (nls_strnicmp(codepage, name->name, str, len) == 0))
717 return 0;
718 return 1;
721 const struct dentry_operations cifs_ci_dentry_ops = {
722 .d_revalidate = cifs_d_revalidate,
723 .d_hash = cifs_ci_hash,
724 .d_compare = cifs_ci_compare,
725 .d_automount = cifs_dfs_d_automount,