Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  *   fs/cifs/dir.c
  3  *
  4  *   vfs operations that deal with dentries
  5  *
  6  *   Copyright (C) International Business Machines  Corp., 2002,2009
  7  *   Author(s): Steve French (sfrench@us.ibm.com)
  8  *
  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.
 13  *
 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.
 18  *
 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
 22  */
 23 #include <linux/fs.h>
 24 #include <linux/stat.h>
 25 #include <linux/slab.h>
 26 #include <linux/namei.h>
 27 #include "cifsfs.h"
 28 #include "cifspdu.h"
 29 #include "cifsglob.h"
 30 #include "cifsproto.h"
 31 #include "cifs_debug.h"
 32 #include "cifs_fs_sb.h"
 33 
 34 static void
 35 renew_parental_timestamps(struct dentry *direntry)
 36 {
 37         /* BB check if there is a way to get the kernel to do this or if we
 38            really need this */
 39         do {
 40                 direntry->d_time = jiffies;
 41                 direntry = direntry->d_parent;
 42         } while (!IS_ROOT(direntry));
 43 }
 44 
 45 /* Note: caller must free return buffer */
 46 char *
 47 build_path_from_dentry(struct dentry *direntry)
 48 {
 49         struct dentry *temp;
 50         int namelen;
 51         int pplen;
 52         int dfsplen;
 53         char *full_path;
 54         char dirsep;
 55         struct cifs_sb_info *cifs_sb;
 56 
 57         if (direntry == NULL)
 58                 return NULL;  /* not much we can do if dentry is freed and
 59                 we need to reopen the file after it was closed implicitly
 60                 when the server crashed */
 61 
 62         cifs_sb = CIFS_SB(direntry->d_sb);
 63         dirsep = CIFS_DIR_SEP(cifs_sb);
 64         pplen = cifs_sb->prepathlen;
 65         if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
 66                 dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
 67         else
 68                 dfsplen = 0;
 69 cifs_bp_rename_retry:
 70         namelen = pplen + dfsplen;
 71         for (temp = direntry; !IS_ROOT(temp);) {
 72                 namelen += (1 + temp->d_name.len);
 73                 temp = temp->d_parent;
 74                 if (temp == NULL) {
 75                         cERROR(1, ("corrupt dentry"));
 76                         return NULL;
 77                 }
 78         }
 79 
 80         full_path = kmalloc(namelen+1, GFP_KERNEL);
 81         if (full_path == NULL)
 82                 return full_path;
 83         full_path[namelen] = 0; /* trailing null */
 84         for (temp = direntry; !IS_ROOT(temp);) {
 85                 namelen -= 1 + temp->d_name.len;
 86                 if (namelen < 0) {
 87                         break;
 88                 } else {
 89                         full_path[namelen] = dirsep;
 90                         strncpy(full_path + namelen + 1, temp->d_name.name,
 91                                 temp->d_name.len);
 92                         cFYI(0, ("name: %s", full_path + namelen));
 93                 }
 94                 temp = temp->d_parent;
 95                 if (temp == NULL) {
 96                         cERROR(1, ("corrupt dentry"));
 97                         kfree(full_path);
 98                         return NULL;
 99                 }
100         }
101         if (namelen != pplen + dfsplen) {
102                 cERROR(1,
103                        ("did not end path lookup where expected namelen is %d",
104                         namelen));
105                 /* presumably this is only possible if racing with a rename
106                 of one of the parent directories  (we can not lock the dentries
107                 above us to prevent this, but retrying should be harmless) */
108                 kfree(full_path);
109                 goto cifs_bp_rename_retry;
110         }
111         /* DIR_SEP already set for byte  0 / vs \ but not for
112            subsequent slashes in prepath which currently must
113            be entered the right way - not sure if there is an alternative
114            since the '\' is a valid posix character so we can not switch
115            those safely to '/' if any are found in the middle of the prepath */
116         /* BB test paths to Windows with '/' in the midst of prepath */
117 
118         if (dfsplen) {
119                 strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
120                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
121                         int i;
122                         for (i = 0; i < dfsplen; i++) {
123                                 if (full_path[i] == '\\')
124                                         full_path[i] = '/';
125                         }
126                 }
127         }
128         strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
129         return full_path;
130 }
131 
132 static void
133 cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
134                         struct cifsTconInfo *tcon, bool write_only)
135 {
136         int oplock = 0;
137         struct cifsFileInfo *pCifsFile;
138         struct cifsInodeInfo *pCifsInode;
139 
140         pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
141 
142         if (pCifsFile == NULL)
143                 return;
144 
145         if (oplockEnabled)
146                 oplock = REQ_OPLOCK;
147 
148         pCifsFile->netfid = fileHandle;
149         pCifsFile->pid = current->tgid;
150         pCifsFile->pInode = newinode;
151         pCifsFile->invalidHandle = false;
152         pCifsFile->closePend = false;
153         mutex_init(&pCifsFile->fh_mutex);
154         mutex_init(&pCifsFile->lock_mutex);
155         INIT_LIST_HEAD(&pCifsFile->llist);
156         atomic_set(&pCifsFile->wrtPending, 0);
157 
158         /* set the following in open now
159                         pCifsFile->pfile = file; */
160         write_lock(&GlobalSMBSeslock);
161         list_add(&pCifsFile->tlist, &tcon->openFileList);
162         pCifsInode = CIFS_I(newinode);
163         if (pCifsInode) {
164                 /* if readable file instance put first in list*/
165                 if (write_only)
166                         list_add_tail(&pCifsFile->flist,
167                                       &pCifsInode->openFileList);
168                 else
169                         list_add(&pCifsFile->flist, &pCifsInode->openFileList);
170 
171                 if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
172                         pCifsInode->clientCanCacheAll = true;
173                         pCifsInode->clientCanCacheRead = true;
174                         cFYI(1, ("Exclusive Oplock inode %p", newinode));
175                 } else if ((oplock & 0xF) == OPLOCK_READ)
176                                 pCifsInode->clientCanCacheRead = true;
177         }
178         write_unlock(&GlobalSMBSeslock);
179 }
180 
181 int cifs_posix_open(char *full_path, struct inode **pinode,
182                     struct super_block *sb, int mode, int oflags,
183                     int *poplock, __u16 *pnetfid, int xid)
184 {
185         int rc;
186         __u32 oplock;
187         bool write_only = false;
188         FILE_UNIX_BASIC_INFO *presp_data;
189         __u32 posix_flags = 0;
190         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
191         struct cifs_fattr fattr;
192 
193         cFYI(1, ("posix open %s", full_path));
194 
195         presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
196         if (presp_data == NULL)
197                 return -ENOMEM;
198 
199 /* So far cifs posix extensions can only map the following flags.
200    There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
201    so far we do not seem to need them, and we can treat them as local only */
202         if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
203                 (FMODE_READ | FMODE_WRITE))
204                 posix_flags = SMB_O_RDWR;
205         else if (oflags & FMODE_READ)
206                 posix_flags = SMB_O_RDONLY;
207         else if (oflags & FMODE_WRITE)
208                 posix_flags = SMB_O_WRONLY;
209         if (oflags & O_CREAT)
210                 posix_flags |= SMB_O_CREAT;
211         if (oflags & O_EXCL)
212                 posix_flags |= SMB_O_EXCL;
213         if (oflags & O_TRUNC)
214                 posix_flags |= SMB_O_TRUNC;
215         if (oflags & O_SYNC)
216                 posix_flags |= SMB_O_SYNC;
217         if (oflags & O_DIRECTORY)
218                 posix_flags |= SMB_O_DIRECTORY;
219         if (oflags & O_NOFOLLOW)
220                 posix_flags |= SMB_O_NOFOLLOW;
221         if (oflags & O_DIRECT)
222                 posix_flags |= SMB_O_DIRECT;
223 
224         if (!(oflags & FMODE_READ))
225                 write_only = true;
226 
227         mode &= ~current_umask();
228         rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
229                         pnetfid, presp_data, &oplock, full_path,
230                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
231                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
232         if (rc)
233                 goto posix_open_ret;
234 
235         if (presp_data->Type == cpu_to_le32(-1))
236                 goto posix_open_ret; /* open ok, caller does qpathinfo */
237 
238         if (!pinode)
239                 goto posix_open_ret; /* caller does not need info */
240 
241         cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb);
242 
243         /* get new inode and set it up */
244         if (*pinode == NULL) {
245                 *pinode = cifs_iget(sb, &fattr);
246                 if (!*pinode) {
247                         rc = -ENOMEM;
248                         goto posix_open_ret;
249                 }
250         } else {
251                 cifs_fattr_to_inode(*pinode, &fattr);
252         }
253 
254         cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
255 
256 posix_open_ret:
257         kfree(presp_data);
258         return rc;
259 }
260 
261 static void setup_cifs_dentry(struct cifsTconInfo *tcon,
262                               struct dentry *direntry,
263                               struct inode *newinode)
264 {
265         if (tcon->nocase)
266                 direntry->d_op = &cifs_ci_dentry_ops;
267         else
268                 direntry->d_op = &cifs_dentry_ops;
269         d_instantiate(direntry, newinode);
270 }
271 
272 /* Inode operations in similar order to how they appear in Linux file fs.h */
273 
274 int
275 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
276                 struct nameidata *nd)
277 {
278         int rc = -ENOENT;
279         int xid;
280         int create_options = CREATE_NOT_DIR;
281         int oplock = 0;
282         int oflags;
283         bool posix_create = false;
284         /*
285          * BB below access is probably too much for mknod to request
286          *    but we have to do query and setpathinfo so requesting
287          *    less could fail (unless we want to request getatr and setatr
288          *    permissions (only).  At least for POSIX we do not have to
289          *    request so much.
290          */
291         int desiredAccess = GENERIC_READ | GENERIC_WRITE;
292         __u16 fileHandle;
293         struct cifs_sb_info *cifs_sb;
294         struct cifsTconInfo *tcon;
295         char *full_path = NULL;
296         FILE_ALL_INFO *buf = NULL;
297         struct inode *newinode = NULL;
298         int disposition = FILE_OVERWRITE_IF;
299         bool write_only = false;
300 
301         xid = GetXid();
302 
303         cifs_sb = CIFS_SB(inode->i_sb);
304         tcon = cifs_sb->tcon;
305 
306         full_path = build_path_from_dentry(direntry);
307         if (full_path == NULL) {
308                 rc = -ENOMEM;
309                 FreeXid(xid);
310                 return rc;
311         }
312 
313         if (oplockEnabled)
314                 oplock = REQ_OPLOCK;
315 
316         if (nd && (nd->flags & LOOKUP_OPEN))
317                 oflags = nd->intent.open.flags;
318         else
319                 oflags = FMODE_READ;
320 
321         if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
322             (CIFS_UNIX_POSIX_PATH_OPS_CAP &
323                         le64_to_cpu(tcon->fsUnixInfo.Capability))) {
324                 rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
325                                      mode, oflags, &oplock, &fileHandle, xid);
326                 /* EIO could indicate that (posix open) operation is not
327                    supported, despite what server claimed in capability
328                    negotation.  EREMOTE indicates DFS junction, which is not
329                    handled in posix open */
330 
331                 if (rc == 0) {
332                         posix_create = true;
333                         if (newinode == NULL) /* query inode info */
334                                 goto cifs_create_get_file_info;
335                         else /* success, no need to query */
336                                 goto cifs_create_set_dentry;
337                 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
338                          (rc != -EOPNOTSUPP) && (rc != -EINVAL))
339                         goto cifs_create_out;
340                 /* else fallthrough to retry, using older open call, this is
341                    case where server does not support this SMB level, and
342                    falsely claims capability (also get here for DFS case
343                    which should be rare for path not covered on files) */
344         }
345 
346         if (nd && (nd->flags & LOOKUP_OPEN)) {
347                 /* if the file is going to stay open, then we
348                    need to set the desired access properly */
349                 desiredAccess = 0;
350                 if (oflags & FMODE_READ)
351                         desiredAccess |= GENERIC_READ; /* is this too little? */
352                 if (oflags & FMODE_WRITE) {
353                         desiredAccess |= GENERIC_WRITE;
354                         if (!(oflags & FMODE_READ))
355                                 write_only = true;
356                 }
357 
358                 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
359                         disposition = FILE_CREATE;
360                 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
361                         disposition = FILE_OVERWRITE_IF;
362                 else if ((oflags & O_CREAT) == O_CREAT)
363                         disposition = FILE_OPEN_IF;
364                 else
365                         cFYI(1, ("Create flag not set in create function"));
366         }
367 
368         /* BB add processing to set equivalent of mode - e.g. via CreateX with
369            ACLs */
370 
371         buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
372         if (buf == NULL) {
373                 kfree(full_path);
374                 FreeXid(xid);
375                 return -ENOMEM;
376         }
377 
378         /*
379          * if we're not using unix extensions, see if we need to set
380          * ATTR_READONLY on the create call
381          */
382         if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
383                 create_options |= CREATE_OPTION_READONLY;
384 
385         if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
386                 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
387                          desiredAccess, create_options,
388                          &fileHandle, &oplock, buf, cifs_sb->local_nls,
389                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
390         else
391                 rc = -EIO; /* no NT SMB support fall into legacy open below */
392 
393         if (rc == -EIO) {
394                 /* old server, retry the open legacy style */
395                 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
396                         desiredAccess, create_options,
397                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
398                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
399         }
400         if (rc) {
401                 cFYI(1, ("cifs_create returned 0x%x", rc));
402                 goto cifs_create_out;
403         }
404 
405         /* If Open reported that we actually created a file
406            then we now have to set the mode if possible */
407         if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
408                 struct cifs_unix_set_info_args args = {
409                                 .mode   = mode,
410                                 .ctime  = NO_CHANGE_64,
411                                 .atime  = NO_CHANGE_64,
412                                 .mtime  = NO_CHANGE_64,
413                                 .device = 0,
414                 };
415 
416                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
417                         args.uid = (__u64) current_fsuid();
418                         if (inode->i_mode & S_ISGID)
419                                 args.gid = (__u64) inode->i_gid;
420                         else
421                                 args.gid = (__u64) current_fsgid();
422                 } else {
423                         args.uid = NO_CHANGE_64;
424                         args.gid = NO_CHANGE_64;
425                 }
426                 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
427                                         cifs_sb->local_nls,
428                                         cifs_sb->mnt_cifs_flags &
429                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
430         } else {
431                 /* BB implement mode setting via Windows security
432                    descriptors e.g. */
433                 /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
434 
435                 /* Could set r/o dos attribute if mode & 0222 == 0 */
436         }
437 
438 cifs_create_get_file_info:
439         /* server might mask mode so we have to query for it */
440         if (tcon->unix_ext)
441                 rc = cifs_get_inode_info_unix(&newinode, full_path,
442                                               inode->i_sb, xid);
443         else {
444                 rc = cifs_get_inode_info(&newinode, full_path, buf,
445                                          inode->i_sb, xid, &fileHandle);
446                 if (newinode) {
447                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
448                                 newinode->i_mode = mode;
449                         if ((oplock & CIFS_CREATE_ACTION) &&
450                             (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
451                                 newinode->i_uid = current_fsuid();
452                                 if (inode->i_mode & S_ISGID)
453                                         newinode->i_gid = inode->i_gid;
454                                 else
455                                         newinode->i_gid = current_fsgid();
456                         }
457                 }
458         }
459 
460 cifs_create_set_dentry:
461         if (rc == 0)
462                 setup_cifs_dentry(tcon, direntry, newinode);
463         else
464                 cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
465 
466         /* nfsd case - nfs srv does not set nd */
467         if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
468                 /* mknod case - do not leave file open */
469                 CIFSSMBClose(xid, tcon, fileHandle);
470         } else if (!(posix_create) && (newinode)) {
471                         cifs_fill_fileinfo(newinode, fileHandle,
472                                         cifs_sb->tcon, write_only);
473         }
474 cifs_create_out:
475         kfree(buf);
476         kfree(full_path);
477         FreeXid(xid);
478         return rc;
479 }
480 
481 int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
482                 dev_t device_number)
483 {
484         int rc = -EPERM;
485         int xid;
486         struct cifs_sb_info *cifs_sb;
487         struct cifsTconInfo *pTcon;
488         char *full_path = NULL;
489         struct inode *newinode = NULL;
490 
491         if (!old_valid_dev(device_number))
492                 return -EINVAL;
493 
494         xid = GetXid();
495 
496         cifs_sb = CIFS_SB(inode->i_sb);
497         pTcon = cifs_sb->tcon;
498 
499         full_path = build_path_from_dentry(direntry);
500         if (full_path == NULL)
501                 rc = -ENOMEM;
502         else if (pTcon->unix_ext) {
503                 struct cifs_unix_set_info_args args = {
504                         .mode   = mode & ~current_umask(),
505                         .ctime  = NO_CHANGE_64,
506                         .atime  = NO_CHANGE_64,
507                         .mtime  = NO_CHANGE_64,
508                         .device = device_number,
509                 };
510                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
511                         args.uid = (__u64) current_fsuid();
512                         args.gid = (__u64) current_fsgid();
513                 } else {
514                         args.uid = NO_CHANGE_64;
515                         args.gid = NO_CHANGE_64;
516                 }
517                 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
518                                             cifs_sb->local_nls,
519                                             cifs_sb->mnt_cifs_flags &
520                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
521 
522                 if (!rc) {
523                         rc = cifs_get_inode_info_unix(&newinode, full_path,
524                                                 inode->i_sb, xid);
525                         if (pTcon->nocase)
526                                 direntry->d_op = &cifs_ci_dentry_ops;
527                         else
528                                 direntry->d_op = &cifs_dentry_ops;
529                         if (rc == 0)
530                                 d_instantiate(direntry, newinode);
531                 }
532         } else {
533                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
534                         int oplock = 0;
535                         u16 fileHandle;
536                         FILE_ALL_INFO *buf;
537 
538                         cFYI(1, ("sfu compat create special file"));
539 
540                         buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
541                         if (buf == NULL) {
542                                 kfree(full_path);
543                                 rc = -ENOMEM;
544                                 FreeXid(xid);
545                                 return rc;
546                         }
547 
548                         rc = CIFSSMBOpen(xid, pTcon, full_path,
549                                          FILE_CREATE, /* fail if exists */
550                                          GENERIC_WRITE /* BB would
551                                           WRITE_OWNER | WRITE_DAC be better? */,
552                                          /* Create a file and set the
553                                             file attribute to SYSTEM */
554                                          CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
555                                          &fileHandle, &oplock, buf,
556                                          cifs_sb->local_nls,
557                                          cifs_sb->mnt_cifs_flags &
558                                             CIFS_MOUNT_MAP_SPECIAL_CHR);
559 
560                         /* BB FIXME - add handling for backlevel servers
561                            which need legacy open and check for all
562                            calls to SMBOpen for fallback to SMBLeagcyOpen */
563                         if (!rc) {
564                                 /* BB Do not bother to decode buf since no
565                                    local inode yet to put timestamps in,
566                                    but we can reuse it safely */
567                                 unsigned int bytes_written;
568                                 struct win_dev *pdev;
569                                 pdev = (struct win_dev *)buf;
570                                 if (S_ISCHR(mode)) {
571                                         memcpy(pdev->type, "IntxCHR", 8);
572                                         pdev->major =
573                                               cpu_to_le64(MAJOR(device_number));
574                                         pdev->minor =
575                                               cpu_to_le64(MINOR(device_number));
576                                         rc = CIFSSMBWrite(xid, pTcon,
577                                                 fileHandle,
578                                                 sizeof(struct win_dev),
579                                                 0, &bytes_written, (char *)pdev,
580                                                 NULL, 0);
581                                 } else if (S_ISBLK(mode)) {
582                                         memcpy(pdev->type, "IntxBLK", 8);
583                                         pdev->major =
584                                               cpu_to_le64(MAJOR(device_number));
585                                         pdev->minor =
586                                               cpu_to_le64(MINOR(device_number));
587                                         rc = CIFSSMBWrite(xid, pTcon,
588                                                 fileHandle,
589                                                 sizeof(struct win_dev),
590                                                 0, &bytes_written, (char *)pdev,
591                                                 NULL, 0);
592                                 } /* else if(S_ISFIFO */
593                                 CIFSSMBClose(xid, pTcon, fileHandle);
594                                 d_drop(direntry);
595                         }
596                         kfree(buf);
597                         /* add code here to set EAs */
598                 }
599         }
600 
601         kfree(full_path);
602         FreeXid(xid);
603         return rc;
604 }
605 
606 struct dentry *
607 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
608             struct nameidata *nd)
609 {
610         int xid;
611         int rc = 0; /* to get around spurious gcc warning, set to zero here */
612         int oplock = 0;
613         __u16 fileHandle = 0;
614         bool posix_open = false;
615         struct cifs_sb_info *cifs_sb;
616         struct cifsTconInfo *pTcon;
617         struct inode *newInode = NULL;
618         char *full_path = NULL;
619         struct file *filp;
620 
621         xid = GetXid();
622 
623         cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
624               parent_dir_inode, direntry->d_name.name, direntry));
625 
626         /* check whether path exists */
627 
628         cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
629         pTcon = cifs_sb->tcon;
630 
631         /*
632          * Don't allow the separator character in a path component.
633          * The VFS will not allow "/", but "\" is allowed by posix.
634          */
635         if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
636                 int i;
637                 for (i = 0; i < direntry->d_name.len; i++)
638                         if (direntry->d_name.name[i] == '\\') {
639                                 cFYI(1, ("Invalid file name"));
640                                 FreeXid(xid);
641                                 return ERR_PTR(-EINVAL);
642                         }
643         }
644 
645         /*
646          * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
647          * the VFS handle the create.
648          */
649         if (nd && (nd->flags & LOOKUP_EXCL)) {
650                 d_instantiate(direntry, NULL);
651                 return 0;
652         }
653 
654         /* can not grab the rename sem here since it would
655         deadlock in the cases (beginning of sys_rename itself)
656         in which we already have the sb rename sem */
657         full_path = build_path_from_dentry(direntry);
658         if (full_path == NULL) {
659                 FreeXid(xid);
660                 return ERR_PTR(-ENOMEM);
661         }
662 
663         if (direntry->d_inode != NULL) {
664                 cFYI(1, ("non-NULL inode in lookup"));
665         } else {
666                 cFYI(1, ("NULL inode in lookup"));
667         }
668         cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
669 
670         /* Posix open is only called (at lookup time) for file create now.
671          * For opens (rather than creates), because we do not know if it
672          * is a file or directory yet, and current Samba no longer allows
673          * us to do posix open on dirs, we could end up wasting an open call
674          * on what turns out to be a dir. For file opens, we wait to call posix
675          * open till cifs_open.  It could be added here (lookup) in the future
676          * but the performance tradeoff of the extra network request when EISDIR
677          * or EACCES is returned would have to be weighed against the 50%
678          * reduction in network traffic in the other paths.
679          */
680         if (pTcon->unix_ext) {
681                 if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
682                      (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
683                      (nd->intent.open.flags & O_CREAT)) {
684                         rc = cifs_posix_open(full_path, &newInode,
685                                         parent_dir_inode->i_sb,
686                                         nd->intent.open.create_mode,
687                                         nd->intent.open.flags, &oplock,
688                                         &fileHandle, xid);
689                         /*
690                          * The check below works around a bug in POSIX
691                          * open in samba versions 3.3.1 and earlier where
692                          * open could incorrectly fail with invalid parameter.
693                          * If either that or op not supported returned, follow
694                          * the normal lookup.
695                          */
696                         if ((rc == 0) || (rc == -ENOENT))
697                                 posix_open = true;
698                         else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
699                                 pTcon->broken_posix_open = true;
700                 }
701                 if (!posix_open)
702                         rc = cifs_get_inode_info_unix(&newInode, full_path,
703                                                 parent_dir_inode->i_sb, xid);
704         } else
705                 rc = cifs_get_inode_info(&newInode, full_path, NULL,
706                                 parent_dir_inode->i_sb, xid, NULL);
707 
708         if ((rc == 0) && (newInode != NULL)) {
709                 if (pTcon->nocase)
710                         direntry->d_op = &cifs_ci_dentry_ops;
711                 else
712                         direntry->d_op = &cifs_dentry_ops;
713                 d_add(direntry, newInode);
714                 if (posix_open)
715                         filp = lookup_instantiate_filp(nd, direntry, NULL);
716                 /* since paths are not looked up by component - the parent
717                    directories are presumed to be good here */
718                 renew_parental_timestamps(direntry);
719 
720         } else if (rc == -ENOENT) {
721                 rc = 0;
722                 direntry->d_time = jiffies;
723                 if (pTcon->nocase)
724                         direntry->d_op = &cifs_ci_dentry_ops;
725                 else
726                         direntry->d_op = &cifs_dentry_ops;
727                 d_add(direntry, NULL);
728         /*      if it was once a directory (but how can we tell?) we could do
729                 shrink_dcache_parent(direntry); */
730         } else if (rc != -EACCES) {
731                 cERROR(1, ("Unexpected lookup error %d", rc));
732                 /* We special case check for Access Denied - since that
733                 is a common return code */
734         }
735 
736         kfree(full_path);
737         FreeXid(xid);
738         return ERR_PTR(rc);
739 }
740 
741 static int
742 cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
743 {
744         int isValid = 1;
745 
746         if (direntry->d_inode) {
747                 if (cifs_revalidate(direntry))
748                         return 0;
749         } else {
750                 cFYI(1, ("neg dentry 0x%p name = %s",
751                          direntry, direntry->d_name.name));
752                 if (time_after(jiffies, direntry->d_time + HZ) ||
753                         !lookupCacheEnabled) {
754                         d_drop(direntry);
755                         isValid = 0;
756                 }
757         }
758 
759         return isValid;
760 }
761 
762 /* static int cifs_d_delete(struct dentry *direntry)
763 {
764         int rc = 0;
765 
766         cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
767 
768         return rc;
769 }     */
770 
771 const struct dentry_operations cifs_dentry_ops = {
772         .d_revalidate = cifs_d_revalidate,
773 /* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
774 };
775 
776 static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
777 {
778         struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
779         unsigned long hash;
780         int i;
781 
782         hash = init_name_hash();
783         for (i = 0; i < q->len; i++)
784                 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
785                                          hash);
786         q->hash = end_name_hash(hash);
787 
788         return 0;
789 }
790 
791 static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
792                            struct qstr *b)
793 {
794         struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
795 
796         if ((a->len == b->len) &&
797             (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
798                 /*
799                  * To preserve case, don't let an existing negative dentry's
800                  * case take precedence.  If a is not a negative dentry, this
801                  * should have no side effects
802                  */
803                 memcpy((void *)a->name, b->name, a->len);
804                 return 0;
805         }
806         return 1;
807 }
808 
809 const struct dentry_operations cifs_ci_dentry_ops = {
810         .d_revalidate = cifs_d_revalidate,
811         .d_hash = cifs_ci_hash,
812         .d_compare = cifs_ci_compare,
813 };
814 
  This page was automatically generated by the LXR engine.