diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsglob.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 8 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 20 | ||||
-rw-r--r-- | fs/cifs/link.c | 74 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 1 |
5 files changed, 63 insertions, 44 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a0105c547ffd..8595d498ad80 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -278,6 +278,10 @@ struct smb_version_operations { | |||
278 | /* send rename request */ | 278 | /* send rename request */ |
279 | int (*rename)(const unsigned int, struct cifs_tcon *, const char *, | 279 | int (*rename)(const unsigned int, struct cifs_tcon *, const char *, |
280 | const char *, struct cifs_sb_info *); | 280 | const char *, struct cifs_sb_info *); |
281 | /* send create hardlink request */ | ||
282 | int (*create_hardlink)(const unsigned int, struct cifs_tcon *, | ||
283 | const char *, const char *, | ||
284 | struct cifs_sb_info *); | ||
281 | /* open a file for non-posix mounts */ | 285 | /* open a file for non-posix mounts */ |
282 | int (*open)(const unsigned int, struct cifs_tcon *, const char *, int, | 286 | int (*open)(const unsigned int, struct cifs_tcon *, const char *, int, |
283 | int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *, | 287 | int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *, |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index eecd233c6912..3c50555c7735 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -316,11 +316,9 @@ extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon, | |||
316 | int netfid, const char *target_name, | 316 | int netfid, const char *target_name, |
317 | const struct nls_table *nls_codepage, | 317 | const struct nls_table *nls_codepage, |
318 | int remap_special_chars); | 318 | int remap_special_chars); |
319 | extern int CIFSCreateHardLink(const unsigned int xid, | 319 | extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, |
320 | struct cifs_tcon *tcon, | 320 | const char *from_name, const char *to_name, |
321 | const char *fromName, const char *toName, | 321 | struct cifs_sb_info *cifs_sb); |
322 | const struct nls_table *nls_codepage, | ||
323 | int remap_special_chars); | ||
324 | extern int CIFSUnixCreateHardLink(const unsigned int xid, | 322 | extern int CIFSUnixCreateHardLink(const unsigned int xid, |
325 | struct cifs_tcon *tcon, | 323 | struct cifs_tcon *tcon, |
326 | const char *fromName, const char *toName, | 324 | const char *fromName, const char *toName, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b8cd335d6f11..eb3d2cf76e6e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -2924,8 +2924,8 @@ createHardLinkRetry: | |||
2924 | 2924 | ||
2925 | int | 2925 | int |
2926 | CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, | 2926 | CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, |
2927 | const char *fromName, const char *toName, | 2927 | const char *from_name, const char *to_name, |
2928 | const struct nls_table *nls_codepage, int remap) | 2928 | struct cifs_sb_info *cifs_sb) |
2929 | { | 2929 | { |
2930 | int rc = 0; | 2930 | int rc = 0; |
2931 | NT_RENAME_REQ *pSMB = NULL; | 2931 | NT_RENAME_REQ *pSMB = NULL; |
@@ -2933,6 +2933,7 @@ CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, | |||
2933 | int bytes_returned; | 2933 | int bytes_returned; |
2934 | int name_len, name_len2; | 2934 | int name_len, name_len2; |
2935 | __u16 count; | 2935 | __u16 count; |
2936 | int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; | ||
2936 | 2937 | ||
2937 | cFYI(1, "In CIFSCreateHardLink"); | 2938 | cFYI(1, "In CIFSCreateHardLink"); |
2938 | winCreateHardLinkRetry: | 2939 | winCreateHardLinkRetry: |
@@ -2952,8 +2953,8 @@ winCreateHardLinkRetry: | |||
2952 | 2953 | ||
2953 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2954 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2954 | name_len = | 2955 | name_len = |
2955 | cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName, | 2956 | cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name, |
2956 | PATH_MAX, nls_codepage, remap); | 2957 | PATH_MAX, cifs_sb->local_nls, remap); |
2957 | name_len++; /* trailing null */ | 2958 | name_len++; /* trailing null */ |
2958 | name_len *= 2; | 2959 | name_len *= 2; |
2959 | 2960 | ||
@@ -2962,17 +2963,18 @@ winCreateHardLinkRetry: | |||
2962 | pSMB->OldFileName[name_len + 1] = 0x00; /* pad */ | 2963 | pSMB->OldFileName[name_len + 1] = 0x00; /* pad */ |
2963 | name_len2 = | 2964 | name_len2 = |
2964 | cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], | 2965 | cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], |
2965 | toName, PATH_MAX, nls_codepage, remap); | 2966 | to_name, PATH_MAX, cifs_sb->local_nls, |
2967 | remap); | ||
2966 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; | 2968 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; |
2967 | name_len2 *= 2; /* convert to bytes */ | 2969 | name_len2 *= 2; /* convert to bytes */ |
2968 | } else { /* BB improve the check for buffer overruns BB */ | 2970 | } else { /* BB improve the check for buffer overruns BB */ |
2969 | name_len = strnlen(fromName, PATH_MAX); | 2971 | name_len = strnlen(from_name, PATH_MAX); |
2970 | name_len++; /* trailing null */ | 2972 | name_len++; /* trailing null */ |
2971 | strncpy(pSMB->OldFileName, fromName, name_len); | 2973 | strncpy(pSMB->OldFileName, from_name, name_len); |
2972 | name_len2 = strnlen(toName, PATH_MAX); | 2974 | name_len2 = strnlen(to_name, PATH_MAX); |
2973 | name_len2++; /* trailing null */ | 2975 | name_len2++; /* trailing null */ |
2974 | pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ | 2976 | pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ |
2975 | strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); | 2977 | strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2); |
2976 | name_len2++; /* trailing null */ | 2978 | name_len2++; /* trailing null */ |
2977 | name_len2++; /* signature byte */ | 2979 | name_len2++; /* signature byte */ |
2978 | } | 2980 | } |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index e6ce3b112875..51dc2fb6e854 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -391,72 +391,86 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, | |||
391 | { | 391 | { |
392 | int rc = -EACCES; | 392 | int rc = -EACCES; |
393 | unsigned int xid; | 393 | unsigned int xid; |
394 | char *fromName = NULL; | 394 | char *from_name = NULL; |
395 | char *toName = NULL; | 395 | char *to_name = NULL; |
396 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 396 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
397 | struct tcon_link *tlink; | 397 | struct tcon_link *tlink; |
398 | struct cifs_tcon *pTcon; | 398 | struct cifs_tcon *tcon; |
399 | struct TCP_Server_Info *server; | ||
399 | struct cifsInodeInfo *cifsInode; | 400 | struct cifsInodeInfo *cifsInode; |
400 | 401 | ||
401 | tlink = cifs_sb_tlink(cifs_sb); | 402 | tlink = cifs_sb_tlink(cifs_sb); |
402 | if (IS_ERR(tlink)) | 403 | if (IS_ERR(tlink)) |
403 | return PTR_ERR(tlink); | 404 | return PTR_ERR(tlink); |
404 | pTcon = tlink_tcon(tlink); | 405 | tcon = tlink_tcon(tlink); |
405 | 406 | ||
406 | xid = get_xid(); | 407 | xid = get_xid(); |
407 | 408 | ||
408 | fromName = build_path_from_dentry(old_file); | 409 | from_name = build_path_from_dentry(old_file); |
409 | toName = build_path_from_dentry(direntry); | 410 | to_name = build_path_from_dentry(direntry); |
410 | if ((fromName == NULL) || (toName == NULL)) { | 411 | if ((from_name == NULL) || (to_name == NULL)) { |
411 | rc = -ENOMEM; | 412 | rc = -ENOMEM; |
412 | goto cifs_hl_exit; | 413 | goto cifs_hl_exit; |
413 | } | 414 | } |
414 | 415 | ||
415 | if (pTcon->unix_ext) | 416 | if (tcon->unix_ext) |
416 | rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, | 417 | rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name, |
417 | cifs_sb->local_nls, | 418 | cifs_sb->local_nls, |
418 | cifs_sb->mnt_cifs_flags & | 419 | cifs_sb->mnt_cifs_flags & |
419 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 420 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
420 | else { | 421 | else { |
421 | rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, | 422 | server = tcon->ses->server; |
422 | cifs_sb->local_nls, | 423 | if (!server->ops->create_hardlink) |
423 | cifs_sb->mnt_cifs_flags & | 424 | return -ENOSYS; |
424 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 425 | rc = server->ops->create_hardlink(xid, tcon, from_name, to_name, |
426 | cifs_sb); | ||
425 | if ((rc == -EIO) || (rc == -EINVAL)) | 427 | if ((rc == -EIO) || (rc == -EINVAL)) |
426 | rc = -EOPNOTSUPP; | 428 | rc = -EOPNOTSUPP; |
427 | } | 429 | } |
428 | 430 | ||
429 | d_drop(direntry); /* force new lookup from server of target */ | 431 | d_drop(direntry); /* force new lookup from server of target */ |
430 | 432 | ||
431 | /* if source file is cached (oplocked) revalidate will not go to server | 433 | /* |
432 | until the file is closed or oplock broken so update nlinks locally */ | 434 | * if source file is cached (oplocked) revalidate will not go to server |
435 | * until the file is closed or oplock broken so update nlinks locally | ||
436 | */ | ||
433 | if (old_file->d_inode) { | 437 | if (old_file->d_inode) { |
434 | cifsInode = CIFS_I(old_file->d_inode); | 438 | cifsInode = CIFS_I(old_file->d_inode); |
435 | if (rc == 0) { | 439 | if (rc == 0) { |
436 | spin_lock(&old_file->d_inode->i_lock); | 440 | spin_lock(&old_file->d_inode->i_lock); |
437 | inc_nlink(old_file->d_inode); | 441 | inc_nlink(old_file->d_inode); |
438 | spin_unlock(&old_file->d_inode->i_lock); | 442 | spin_unlock(&old_file->d_inode->i_lock); |
439 | /* BB should we make this contingent on superblock flag NOATIME? */ | 443 | /* |
440 | /* old_file->d_inode->i_ctime = CURRENT_TIME;*/ | 444 | * BB should we make this contingent on superblock flag |
441 | /* parent dir timestamps will update from srv | 445 | * NOATIME? |
442 | within a second, would it really be worth it | 446 | */ |
443 | to set the parent dir cifs inode time to zero | 447 | /* old_file->d_inode->i_ctime = CURRENT_TIME; */ |
444 | to force revalidate (faster) for it too? */ | 448 | /* |
449 | * parent dir timestamps will update from srv within a | ||
450 | * second, would it really be worth it to set the parent | ||
451 | * dir cifs inode time to zero to force revalidate | ||
452 | * (faster) for it too? | ||
453 | */ | ||
445 | } | 454 | } |
446 | /* if not oplocked will force revalidate to get info | 455 | /* |
447 | on source file from srv */ | 456 | * if not oplocked will force revalidate to get info on source |
457 | * file from srv | ||
458 | */ | ||
448 | cifsInode->time = 0; | 459 | cifsInode->time = 0; |
449 | 460 | ||
450 | /* Will update parent dir timestamps from srv within a second. | 461 | /* |
451 | Would it really be worth it to set the parent dir (cifs | 462 | * Will update parent dir timestamps from srv within a second. |
452 | inode) time field to zero to force revalidate on parent | 463 | * Would it really be worth it to set the parent dir (cifs |
453 | directory faster ie | 464 | * inode) time field to zero to force revalidate on parent |
454 | CIFS_I(inode)->time = 0; */ | 465 | * directory faster ie |
466 | * | ||
467 | * CIFS_I(inode)->time = 0; | ||
468 | */ | ||
455 | } | 469 | } |
456 | 470 | ||
457 | cifs_hl_exit: | 471 | cifs_hl_exit: |
458 | kfree(fromName); | 472 | kfree(from_name); |
459 | kfree(toName); | 473 | kfree(to_name); |
460 | free_xid(xid); | 474 | free_xid(xid); |
461 | cifs_put_tlink(tlink); | 475 | cifs_put_tlink(tlink); |
462 | return rc; | 476 | return rc; |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 377392003655..e5d63444f0ff 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -801,6 +801,7 @@ struct smb_version_operations smb1_operations = { | |||
801 | .unlink = CIFSSMBDelFile, | 801 | .unlink = CIFSSMBDelFile, |
802 | .rename_pending_delete = cifs_rename_pending_delete, | 802 | .rename_pending_delete = cifs_rename_pending_delete, |
803 | .rename = CIFSSMBRename, | 803 | .rename = CIFSSMBRename, |
804 | .create_hardlink = CIFSCreateHardLink, | ||
804 | .open = cifs_open_file, | 805 | .open = cifs_open_file, |
805 | .set_fid = cifs_set_fid, | 806 | .set_fid = cifs_set_fid, |
806 | .close = cifs_close_file, | 807 | .close = cifs_close_file, |