diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 570 |
1 files changed, 357 insertions, 213 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 2e904bd111c8..28a22092d450 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -737,7 +737,7 @@ psx_del_no_retry: | |||
737 | /* ATTRS set to normal clears r/o bit */ | 737 | /* ATTRS set to normal clears r/o bit */ |
738 | pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); | 738 | pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); |
739 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) | 739 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) |
740 | rc = CIFSSMBSetTimes(xid, pTcon, full_path, | 740 | rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, |
741 | pinfo_buf, | 741 | pinfo_buf, |
742 | cifs_sb->local_nls, | 742 | cifs_sb->local_nls, |
743 | cifs_sb->mnt_cifs_flags & | 743 | cifs_sb->mnt_cifs_flags & |
@@ -767,9 +767,10 @@ psx_del_no_retry: | |||
767 | cifs_sb->mnt_cifs_flags & | 767 | cifs_sb->mnt_cifs_flags & |
768 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 768 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
769 | if (rc == 0) { | 769 | if (rc == 0) { |
770 | rc = CIFSSMBSetFileTimes(xid, pTcon, | 770 | rc = CIFSSMBSetFileInfo(xid, pTcon, |
771 | pinfo_buf, | 771 | pinfo_buf, |
772 | netfid); | 772 | netfid, |
773 | current->tgid); | ||
773 | CIFSSMBClose(xid, pTcon, netfid); | 774 | CIFSSMBClose(xid, pTcon, netfid); |
774 | } | 775 | } |
775 | } | 776 | } |
@@ -984,32 +985,41 @@ mkdir_get_info: | |||
984 | * failed to get it from the server or was set bogus */ | 985 | * failed to get it from the server or was set bogus */ |
985 | if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) | 986 | if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) |
986 | direntry->d_inode->i_nlink = 2; | 987 | direntry->d_inode->i_nlink = 2; |
988 | |||
987 | mode &= ~current->fs->umask; | 989 | mode &= ~current->fs->umask; |
990 | /* must turn on setgid bit if parent dir has it */ | ||
991 | if (inode->i_mode & S_ISGID) | ||
992 | mode |= S_ISGID; | ||
993 | |||
988 | if (pTcon->unix_ext) { | 994 | if (pTcon->unix_ext) { |
995 | struct cifs_unix_set_info_args args = { | ||
996 | .mode = mode, | ||
997 | .ctime = NO_CHANGE_64, | ||
998 | .atime = NO_CHANGE_64, | ||
999 | .mtime = NO_CHANGE_64, | ||
1000 | .device = 0, | ||
1001 | }; | ||
989 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 1002 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
990 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 1003 | args.uid = (__u64)current->fsuid; |
991 | mode, | 1004 | if (inode->i_mode & S_ISGID) |
992 | (__u64)current->fsuid, | 1005 | args.gid = (__u64)inode->i_gid; |
993 | (__u64)current->fsgid, | 1006 | else |
994 | 0 /* dev_t */, | 1007 | args.gid = (__u64)current->fsgid; |
995 | cifs_sb->local_nls, | ||
996 | cifs_sb->mnt_cifs_flags & | ||
997 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
998 | } else { | 1008 | } else { |
999 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 1009 | args.uid = NO_CHANGE_64; |
1000 | mode, (__u64)-1, | 1010 | args.gid = NO_CHANGE_64; |
1001 | (__u64)-1, 0 /* dev_t */, | ||
1002 | cifs_sb->local_nls, | ||
1003 | cifs_sb->mnt_cifs_flags & | ||
1004 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1005 | } | 1011 | } |
1012 | CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, | ||
1013 | cifs_sb->local_nls, | ||
1014 | cifs_sb->mnt_cifs_flags & | ||
1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1006 | } else { | 1016 | } else { |
1007 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && | 1017 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && |
1008 | (mode & S_IWUGO) == 0) { | 1018 | (mode & S_IWUGO) == 0) { |
1009 | FILE_BASIC_INFO pInfo; | 1019 | FILE_BASIC_INFO pInfo; |
1010 | memset(&pInfo, 0, sizeof(pInfo)); | 1020 | memset(&pInfo, 0, sizeof(pInfo)); |
1011 | pInfo.Attributes = cpu_to_le32(ATTR_READONLY); | 1021 | pInfo.Attributes = cpu_to_le32(ATTR_READONLY); |
1012 | CIFSSMBSetTimes(xid, pTcon, full_path, | 1022 | CIFSSMBSetPathInfo(xid, pTcon, full_path, |
1013 | &pInfo, cifs_sb->local_nls, | 1023 | &pInfo, cifs_sb->local_nls, |
1014 | cifs_sb->mnt_cifs_flags & | 1024 | cifs_sb->mnt_cifs_flags & |
1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1025 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
@@ -1024,8 +1034,12 @@ mkdir_get_info: | |||
1024 | CIFS_MOUNT_SET_UID) { | 1034 | CIFS_MOUNT_SET_UID) { |
1025 | direntry->d_inode->i_uid = | 1035 | direntry->d_inode->i_uid = |
1026 | current->fsuid; | 1036 | current->fsuid; |
1027 | direntry->d_inode->i_gid = | 1037 | if (inode->i_mode & S_ISGID) |
1028 | current->fsgid; | 1038 | direntry->d_inode->i_gid = |
1039 | inode->i_gid; | ||
1040 | else | ||
1041 | direntry->d_inode->i_gid = | ||
1042 | current->fsgid; | ||
1029 | } | 1043 | } |
1030 | } | 1044 | } |
1031 | } | 1045 | } |
@@ -1310,10 +1324,11 @@ int cifs_revalidate(struct dentry *direntry) | |||
1310 | /* if (S_ISDIR(direntry->d_inode->i_mode)) | 1324 | /* if (S_ISDIR(direntry->d_inode->i_mode)) |
1311 | shrink_dcache_parent(direntry); */ | 1325 | shrink_dcache_parent(direntry); */ |
1312 | if (S_ISREG(direntry->d_inode->i_mode)) { | 1326 | if (S_ISREG(direntry->d_inode->i_mode)) { |
1313 | if (direntry->d_inode->i_mapping) | 1327 | if (direntry->d_inode->i_mapping) { |
1314 | wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); | 1328 | wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); |
1315 | if (wbrc) | 1329 | if (wbrc) |
1316 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; | 1330 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; |
1331 | } | ||
1317 | /* may eventually have to do this for open files too */ | 1332 | /* may eventually have to do this for open files too */ |
1318 | if (list_empty(&(cifsInode->openFileList))) { | 1333 | if (list_empty(&(cifsInode->openFileList))) { |
1319 | /* changed on server - flush read ahead pages */ | 1334 | /* changed on server - flush read ahead pages */ |
@@ -1413,31 +1428,304 @@ out_busy: | |||
1413 | return -ETXTBSY; | 1428 | return -ETXTBSY; |
1414 | } | 1429 | } |
1415 | 1430 | ||
1416 | int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | 1431 | static int |
1432 | cifs_set_file_size(struct inode *inode, struct iattr *attrs, | ||
1433 | int xid, char *full_path) | ||
1417 | { | 1434 | { |
1435 | int rc; | ||
1436 | struct cifsFileInfo *open_file; | ||
1437 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
1438 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1439 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1440 | |||
1441 | /* | ||
1442 | * To avoid spurious oplock breaks from server, in the case of | ||
1443 | * inodes that we already have open, avoid doing path based | ||
1444 | * setting of file size if we can do it by handle. | ||
1445 | * This keeps our caching token (oplock) and avoids timeouts | ||
1446 | * when the local oplock break takes longer to flush | ||
1447 | * writebehind data than the SMB timeout for the SetPathInfo | ||
1448 | * request would allow | ||
1449 | */ | ||
1450 | open_file = find_writable_file(cifsInode); | ||
1451 | if (open_file) { | ||
1452 | __u16 nfid = open_file->netfid; | ||
1453 | __u32 npid = open_file->pid; | ||
1454 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, | ||
1455 | npid, false); | ||
1456 | atomic_dec(&open_file->wrtPending); | ||
1457 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); | ||
1458 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | ||
1459 | unsigned int bytes_written; | ||
1460 | rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, | ||
1461 | &bytes_written, NULL, NULL, 1); | ||
1462 | cFYI(1, ("Wrt seteof rc %d", rc)); | ||
1463 | } | ||
1464 | } else | ||
1465 | rc = -EINVAL; | ||
1466 | |||
1467 | if (rc != 0) { | ||
1468 | /* Set file size by pathname rather than by handle | ||
1469 | either because no valid, writeable file handle for | ||
1470 | it was found or because there was an error setting | ||
1471 | it by handle */ | ||
1472 | rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, | ||
1473 | false, cifs_sb->local_nls, | ||
1474 | cifs_sb->mnt_cifs_flags & | ||
1475 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1476 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); | ||
1477 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | ||
1478 | __u16 netfid; | ||
1479 | int oplock = 0; | ||
1480 | |||
1481 | rc = SMBLegacyOpen(xid, pTcon, full_path, | ||
1482 | FILE_OPEN, GENERIC_WRITE, | ||
1483 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | ||
1484 | cifs_sb->local_nls, | ||
1485 | cifs_sb->mnt_cifs_flags & | ||
1486 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1487 | if (rc == 0) { | ||
1488 | unsigned int bytes_written; | ||
1489 | rc = CIFSSMBWrite(xid, pTcon, netfid, 0, | ||
1490 | attrs->ia_size, | ||
1491 | &bytes_written, NULL, | ||
1492 | NULL, 1); | ||
1493 | cFYI(1, ("wrt seteof rc %d", rc)); | ||
1494 | CIFSSMBClose(xid, pTcon, netfid); | ||
1495 | } | ||
1496 | } | ||
1497 | } | ||
1498 | |||
1499 | if (rc == 0) { | ||
1500 | rc = cifs_vmtruncate(inode, attrs->ia_size); | ||
1501 | cifs_truncate_page(inode->i_mapping, inode->i_size); | ||
1502 | } | ||
1503 | |||
1504 | return rc; | ||
1505 | } | ||
1506 | |||
1507 | static int | ||
1508 | cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, | ||
1509 | char *full_path, __u32 dosattr) | ||
1510 | { | ||
1511 | int rc; | ||
1512 | int oplock = 0; | ||
1513 | __u16 netfid; | ||
1514 | __u32 netpid; | ||
1515 | bool set_time = false; | ||
1516 | struct cifsFileInfo *open_file; | ||
1517 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
1518 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1519 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1520 | FILE_BASIC_INFO info_buf; | ||
1521 | |||
1522 | if (attrs->ia_valid & ATTR_ATIME) { | ||
1523 | set_time = true; | ||
1524 | info_buf.LastAccessTime = | ||
1525 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | ||
1526 | } else | ||
1527 | info_buf.LastAccessTime = 0; | ||
1528 | |||
1529 | if (attrs->ia_valid & ATTR_MTIME) { | ||
1530 | set_time = true; | ||
1531 | info_buf.LastWriteTime = | ||
1532 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
1533 | } else | ||
1534 | info_buf.LastWriteTime = 0; | ||
1535 | |||
1536 | /* | ||
1537 | * Samba throws this field away, but windows may actually use it. | ||
1538 | * Do not set ctime unless other time stamps are changed explicitly | ||
1539 | * (i.e. by utimes()) since we would then have a mix of client and | ||
1540 | * server times. | ||
1541 | */ | ||
1542 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
1543 | cFYI(1, ("CIFS - CTIME changed")); | ||
1544 | info_buf.ChangeTime = | ||
1545 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
1546 | } else | ||
1547 | info_buf.ChangeTime = 0; | ||
1548 | |||
1549 | info_buf.CreationTime = 0; /* don't change */ | ||
1550 | info_buf.Attributes = cpu_to_le32(dosattr); | ||
1551 | |||
1552 | /* | ||
1553 | * If the file is already open for write, just use that fileid | ||
1554 | */ | ||
1555 | open_file = find_writable_file(cifsInode); | ||
1556 | if (open_file) { | ||
1557 | netfid = open_file->netfid; | ||
1558 | netpid = open_file->pid; | ||
1559 | goto set_via_filehandle; | ||
1560 | } | ||
1561 | |||
1562 | /* | ||
1563 | * NT4 apparently returns success on this call, but it doesn't | ||
1564 | * really work. | ||
1565 | */ | ||
1566 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) { | ||
1567 | rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, | ||
1568 | &info_buf, cifs_sb->local_nls, | ||
1569 | cifs_sb->mnt_cifs_flags & | ||
1570 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1571 | if (rc != -EOPNOTSUPP && rc != -EINVAL) | ||
1572 | goto out; | ||
1573 | } | ||
1574 | |||
1575 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
1576 | "times not supported by this server")); | ||
1577 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
1578 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
1579 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1580 | NULL, cifs_sb->local_nls, | ||
1581 | cifs_sb->mnt_cifs_flags & | ||
1582 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1583 | |||
1584 | if (rc != 0) { | ||
1585 | if (rc == -EIO) | ||
1586 | rc = -EINVAL; | ||
1587 | goto out; | ||
1588 | } | ||
1589 | |||
1590 | netpid = current->tgid; | ||
1591 | |||
1592 | set_via_filehandle: | ||
1593 | rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid); | ||
1594 | if (open_file == NULL) | ||
1595 | CIFSSMBClose(xid, pTcon, netfid); | ||
1596 | else | ||
1597 | atomic_dec(&open_file->wrtPending); | ||
1598 | out: | ||
1599 | return rc; | ||
1600 | } | ||
1601 | |||
1602 | static int | ||
1603 | cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | ||
1604 | { | ||
1605 | int rc; | ||
1418 | int xid; | 1606 | int xid; |
1419 | struct cifs_sb_info *cifs_sb; | ||
1420 | struct cifsTconInfo *pTcon; | ||
1421 | char *full_path = NULL; | 1607 | char *full_path = NULL; |
1422 | int rc = -EACCES; | ||
1423 | struct cifsFileInfo *open_file = NULL; | ||
1424 | FILE_BASIC_INFO time_buf; | ||
1425 | bool set_time = false; | ||
1426 | bool set_dosattr = false; | ||
1427 | __u64 mode = 0xFFFFFFFFFFFFFFFFULL; | ||
1428 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; | ||
1429 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; | ||
1430 | struct cifsInodeInfo *cifsInode; | ||
1431 | struct inode *inode = direntry->d_inode; | 1608 | struct inode *inode = direntry->d_inode; |
1609 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
1610 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1611 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1612 | struct cifs_unix_set_info_args *args = NULL; | ||
1613 | |||
1614 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", | ||
1615 | direntry->d_name.name, attrs->ia_valid)); | ||
1616 | |||
1617 | xid = GetXid(); | ||
1618 | |||
1619 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | ||
1620 | /* check if we have permission to change attrs */ | ||
1621 | rc = inode_change_ok(inode, attrs); | ||
1622 | if (rc < 0) | ||
1623 | goto out; | ||
1624 | else | ||
1625 | rc = 0; | ||
1626 | } | ||
1627 | |||
1628 | full_path = build_path_from_dentry(direntry); | ||
1629 | if (full_path == NULL) { | ||
1630 | rc = -ENOMEM; | ||
1631 | goto out; | ||
1632 | } | ||
1633 | |||
1634 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | ||
1635 | /* | ||
1636 | Flush data before changing file size or changing the last | ||
1637 | write time of the file on the server. If the | ||
1638 | flush returns error, store it to report later and continue. | ||
1639 | BB: This should be smarter. Why bother flushing pages that | ||
1640 | will be truncated anyway? Also, should we error out here if | ||
1641 | the flush returns error? | ||
1642 | */ | ||
1643 | rc = filemap_write_and_wait(inode->i_mapping); | ||
1644 | if (rc != 0) { | ||
1645 | cifsInode->write_behind_rc = rc; | ||
1646 | rc = 0; | ||
1647 | } | ||
1648 | } | ||
1649 | |||
1650 | if (attrs->ia_valid & ATTR_SIZE) { | ||
1651 | rc = cifs_set_file_size(inode, attrs, xid, full_path); | ||
1652 | if (rc != 0) | ||
1653 | goto out; | ||
1654 | } | ||
1655 | |||
1656 | /* skip mode change if it's just for clearing setuid/setgid */ | ||
1657 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) | ||
1658 | attrs->ia_valid &= ~ATTR_MODE; | ||
1659 | |||
1660 | args = kmalloc(sizeof(*args), GFP_KERNEL); | ||
1661 | if (args == NULL) { | ||
1662 | rc = -ENOMEM; | ||
1663 | goto out; | ||
1664 | } | ||
1665 | |||
1666 | /* set up the struct */ | ||
1667 | if (attrs->ia_valid & ATTR_MODE) | ||
1668 | args->mode = attrs->ia_mode; | ||
1669 | else | ||
1670 | args->mode = NO_CHANGE_64; | ||
1671 | |||
1672 | if (attrs->ia_valid & ATTR_UID) | ||
1673 | args->uid = attrs->ia_uid; | ||
1674 | else | ||
1675 | args->uid = NO_CHANGE_64; | ||
1676 | |||
1677 | if (attrs->ia_valid & ATTR_GID) | ||
1678 | args->gid = attrs->ia_gid; | ||
1679 | else | ||
1680 | args->gid = NO_CHANGE_64; | ||
1681 | |||
1682 | if (attrs->ia_valid & ATTR_ATIME) | ||
1683 | args->atime = cifs_UnixTimeToNT(attrs->ia_atime); | ||
1684 | else | ||
1685 | args->atime = NO_CHANGE_64; | ||
1686 | |||
1687 | if (attrs->ia_valid & ATTR_MTIME) | ||
1688 | args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime); | ||
1689 | else | ||
1690 | args->mtime = NO_CHANGE_64; | ||
1691 | |||
1692 | if (attrs->ia_valid & ATTR_CTIME) | ||
1693 | args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime); | ||
1694 | else | ||
1695 | args->ctime = NO_CHANGE_64; | ||
1696 | |||
1697 | args->device = 0; | ||
1698 | rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args, | ||
1699 | cifs_sb->local_nls, | ||
1700 | cifs_sb->mnt_cifs_flags & | ||
1701 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1702 | |||
1703 | if (!rc) | ||
1704 | rc = inode_setattr(inode, attrs); | ||
1705 | out: | ||
1706 | kfree(args); | ||
1707 | kfree(full_path); | ||
1708 | FreeXid(xid); | ||
1709 | return rc; | ||
1710 | } | ||
1711 | |||
1712 | static int | ||
1713 | cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | ||
1714 | { | ||
1715 | int xid; | ||
1716 | struct inode *inode = direntry->d_inode; | ||
1717 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1718 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
1719 | char *full_path = NULL; | ||
1720 | int rc = -EACCES; | ||
1721 | __u32 dosattr = 0; | ||
1722 | __u64 mode = NO_CHANGE_64; | ||
1432 | 1723 | ||
1433 | xid = GetXid(); | 1724 | xid = GetXid(); |
1434 | 1725 | ||
1435 | cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", | 1726 | cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", |
1436 | direntry->d_name.name, attrs->ia_valid)); | 1727 | direntry->d_name.name, attrs->ia_valid)); |
1437 | 1728 | ||
1438 | cifs_sb = CIFS_SB(inode->i_sb); | ||
1439 | pTcon = cifs_sb->tcon; | ||
1440 | |||
1441 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1729 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { |
1442 | /* check if we have permission to change attrs */ | 1730 | /* check if we have permission to change attrs */ |
1443 | rc = inode_change_ok(inode, attrs); | 1731 | rc = inode_change_ok(inode, attrs); |
@@ -1453,7 +1741,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1453 | FreeXid(xid); | 1741 | FreeXid(xid); |
1454 | return -ENOMEM; | 1742 | return -ENOMEM; |
1455 | } | 1743 | } |
1456 | cifsInode = CIFS_I(inode); | ||
1457 | 1744 | ||
1458 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | 1745 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { |
1459 | /* | 1746 | /* |
@@ -1472,78 +1759,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1472 | } | 1759 | } |
1473 | 1760 | ||
1474 | if (attrs->ia_valid & ATTR_SIZE) { | 1761 | if (attrs->ia_valid & ATTR_SIZE) { |
1475 | /* To avoid spurious oplock breaks from server, in the case of | 1762 | rc = cifs_set_file_size(inode, attrs, xid, full_path); |
1476 | inodes that we already have open, avoid doing path based | 1763 | if (rc != 0) |
1477 | setting of file size if we can do it by handle. | ||
1478 | This keeps our caching token (oplock) and avoids timeouts | ||
1479 | when the local oplock break takes longer to flush | ||
1480 | writebehind data than the SMB timeout for the SetPathInfo | ||
1481 | request would allow */ | ||
1482 | |||
1483 | open_file = find_writable_file(cifsInode); | ||
1484 | if (open_file) { | ||
1485 | __u16 nfid = open_file->netfid; | ||
1486 | __u32 npid = open_file->pid; | ||
1487 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, | ||
1488 | nfid, npid, false); | ||
1489 | atomic_dec(&open_file->wrtPending); | ||
1490 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); | ||
1491 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | ||
1492 | unsigned int bytes_written; | ||
1493 | rc = CIFSSMBWrite(xid, pTcon, | ||
1494 | nfid, 0, attrs->ia_size, | ||
1495 | &bytes_written, NULL, NULL, | ||
1496 | 1 /* 45 seconds */); | ||
1497 | cFYI(1, ("Wrt seteof rc %d", rc)); | ||
1498 | } | ||
1499 | } else | ||
1500 | rc = -EINVAL; | ||
1501 | |||
1502 | if (rc != 0) { | ||
1503 | /* Set file size by pathname rather than by handle | ||
1504 | either because no valid, writeable file handle for | ||
1505 | it was found or because there was an error setting | ||
1506 | it by handle */ | ||
1507 | rc = CIFSSMBSetEOF(xid, pTcon, full_path, | ||
1508 | attrs->ia_size, false, | ||
1509 | cifs_sb->local_nls, | ||
1510 | cifs_sb->mnt_cifs_flags & | ||
1511 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1512 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); | ||
1513 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | ||
1514 | __u16 netfid; | ||
1515 | int oplock = 0; | ||
1516 | |||
1517 | rc = SMBLegacyOpen(xid, pTcon, full_path, | ||
1518 | FILE_OPEN, GENERIC_WRITE, | ||
1519 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1520 | NULL, cifs_sb->local_nls, | ||
1521 | cifs_sb->mnt_cifs_flags & | ||
1522 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1523 | if (rc == 0) { | ||
1524 | unsigned int bytes_written; | ||
1525 | rc = CIFSSMBWrite(xid, pTcon, | ||
1526 | netfid, 0, | ||
1527 | attrs->ia_size, | ||
1528 | &bytes_written, NULL, | ||
1529 | NULL, 1 /* 45 sec */); | ||
1530 | cFYI(1, ("wrt seteof rc %d", rc)); | ||
1531 | CIFSSMBClose(xid, pTcon, netfid); | ||
1532 | } | ||
1533 | |||
1534 | } | ||
1535 | } | ||
1536 | |||
1537 | /* Server is ok setting allocation size implicitly - no need | ||
1538 | to call: | ||
1539 | CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, true, | ||
1540 | cifs_sb->local_nls); | ||
1541 | */ | ||
1542 | |||
1543 | if (rc == 0) { | ||
1544 | rc = cifs_vmtruncate(inode, attrs->ia_size); | ||
1545 | cifs_truncate_page(inode->i_mapping, inode->i_size); | ||
1546 | } else | ||
1547 | goto cifs_setattr_exit; | 1764 | goto cifs_setattr_exit; |
1548 | } | 1765 | } |
1549 | 1766 | ||
@@ -1554,21 +1771,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1554 | * CIFSACL support + proper Windows to Unix idmapping, we may be | 1771 | * CIFSACL support + proper Windows to Unix idmapping, we may be |
1555 | * able to support this in the future. | 1772 | * able to support this in the future. |
1556 | */ | 1773 | */ |
1557 | if (!pTcon->unix_ext && | 1774 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) |
1558 | !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { | ||
1559 | attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); | 1775 | attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); |
1560 | } else { | ||
1561 | if (attrs->ia_valid & ATTR_UID) { | ||
1562 | cFYI(1, ("UID changed to %d", attrs->ia_uid)); | ||
1563 | uid = attrs->ia_uid; | ||
1564 | } | ||
1565 | if (attrs->ia_valid & ATTR_GID) { | ||
1566 | cFYI(1, ("GID changed to %d", attrs->ia_gid)); | ||
1567 | gid = attrs->ia_gid; | ||
1568 | } | ||
1569 | } | ||
1570 | |||
1571 | time_buf.Attributes = 0; | ||
1572 | 1776 | ||
1573 | /* skip mode change if it's just for clearing setuid/setgid */ | 1777 | /* skip mode change if it's just for clearing setuid/setgid */ |
1574 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) | 1778 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) |
@@ -1579,13 +1783,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1579 | mode = attrs->ia_mode; | 1783 | mode = attrs->ia_mode; |
1580 | } | 1784 | } |
1581 | 1785 | ||
1582 | if ((pTcon->unix_ext) | 1786 | if (attrs->ia_valid & ATTR_MODE) { |
1583 | && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) | ||
1584 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, | ||
1585 | 0 /* dev_t */, cifs_sb->local_nls, | ||
1586 | cifs_sb->mnt_cifs_flags & | ||
1587 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1588 | else if (attrs->ia_valid & ATTR_MODE) { | ||
1589 | rc = 0; | 1787 | rc = 0; |
1590 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1788 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
1591 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | 1789 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) |
@@ -1594,24 +1792,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1594 | #endif | 1792 | #endif |
1595 | if (((mode & S_IWUGO) == 0) && | 1793 | if (((mode & S_IWUGO) == 0) && |
1596 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { | 1794 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { |
1597 | set_dosattr = true; | 1795 | |
1598 | time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs | | 1796 | dosattr = cifsInode->cifsAttrs | ATTR_READONLY; |
1599 | ATTR_READONLY); | 1797 | |
1600 | /* fix up mode if we're not using dynperm */ | 1798 | /* fix up mode if we're not using dynperm */ |
1601 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | 1799 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) |
1602 | attrs->ia_mode = inode->i_mode & ~S_IWUGO; | 1800 | attrs->ia_mode = inode->i_mode & ~S_IWUGO; |
1603 | } else if ((mode & S_IWUGO) && | 1801 | } else if ((mode & S_IWUGO) && |
1604 | (cifsInode->cifsAttrs & ATTR_READONLY)) { | 1802 | (cifsInode->cifsAttrs & ATTR_READONLY)) { |
1605 | /* If file is readonly on server, we would | 1803 | |
1606 | not be able to write to it - so if any write | 1804 | dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; |
1607 | bit is enabled for user or group or other we | 1805 | /* Attributes of 0 are ignored */ |
1608 | need to at least try to remove r/o dos attr */ | 1806 | if (dosattr == 0) |
1609 | set_dosattr = true; | 1807 | dosattr |= ATTR_NORMAL; |
1610 | time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs & | ||
1611 | (~ATTR_READONLY)); | ||
1612 | /* Windows ignores set to zero */ | ||
1613 | if (time_buf.Attributes == 0) | ||
1614 | time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); | ||
1615 | 1808 | ||
1616 | /* reset local inode permissions to normal */ | 1809 | /* reset local inode permissions to normal */ |
1617 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { | 1810 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { |
@@ -1629,82 +1822,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1629 | } | 1822 | } |
1630 | } | 1823 | } |
1631 | 1824 | ||
1632 | if (attrs->ia_valid & ATTR_ATIME) { | 1825 | if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) || |
1633 | set_time = true; | 1826 | ((attrs->ia_valid & ATTR_MODE) && dosattr)) { |
1634 | time_buf.LastAccessTime = | 1827 | rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); |
1635 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | 1828 | /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */ |
1636 | } else | ||
1637 | time_buf.LastAccessTime = 0; | ||
1638 | |||
1639 | if (attrs->ia_valid & ATTR_MTIME) { | ||
1640 | set_time = true; | ||
1641 | time_buf.LastWriteTime = | ||
1642 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
1643 | } else | ||
1644 | time_buf.LastWriteTime = 0; | ||
1645 | /* Do not set ctime explicitly unless other time | ||
1646 | stamps are changed explicitly (i.e. by utime() | ||
1647 | since we would then have a mix of client and | ||
1648 | server times */ | ||
1649 | |||
1650 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
1651 | set_time = true; | ||
1652 | /* Although Samba throws this field away | ||
1653 | it may be useful to Windows - but we do | ||
1654 | not want to set ctime unless some other | ||
1655 | timestamp is changing */ | ||
1656 | cFYI(1, ("CIFS - CTIME changed")); | ||
1657 | time_buf.ChangeTime = | ||
1658 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
1659 | } else | ||
1660 | time_buf.ChangeTime = 0; | ||
1661 | |||
1662 | if (set_time || set_dosattr) { | ||
1663 | time_buf.CreationTime = 0; /* do not change */ | ||
1664 | /* In the future we should experiment - try setting timestamps | ||
1665 | via Handle (SetFileInfo) instead of by path */ | ||
1666 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) | ||
1667 | rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, | ||
1668 | cifs_sb->local_nls, | ||
1669 | cifs_sb->mnt_cifs_flags & | ||
1670 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1671 | else | ||
1672 | rc = -EOPNOTSUPP; | ||
1673 | 1829 | ||
1674 | if (rc == -EOPNOTSUPP) { | ||
1675 | int oplock = 0; | ||
1676 | __u16 netfid; | ||
1677 | |||
1678 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
1679 | "times not supported by this server")); | ||
1680 | /* BB we could scan to see if we already have it open | ||
1681 | and pass in pid of opener to function */ | ||
1682 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
1683 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
1684 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1685 | NULL, cifs_sb->local_nls, | ||
1686 | cifs_sb->mnt_cifs_flags & | ||
1687 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1688 | if (rc == 0) { | ||
1689 | rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf, | ||
1690 | netfid); | ||
1691 | CIFSSMBClose(xid, pTcon, netfid); | ||
1692 | } else { | ||
1693 | /* BB For even older servers we could convert time_buf | ||
1694 | into old DOS style which uses two second | ||
1695 | granularity */ | ||
1696 | |||
1697 | /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path, | ||
1698 | &time_buf, cifs_sb->local_nls); */ | ||
1699 | } | ||
1700 | } | ||
1701 | /* Even if error on time set, no sense failing the call if | 1830 | /* Even if error on time set, no sense failing the call if |
1702 | the server would set the time to a reasonable value anyway, | 1831 | the server would set the time to a reasonable value anyway, |
1703 | and this check ensures that we are not being called from | 1832 | and this check ensures that we are not being called from |
1704 | sys_utimes in which case we ought to fail the call back to | 1833 | sys_utimes in which case we ought to fail the call back to |
1705 | the user when the server rejects the call */ | 1834 | the user when the server rejects the call */ |
1706 | if ((rc) && (attrs->ia_valid & | 1835 | if ((rc) && (attrs->ia_valid & |
1707 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | 1836 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) |
1708 | rc = 0; | 1837 | rc = 0; |
1709 | } | 1838 | } |
1710 | 1839 | ||
@@ -1718,6 +1847,21 @@ cifs_setattr_exit: | |||
1718 | return rc; | 1847 | return rc; |
1719 | } | 1848 | } |
1720 | 1849 | ||
1850 | int | ||
1851 | cifs_setattr(struct dentry *direntry, struct iattr *attrs) | ||
1852 | { | ||
1853 | struct inode *inode = direntry->d_inode; | ||
1854 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1855 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1856 | |||
1857 | if (pTcon->unix_ext) | ||
1858 | return cifs_setattr_unix(direntry, attrs); | ||
1859 | |||
1860 | return cifs_setattr_nounix(direntry, attrs); | ||
1861 | |||
1862 | /* BB: add cifs_setattr_legacy for really old servers */ | ||
1863 | } | ||
1864 | |||
1721 | #if 0 | 1865 | #if 0 |
1722 | void cifs_delete_inode(struct inode *inode) | 1866 | void cifs_delete_inode(struct inode *inode) |
1723 | { | 1867 | { |