提交 dabcbb1b 编写于 作者: L Linus Torvalds

Merge branch '3.2-without-smb2' of git://git.samba.org/sfrench/cifs-2.6

* '3.2-without-smb2' of git://git.samba.org/sfrench/cifs-2.6: (52 commits)
  Fix build break when freezer not configured
  Add definition for share encryption
  CIFS: Make cifs_push_locks send as many locks at once as possible
  CIFS: Send as many mandatory unlock ranges at once as possible
  CIFS: Implement caching mechanism for posix brlocks
  CIFS: Implement caching mechanism for mandatory brlocks
  CIFS: Fix DFS handling in cifs_get_file_info
  CIFS: Fix error handling in cifs_readv_complete
  [CIFS] Fixup trivial checkpatch warning
  [CIFS] Show nostrictsync and noperm mount options in /proc/mounts
  cifs, freezer: add wait_event_freezekillable and have cifs use it
  cifs: allow cifs_max_pending to be readable under /sys/module/cifs/parameters
  cifs: tune bdi.ra_pages in accordance with the rsize
  cifs: allow for larger rsize= options and change defaults
  cifs: convert cifs_readpages to use async reads
  cifs: add cifs_async_readv
  cifs: fix protocol definition for READ_RSP
  cifs: add a callback function to receive the rest of the frame
  cifs: break out 3rd receive phase into separate function
  cifs: find mid earlier in receive codepath
  ...
...@@ -745,4 +745,18 @@ installed and something like the following lines should be added to the ...@@ -745,4 +745,18 @@ installed and something like the following lines should be added to the
create cifs.spnego * * /usr/local/sbin/cifs.upcall %k create cifs.spnego * * /usr/local/sbin/cifs.upcall %k
create dns_resolver * * /usr/local/sbin/cifs.upcall %k create dns_resolver * * /usr/local/sbin/cifs.upcall %k
CIFS kernel module parameters
=============================
These module parameters can be specified or modified either during the time of
module loading or during the runtime by using the interface
/proc/module/cifs/parameters/<param>
i.e. echo "value" > /sys/module/cifs/parameters/<param>
1. echo_retries - The number of echo attempts before giving up and
reconnecting to the server. The default is 5. The value 0
means never reconnect.
2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
[Y/y/1]. To disable use any of [N/n/0].
...@@ -511,7 +511,7 @@ static const struct file_operations cifsFYI_proc_fops = { ...@@ -511,7 +511,7 @@ static const struct file_operations cifsFYI_proc_fops = {
static int cifs_oplock_proc_show(struct seq_file *m, void *v) static int cifs_oplock_proc_show(struct seq_file *m, void *v)
{ {
seq_printf(m, "%d\n", oplockEnabled); seq_printf(m, "%d\n", enable_oplocks);
return 0; return 0;
} }
...@@ -526,13 +526,16 @@ static ssize_t cifs_oplock_proc_write(struct file *file, ...@@ -526,13 +526,16 @@ static ssize_t cifs_oplock_proc_write(struct file *file,
char c; char c;
int rc; int rc;
printk(KERN_WARNING "CIFS: The /proc/fs/cifs/OplockEnabled interface "
"will be removed in kernel version 3.4. Please migrate to "
"using the 'enable_oplocks' module parameter in cifs.ko.\n");
rc = get_user(c, buffer); rc = get_user(c, buffer);
if (rc) if (rc)
return rc; return rc;
if (c == '0' || c == 'n' || c == 'N') if (c == '0' || c == 'n' || c == 'N')
oplockEnabled = 0; enable_oplocks = false;
else if (c == '1' || c == 'y' || c == 'Y') else if (c == '1' || c == 'y' || c == 'Y')
oplockEnabled = 1; enable_oplocks = true;
return count; return count;
} }
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
#define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */ #define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */
#define CIFS_MOUNT_RWPIDFORWARD 0x80000 /* use pid forwarding for rw */ #define CIFS_MOUNT_RWPIDFORWARD 0x80000 /* use pid forwarding for rw */
#define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */ #define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */
#define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
#define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
struct cifs_sb_info { struct cifs_sb_info {
struct rb_root tlink_tree; struct rb_root tlink_tree;
...@@ -55,6 +57,8 @@ struct cifs_sb_info { ...@@ -55,6 +57,8 @@ struct cifs_sb_info {
atomic_t active; atomic_t active;
uid_t mnt_uid; uid_t mnt_uid;
gid_t mnt_gid; gid_t mnt_gid;
uid_t mnt_backupuid;
gid_t mnt_backupgid;
mode_t mnt_file_mode; mode_t mnt_file_mode;
mode_t mnt_dir_mode; mode_t mnt_dir_mode;
unsigned int mnt_cifs_flags; unsigned int mnt_cifs_flags;
......
...@@ -91,9 +91,76 @@ cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc) ...@@ -91,9 +91,76 @@ cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc)
shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
spin_unlock(&sidgidlock); spin_unlock(&sidgidlock);
root = &siduidtree;
spin_lock(&uidsidlock);
shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
spin_unlock(&uidsidlock);
root = &sidgidtree;
spin_lock(&gidsidlock);
shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
spin_unlock(&gidsidlock);
return nr_rem; return nr_rem;
} }
static void
sid_rb_insert(struct rb_root *root, unsigned long cid,
struct cifs_sid_id **psidid, char *typestr)
{
char *strptr;
struct rb_node *node = root->rb_node;
struct rb_node *parent = NULL;
struct rb_node **linkto = &(root->rb_node);
struct cifs_sid_id *lsidid;
while (node) {
lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
parent = node;
if (cid > lsidid->id) {
linkto = &(node->rb_left);
node = node->rb_left;
}
if (cid < lsidid->id) {
linkto = &(node->rb_right);
node = node->rb_right;
}
}
(*psidid)->id = cid;
(*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
(*psidid)->refcount = 0;
sprintf((*psidid)->sidstr, "%s", typestr);
strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
sprintf(strptr, "%ld", cid);
clear_bit(SID_ID_PENDING, &(*psidid)->state);
clear_bit(SID_ID_MAPPED, &(*psidid)->state);
rb_link_node(&(*psidid)->rbnode, parent, linkto);
rb_insert_color(&(*psidid)->rbnode, root);
}
static struct cifs_sid_id *
sid_rb_search(struct rb_root *root, unsigned long cid)
{
struct rb_node *node = root->rb_node;
struct cifs_sid_id *lsidid;
while (node) {
lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
if (cid > lsidid->id)
node = node->rb_left;
else if (cid < lsidid->id)
node = node->rb_right;
else /* node found */
return lsidid;
}
return NULL;
}
static struct shrinker cifs_shrinker = { static struct shrinker cifs_shrinker = {
.shrink = cifs_idmap_shrinker, .shrink = cifs_idmap_shrinker,
.seeks = DEFAULT_SEEKS, .seeks = DEFAULT_SEEKS,
...@@ -110,6 +177,7 @@ cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) ...@@ -110,6 +177,7 @@ cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
memcpy(payload, data, datalen); memcpy(payload, data, datalen);
key->payload.data = payload; key->payload.data = payload;
key->datalen = datalen;
return 0; return 0;
} }
...@@ -223,6 +291,120 @@ sidid_pending_wait(void *unused) ...@@ -223,6 +291,120 @@ sidid_pending_wait(void *unused)
return signal_pending(current) ? -ERESTARTSYS : 0; return signal_pending(current) ? -ERESTARTSYS : 0;
} }
static int
id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
{
int rc = 0;
struct key *sidkey;
const struct cred *saved_cred;
struct cifs_sid *lsid;
struct cifs_sid_id *psidid, *npsidid;
struct rb_root *cidtree;
spinlock_t *cidlock;
if (sidtype == SIDOWNER) {
cidlock = &siduidlock;
cidtree = &uidtree;
} else if (sidtype == SIDGROUP) {
cidlock = &sidgidlock;
cidtree = &gidtree;
} else
return -EINVAL;
spin_lock(cidlock);
psidid = sid_rb_search(cidtree, cid);
if (!psidid) { /* node does not exist, allocate one & attempt adding */
spin_unlock(cidlock);
npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
if (!npsidid)
return -ENOMEM;
npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
if (!npsidid->sidstr) {
kfree(npsidid);
return -ENOMEM;
}
spin_lock(cidlock);
psidid = sid_rb_search(cidtree, cid);
if (psidid) { /* node happened to get inserted meanwhile */
++psidid->refcount;
spin_unlock(cidlock);
kfree(npsidid->sidstr);
kfree(npsidid);
} else {
psidid = npsidid;
sid_rb_insert(cidtree, cid, &psidid,
sidtype == SIDOWNER ? "oi:" : "gi:");
++psidid->refcount;
spin_unlock(cidlock);
}
} else {
++psidid->refcount;
spin_unlock(cidlock);
}
/*
* If we are here, it is safe to access psidid and its fields
* since a reference was taken earlier while holding the spinlock.
* A reference on the node is put without holding the spinlock
* and it is OK to do so in this case, shrinker will not erase
* this node until all references are put and we do not access
* any fields of the node after a reference is put .
*/
if (test_bit(SID_ID_MAPPED, &psidid->state)) {
memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid));
psidid->time = jiffies; /* update ts for accessing */
goto id_sid_out;
}
if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) {
rc = -EINVAL;
goto id_sid_out;
}
if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
saved_cred = override_creds(root_cred);
sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
if (IS_ERR(sidkey)) {
rc = -EINVAL;
cFYI(1, "%s: Can't map and id to a SID", __func__);
} else {
lsid = (struct cifs_sid *)sidkey->payload.data;
memcpy(&psidid->sid, lsid,
sidkey->datalen < sizeof(struct cifs_sid) ?
sidkey->datalen : sizeof(struct cifs_sid));
memcpy(ssid, &psidid->sid,
sidkey->datalen < sizeof(struct cifs_sid) ?
sidkey->datalen : sizeof(struct cifs_sid));
set_bit(SID_ID_MAPPED, &psidid->state);
key_put(sidkey);
kfree(psidid->sidstr);
}
psidid->time = jiffies; /* update ts for accessing */
revert_creds(saved_cred);
clear_bit(SID_ID_PENDING, &psidid->state);
wake_up_bit(&psidid->state, SID_ID_PENDING);
} else {
rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
sidid_pending_wait, TASK_INTERRUPTIBLE);
if (rc) {
cFYI(1, "%s: sidid_pending_wait interrupted %d",
__func__, rc);
--psidid->refcount;
return rc;
}
if (test_bit(SID_ID_MAPPED, &psidid->state))
memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid));
else
rc = -EINVAL;
}
id_sid_out:
--psidid->refcount;
return rc;
}
static int static int
sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
struct cifs_fattr *fattr, uint sidtype) struct cifs_fattr *fattr, uint sidtype)
...@@ -383,6 +565,10 @@ init_cifs_idmap(void) ...@@ -383,6 +565,10 @@ init_cifs_idmap(void)
spin_lock_init(&sidgidlock); spin_lock_init(&sidgidlock);
gidtree = RB_ROOT; gidtree = RB_ROOT;
spin_lock_init(&uidsidlock);
siduidtree = RB_ROOT;
spin_lock_init(&gidsidlock);
sidgidtree = RB_ROOT;
register_shrinker(&cifs_shrinker); register_shrinker(&cifs_shrinker);
cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring)); cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
...@@ -422,6 +608,18 @@ cifs_destroy_idmaptrees(void) ...@@ -422,6 +608,18 @@ cifs_destroy_idmaptrees(void)
while ((node = rb_first(root))) while ((node = rb_first(root)))
rb_erase(node, root); rb_erase(node, root);
spin_unlock(&sidgidlock); spin_unlock(&sidgidlock);
root = &siduidtree;
spin_lock(&uidsidlock);
while ((node = rb_first(root)))
rb_erase(node, root);
spin_unlock(&uidsidlock);
root = &sidgidtree;
spin_lock(&gidsidlock);
while ((node = rb_first(root)))
rb_erase(node, root);
spin_unlock(&gidsidlock);
} }
/* if the two SIDs (roughly equivalent to a UUID for a user or group) are /* if the two SIDs (roughly equivalent to a UUID for a user or group) are
...@@ -706,7 +904,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, ...@@ -706,7 +904,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
acl_size = sizeof(struct cifs_acl); acl_size = sizeof(struct cifs_acl);
num_aces = le32_to_cpu(pdacl->num_aces); num_aces = le32_to_cpu(pdacl->num_aces);
if (num_aces > 0) { if (num_aces > 0) {
umode_t user_mask = S_IRWXU; umode_t user_mask = S_IRWXU;
umode_t group_mask = S_IRWXG; umode_t group_mask = S_IRWXG;
umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
...@@ -868,52 +1066,82 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, ...@@ -868,52 +1066,82 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
else else
cFYI(1, "no ACL"); /* BB grant all or default perms? */ cFYI(1, "no ACL"); /* BB grant all or default perms? */
/* cifscred->uid = owner_sid_ptr->rid;
cifscred->gid = group_sid_ptr->rid;
memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
sizeof(struct cifs_sid));
memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
sizeof(struct cifs_sid)); */
return rc; return rc;
} }
/* Convert permission bits from mode to equivalent CIFS ACL */ /* Convert permission bits from mode to equivalent CIFS ACL */
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
struct inode *inode, __u64 nmode) __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
{ {
int rc = 0; int rc = 0;
__u32 dacloffset; __u32 dacloffset;
__u32 ndacloffset; __u32 ndacloffset;
__u32 sidsoffset; __u32 sidsoffset;
struct cifs_sid *owner_sid_ptr, *group_sid_ptr; struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */ struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL)) if (nmode != NO_CHANGE_64) { /* chmod */
return -EIO; owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
le32_to_cpu(pntsd->osidoffset)); le32_to_cpu(pntsd->osidoffset));
group_sid_ptr = (struct cifs_sid *)((char *)pntsd + group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
le32_to_cpu(pntsd->gsidoffset)); le32_to_cpu(pntsd->gsidoffset));
dacloffset = le32_to_cpu(pntsd->dacloffset);
dacloffset = le32_to_cpu(pntsd->dacloffset); dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); ndacloffset = sizeof(struct cifs_ntsd);
ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
ndacloffset = sizeof(struct cifs_ntsd); ndacl_ptr->revision = dacl_ptr->revision;
ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset); ndacl_ptr->size = 0;
ndacl_ptr->revision = dacl_ptr->revision; ndacl_ptr->num_aces = 0;
ndacl_ptr->size = 0;
ndacl_ptr->num_aces = 0; rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
nmode);
rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode); sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
/* copy sec desc control portion & owner and group sids */
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); copy_sec_desc(pntsd, pnntsd, sidsoffset);
*aclflag = CIFS_ACL_DACL;
/* copy security descriptor control portion and owner and group sid */ } else {
copy_sec_desc(pntsd, pnntsd, sidsoffset); memcpy(pnntsd, pntsd, secdesclen);
if (uid != NO_CHANGE_32) { /* chown */
owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
le32_to_cpu(pnntsd->osidoffset));
nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
GFP_KERNEL);
if (!nowner_sid_ptr)
return -ENOMEM;
rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
if (rc) {
cFYI(1, "%s: Mapping error %d for owner id %d",
__func__, rc, uid);
kfree(nowner_sid_ptr);
return rc;
}
memcpy(owner_sid_ptr, nowner_sid_ptr,
sizeof(struct cifs_sid));
kfree(nowner_sid_ptr);
*aclflag = CIFS_ACL_OWNER;
}
if (gid != NO_CHANGE_32) { /* chgrp */
group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
le32_to_cpu(pnntsd->gsidoffset));
ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
GFP_KERNEL);
if (!ngroup_sid_ptr)
return -ENOMEM;
rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
if (rc) {
cFYI(1, "%s: Mapping error %d for group id %d",
__func__, rc, gid);
kfree(ngroup_sid_ptr);
return rc;
}
memcpy(group_sid_ptr, ngroup_sid_ptr,
sizeof(struct cifs_sid));
kfree(ngroup_sid_ptr);
*aclflag = CIFS_ACL_GROUP;
}
}
return rc; return rc;
} }
...@@ -945,7 +1173,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, ...@@ -945,7 +1173,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
{ {
struct cifs_ntsd *pntsd = NULL; struct cifs_ntsd *pntsd = NULL;
int oplock = 0; int oplock = 0;
int xid, rc; int xid, rc, create_options = 0;
__u16 fid; __u16 fid;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
...@@ -956,9 +1184,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, ...@@ -956,9 +1184,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
xid = GetXid(); xid = GetXid();
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0, if (backup_cred(cifs_sb))
&fid, &oplock, NULL, cifs_sb->local_nls, create_options |= CREATE_OPEN_BACKUP_INTENT;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) { if (!rc) {
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
CIFSSMBClose(xid, tcon, fid); CIFSSMBClose(xid, tcon, fid);
...@@ -991,13 +1222,15 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, ...@@ -991,13 +1222,15 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
return pntsd; return pntsd;
} }
static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, /* Set an ACL on the server */
struct cifs_ntsd *pnntsd, u32 acllen) int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
struct inode *inode, const char *path, int aclflag)
{ {
int oplock = 0; int oplock = 0;
int xid, rc; int xid, rc, access_flags, create_options = 0;
__u16 fid; __u16 fid;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) if (IS_ERR(tlink))
...@@ -1006,15 +1239,23 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, ...@@ -1006,15 +1239,23 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
xid = GetXid(); xid = GetXid();
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0, if (backup_cred(cifs_sb))
&fid, &oplock, NULL, cifs_sb->local_nls, create_options |= CREATE_OPEN_BACKUP_INTENT;
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
access_flags = WRITE_OWNER;
else
access_flags = WRITE_DAC;
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) { if (rc) {
cERROR(1, "Unable to open file to set ACL"); cERROR(1, "Unable to open file to set ACL");
goto out; goto out;
} }
rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen); rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
cFYI(DBG2, "SetCIFSACL rc = %d", rc); cFYI(DBG2, "SetCIFSACL rc = %d", rc);
CIFSSMBClose(xid, tcon, fid); CIFSSMBClose(xid, tcon, fid);
...@@ -1024,17 +1265,6 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, ...@@ -1024,17 +1265,6 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
return rc; return rc;
} }
/* Set an ACL on the server */
int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
struct inode *inode, const char *path)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
}
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
int int
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
...@@ -1066,9 +1296,12 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, ...@@ -1066,9 +1296,12 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
} }
/* Convert mode bits to an ACL so we can update the ACL on the server */ /* Convert mode bits to an ACL so we can update the ACL on the server */
int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode) int
id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
uid_t uid, gid_t gid)
{ {
int rc = 0; int rc = 0;
int aclflag = CIFS_ACL_DACL; /* default flag to set */
__u32 secdesclen = 0; __u32 secdesclen = 0;
struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
...@@ -1098,13 +1331,15 @@ int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode) ...@@ -1098,13 +1331,15 @@ int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
return -ENOMEM; return -ENOMEM;
} }
rc = build_sec_desc(pntsd, pnntsd, inode, nmode); rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
&aclflag);
cFYI(DBG2, "build_sec_desc rc: %d", rc); cFYI(DBG2, "build_sec_desc rc: %d", rc);
if (!rc) { if (!rc) {
/* Set the security descriptor */ /* Set the security descriptor */
rc = set_cifs_acl(pnntsd, secdesclen, inode, path); rc = set_cifs_acl(pnntsd, secdesclen, inode,
path, aclflag);
cFYI(DBG2, "set_cifs_acl rc: %d", rc); cFYI(DBG2, "set_cifs_acl rc: %d", rc);
} }
......
...@@ -37,83 +37,8 @@ ...@@ -37,83 +37,8 @@
* the sequence number before this function is called. Also, this function * the sequence number before this function is called. Also, this function
* should be called with the server->srv_mutex held. * should be called with the server->srv_mutex held.
*/ */
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, static int cifs_calc_signature(const struct kvec *iov, int n_vec,
struct TCP_Server_Info *server, char *signature) struct TCP_Server_Info *server, char *signature)
{
int rc;
if (cifs_pdu == NULL || signature == NULL || server == NULL)
return -EINVAL;
if (!server->secmech.sdescmd5) {
cERROR(1, "%s: Can't generate signature\n", __func__);
return -1;
}
rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
if (rc) {
cERROR(1, "%s: Could not init md5\n", __func__);
return rc;
}
rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
server->session_key.response, server->session_key.len);
if (rc) {
cERROR(1, "%s: Could not update with response\n", __func__);
return rc;
}
rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
cifs_pdu->Protocol, be32_to_cpu(cifs_pdu->smb_buf_length));
if (rc) {
cERROR(1, "%s: Could not update with payload\n", __func__);
return rc;
}
rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
if (rc)
cERROR(1, "%s: Could not generate md5 hash\n", __func__);
return rc;
}
/* must be called with server->srv_mutex held */
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number)
{
int rc = 0;
char smb_signature[20];
if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL;
if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
server->tcpStatus == CifsNeedNegotiate)
return rc;
if (!server->session_estab) {
strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
return rc;
}
cifs_pdu->Signature.Sequence.SequenceNumber =
cpu_to_le32(server->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;
*pexpected_response_sequence_number = server->sequence_number++;
server->sequence_number++;
rc = cifs_calculate_signature(cifs_pdu, server, smb_signature);
if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else
memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
return rc;
}
static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
struct TCP_Server_Info *server, char *signature)
{ {
int i; int i;
int rc; int rc;
...@@ -179,7 +104,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, ...@@ -179,7 +104,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
{ {
int rc = 0; int rc = 0;
char smb_signature[20]; char smb_signature[20];
struct smb_hdr *cifs_pdu = iov[0].iov_base; struct smb_hdr *cifs_pdu = (struct smb_hdr *)iov[0].iov_base;
if ((cifs_pdu == NULL) || (server == NULL)) if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL; return -EINVAL;
...@@ -189,7 +114,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, ...@@ -189,7 +114,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
return rc; return rc;
if (!server->session_estab) { if (!server->session_estab) {
strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8); memcpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
return rc; return rc;
} }
...@@ -200,7 +125,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, ...@@ -200,7 +125,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
*pexpected_response_sequence_number = server->sequence_number++; *pexpected_response_sequence_number = server->sequence_number++;
server->sequence_number++; server->sequence_number++;
rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); rc = cifs_calc_signature(iov, n_vec, server, smb_signature);
if (rc) if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8); memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else else
...@@ -209,13 +134,27 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, ...@@ -209,13 +134,27 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
return rc; return rc;
} }
int cifs_verify_signature(struct smb_hdr *cifs_pdu, /* must be called with server->srv_mutex held */
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number)
{
struct kvec iov;
iov.iov_base = cifs_pdu;
iov.iov_len = be32_to_cpu(cifs_pdu->smb_buf_length) + 4;
return cifs_sign_smb2(&iov, 1, server,
pexpected_response_sequence_number);
}
int cifs_verify_signature(struct kvec *iov, unsigned int nr_iov,
struct TCP_Server_Info *server, struct TCP_Server_Info *server,
__u32 expected_sequence_number) __u32 expected_sequence_number)
{ {
unsigned int rc; unsigned int rc;
char server_response_sig[8]; char server_response_sig[8];
char what_we_think_sig_should_be[20]; char what_we_think_sig_should_be[20];
struct smb_hdr *cifs_pdu = (struct smb_hdr *)iov[0].iov_base;
if (cifs_pdu == NULL || server == NULL) if (cifs_pdu == NULL || server == NULL)
return -EINVAL; return -EINVAL;
...@@ -247,8 +186,8 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, ...@@ -247,8 +186,8 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
cifs_pdu->Signature.Sequence.Reserved = 0; cifs_pdu->Signature.Sequence.Reserved = 0;
mutex_lock(&server->srv_mutex); mutex_lock(&server->srv_mutex);
rc = cifs_calculate_signature(cifs_pdu, server, rc = cifs_calc_signature(iov, nr_iov, server,
what_we_think_sig_should_be); what_we_think_sig_should_be);
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
if (rc) if (rc)
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
int cifsFYI = 0; int cifsFYI = 0;
int cifsERROR = 1; int cifsERROR = 1;
int traceSMB = 0; int traceSMB = 0;
unsigned int oplockEnabled = 1; bool enable_oplocks = true;
unsigned int linuxExtEnabled = 1; unsigned int linuxExtEnabled = 1;
unsigned int lookupCacheEnabled = 1; unsigned int lookupCacheEnabled = 1;
unsigned int multiuser_mount = 0; unsigned int multiuser_mount = 0;
...@@ -74,7 +74,7 @@ module_param(cifs_min_small, int, 0); ...@@ -74,7 +74,7 @@ module_param(cifs_min_small, int, 0);
MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
"Range: 2 to 256"); "Range: 2 to 256");
unsigned int cifs_max_pending = CIFS_MAX_REQ; unsigned int cifs_max_pending = CIFS_MAX_REQ;
module_param(cifs_max_pending, int, 0); module_param(cifs_max_pending, int, 0444);
MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
"Default: 50 Range: 2 to 256"); "Default: 50 Range: 2 to 256");
unsigned short echo_retries = 5; unsigned short echo_retries = 5;
...@@ -82,6 +82,10 @@ module_param(echo_retries, ushort, 0644); ...@@ -82,6 +82,10 @@ module_param(echo_retries, ushort, 0644);
MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
"reconnecting server. Default: 5. 0 means " "reconnecting server. Default: 5. 0 means "
"never reconnect."); "never reconnect.");
module_param(enable_oplocks, bool, 0644);
MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
"y/Y/1");
extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_req_poolp;
extern mempool_t *cifs_mid_poolp; extern mempool_t *cifs_mid_poolp;
...@@ -132,12 +136,12 @@ cifs_read_super(struct super_block *sb) ...@@ -132,12 +136,12 @@ cifs_read_super(struct super_block *sb)
else else
sb->s_d_op = &cifs_dentry_ops; sb->s_d_op = &cifs_dentry_ops;
#ifdef CIFS_NFSD_EXPORT #ifdef CONFIG_CIFS_NFSD_EXPORT
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
cFYI(1, "export ops supported"); cFYI(1, "export ops supported");
sb->s_export_op = &cifs_export_ops; sb->s_export_op = &cifs_export_ops;
} }
#endif /* CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
return 0; return 0;
...@@ -432,6 +436,12 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) ...@@ -432,6 +436,12 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
seq_printf(s, ",mfsymlinks"); seq_printf(s, ",mfsymlinks");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
seq_printf(s, ",fsc"); seq_printf(s, ",fsc");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)
seq_printf(s, ",nostrictsync");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
seq_printf(s, ",noperm");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
seq_printf(s, ",strictcache");
seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",rsize=%d", cifs_sb->rsize);
seq_printf(s, ",wsize=%d", cifs_sb->wsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize);
...@@ -530,7 +540,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) ...@@ -530,7 +540,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
char *full_path = NULL; char *full_path = NULL;
char *s, *p; char *s, *p;
char sep; char sep;
int xid;
full_path = cifs_build_path_to_root(vol, cifs_sb, full_path = cifs_build_path_to_root(vol, cifs_sb,
cifs_sb_master_tcon(cifs_sb)); cifs_sb_master_tcon(cifs_sb));
...@@ -539,7 +548,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) ...@@ -539,7 +548,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
cFYI(1, "Get root dentry for %s", full_path); cFYI(1, "Get root dentry for %s", full_path);
xid = GetXid();
sep = CIFS_DIR_SEP(cifs_sb); sep = CIFS_DIR_SEP(cifs_sb);
dentry = dget(sb->s_root); dentry = dget(sb->s_root);
p = s = full_path; p = s = full_path;
...@@ -570,7 +578,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) ...@@ -570,7 +578,6 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
dput(dentry); dput(dentry);
dentry = child; dentry = child;
} while (!IS_ERR(dentry)); } while (!IS_ERR(dentry));
_FreeXid(xid);
kfree(full_path); kfree(full_path);
return dentry; return dentry;
} }
...@@ -942,7 +949,8 @@ cifs_init_once(void *inode) ...@@ -942,7 +949,8 @@ cifs_init_once(void *inode)
struct cifsInodeInfo *cifsi = inode; struct cifsInodeInfo *cifsi = inode;
inode_init_once(&cifsi->vfs_inode); inode_init_once(&cifsi->vfs_inode);
INIT_LIST_HEAD(&cifsi->lockList); INIT_LIST_HEAD(&cifsi->llist);
mutex_init(&cifsi->lock_mutex);
} }
static int static int
......
...@@ -121,9 +121,9 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); ...@@ -121,9 +121,9 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
#ifdef CIFS_NFSD_EXPORT #ifdef CONFIG_CIFS_NFSD_EXPORT
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
#endif /* CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "1.75" #define CIFS_VERSION "1.75"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -167,6 +167,8 @@ struct smb_vol { ...@@ -167,6 +167,8 @@ struct smb_vol {
uid_t cred_uid; uid_t cred_uid;
uid_t linux_uid; uid_t linux_uid;
gid_t linux_gid; gid_t linux_gid;
uid_t backupuid;
gid_t backupgid;
mode_t file_mode; mode_t file_mode;
mode_t dir_mode; mode_t dir_mode;
unsigned secFlg; unsigned secFlg;
...@@ -179,6 +181,8 @@ struct smb_vol { ...@@ -179,6 +181,8 @@ struct smb_vol {
bool noperm:1; bool noperm:1;
bool no_psx_acl:1; /* set if posix acl support should be disabled */ bool no_psx_acl:1; /* set if posix acl support should be disabled */
bool cifs_acl:1; bool cifs_acl:1;
bool backupuid_specified; /* mount option backupuid is specified */
bool backupgid_specified; /* mount option backupgid is specified */
bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
bool server_ino:1; /* use inode numbers from server ie UniqueId */ bool server_ino:1; /* use inode numbers from server ie UniqueId */
bool direct_io:1; bool direct_io:1;
...@@ -219,7 +223,8 @@ struct smb_vol { ...@@ -219,7 +223,8 @@ struct smb_vol {
CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \ CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \
CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \ CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \
CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \ CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \
CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO) CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID)
#define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \ #define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \
MS_NODEV | MS_SYNCHRONOUS) MS_NODEV | MS_SYNCHRONOUS)
...@@ -286,7 +291,13 @@ struct TCP_Server_Info { ...@@ -286,7 +291,13 @@ struct TCP_Server_Info {
bool sec_kerberosu2u; /* supports U2U Kerberos */ bool sec_kerberosu2u; /* supports U2U Kerberos */
bool sec_kerberos; /* supports plain Kerberos */ bool sec_kerberos; /* supports plain Kerberos */
bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */
bool large_buf; /* is current buffer large? */
struct delayed_work echo; /* echo ping workqueue job */ struct delayed_work echo; /* echo ping workqueue job */
struct kvec *iov; /* reusable kvec array for receives */
unsigned int nr_iov; /* number of kvecs in array */
char *smallbuf; /* pointer to current "small" buffer */
char *bigbuf; /* pointer to current "big" buffer */
unsigned int total_read; /* total amount of data read in this pass */
#ifdef CONFIG_CIFS_FSCACHE #ifdef CONFIG_CIFS_FSCACHE
struct fscache_cookie *fscache; /* client index cache cookie */ struct fscache_cookie *fscache; /* client index cache cookie */
#endif #endif
...@@ -485,9 +496,13 @@ extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb); ...@@ -485,9 +496,13 @@ extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
*/ */
struct cifsLockInfo { struct cifsLockInfo {
struct list_head llist; /* pointer to next cifsLockInfo */ struct list_head llist; /* pointer to next cifsLockInfo */
struct list_head blist; /* pointer to locks blocked on this */
wait_queue_head_t block_q;
__u64 offset; __u64 offset;
__u64 length; __u64 length;
__u32 pid;
__u8 type; __u8 type;
__u16 netfid;
}; };
/* /*
...@@ -520,8 +535,6 @@ struct cifsFileInfo { ...@@ -520,8 +535,6 @@ struct cifsFileInfo {
struct dentry *dentry; struct dentry *dentry;
unsigned int f_flags; unsigned int f_flags;
struct tcon_link *tlink; struct tcon_link *tlink;
struct mutex lock_mutex;
struct list_head llist; /* list of byte range locks we have. */
bool invalidHandle:1; /* file closed via session abend */ bool invalidHandle:1; /* file closed via session abend */
bool oplock_break_cancelled:1; bool oplock_break_cancelled:1;
int count; /* refcount protected by cifs_file_list_lock */ int count; /* refcount protected by cifs_file_list_lock */
...@@ -554,7 +567,9 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file); ...@@ -554,7 +567,9 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
*/ */
struct cifsInodeInfo { struct cifsInodeInfo {
struct list_head lockList; struct list_head llist; /* brlocks for this inode */
bool can_cache_brlcks;
struct mutex lock_mutex; /* protect two fields above */
/* BB add in lists for dirty pages i.e. write caching info for oplock */ /* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList; struct list_head openFileList;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
...@@ -643,8 +658,24 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon, ...@@ -643,8 +658,24 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
struct mid_q_entry; struct mid_q_entry;
/* /*
* This is the prototype for the mid callback function. When creating one, * This is the prototype for the mid receive function. This function is for
* take special care to avoid deadlocks. Things to bear in mind: * receiving the rest of the SMB frame, starting with the WordCount (which is
* just after the MID in struct smb_hdr). Note:
*
* - This will be called by cifsd, with no locks held.
* - The mid will still be on the pending_mid_q.
* - mid->resp_buf will point to the current buffer.
*
* Returns zero on a successful receive, or an error. The receive state in
* the TCP_Server_Info will also be updated.
*/
typedef int (mid_receive_t)(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
/*
* This is the prototype for the mid callback function. This is called once the
* mid has been received off of the socket. When creating one, take special
* care to avoid deadlocks. Things to bear in mind:
* *
* - it will be called by cifsd, with no locks held * - it will be called by cifsd, with no locks held
* - the mid will be removed from any lists * - the mid will be removed from any lists
...@@ -662,9 +693,10 @@ struct mid_q_entry { ...@@ -662,9 +693,10 @@ struct mid_q_entry {
unsigned long when_sent; /* time when smb send finished */ unsigned long when_sent; /* time when smb send finished */
unsigned long when_received; /* when demux complete (taken off wire) */ unsigned long when_received; /* when demux complete (taken off wire) */
#endif #endif
mid_receive_t *receive; /* call receive callback */
mid_callback_t *callback; /* call completion callback */ mid_callback_t *callback; /* call completion callback */
void *callback_data; /* general purpose pointer for callback */ void *callback_data; /* general purpose pointer for callback */
struct smb_hdr *resp_buf; /* response buffer */ struct smb_hdr *resp_buf; /* pointer to received SMB header */
int midState; /* wish this were enum but can not pass to wait_event */ int midState; /* wish this were enum but can not pass to wait_event */
__u8 command; /* smb command code */ __u8 command; /* smb command code */
bool largeBuf:1; /* if valid response, is pointer to large buf */ bool largeBuf:1; /* if valid response, is pointer to large buf */
...@@ -964,7 +996,8 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions ...@@ -964,7 +996,8 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
to be established on existing mount if we to be established on existing mount if we
have the uid/password or Kerberos credential have the uid/password or Kerberos credential
or equivalent for current user */ or equivalent for current user */
GLOBAL_EXTERN unsigned int oplockEnabled; /* enable or disable oplocks */
GLOBAL_EXTERN bool enable_oplocks;
GLOBAL_EXTERN unsigned int lookupCacheEnabled; GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */ with more secure ntlmssp2 challenge/resp */
...@@ -978,10 +1011,16 @@ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ ...@@ -978,10 +1011,16 @@ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
/* reconnect after this many failed echo attempts */ /* reconnect after this many failed echo attempts */
GLOBAL_EXTERN unsigned short echo_retries; GLOBAL_EXTERN unsigned short echo_retries;
#ifdef CONFIG_CIFS_ACL
GLOBAL_EXTERN struct rb_root uidtree; GLOBAL_EXTERN struct rb_root uidtree;
GLOBAL_EXTERN struct rb_root gidtree; GLOBAL_EXTERN struct rb_root gidtree;
GLOBAL_EXTERN spinlock_t siduidlock; GLOBAL_EXTERN spinlock_t siduidlock;
GLOBAL_EXTERN spinlock_t sidgidlock; GLOBAL_EXTERN spinlock_t sidgidlock;
GLOBAL_EXTERN struct rb_root siduidtree;
GLOBAL_EXTERN struct rb_root sidgidtree;
GLOBAL_EXTERN spinlock_t uidsidlock;
GLOBAL_EXTERN spinlock_t gidsidlock;
#endif /* CONFIG_CIFS_ACL */
void cifs_oplock_break(struct work_struct *work); void cifs_oplock_break(struct work_struct *work);
......
...@@ -1089,9 +1089,7 @@ typedef struct smb_com_read_rsp { ...@@ -1089,9 +1089,7 @@ typedef struct smb_com_read_rsp {
__le16 DataLengthHigh; __le16 DataLengthHigh;
__u64 Reserved2; __u64 Reserved2;
__u16 ByteCount; __u16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD /* read response data immediately follows */
boundary and optimum performance here */
char Data[1];
} __attribute__((packed)) READ_RSP; } __attribute__((packed)) READ_RSP;
typedef struct locking_andx_range { typedef struct locking_andx_range {
...@@ -1913,6 +1911,10 @@ typedef struct whoami_rsp_data { /* Query level 0x202 */ ...@@ -1913,6 +1911,10 @@ typedef struct whoami_rsp_data { /* Query level 0x202 */
/* SETFSInfo Levels */ /* SETFSInfo Levels */
#define SMB_SET_CIFS_UNIX_INFO 0x200 #define SMB_SET_CIFS_UNIX_INFO 0x200
/* level 0x203 is defined above in list of QFS info levels */
/* #define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203 */
/* Level 0x200 request structure follows */
typedef struct smb_com_transaction2_setfsi_req { typedef struct smb_com_transaction2_setfsi_req {
struct smb_hdr hdr; /* wct = 15 */ struct smb_hdr hdr; /* wct = 15 */
__le16 TotalParameterCount; __le16 TotalParameterCount;
...@@ -1940,13 +1942,39 @@ typedef struct smb_com_transaction2_setfsi_req { ...@@ -1940,13 +1942,39 @@ typedef struct smb_com_transaction2_setfsi_req {
__le64 ClientUnixCap; /* Data end */ __le64 ClientUnixCap; /* Data end */
} __attribute__((packed)) TRANSACTION2_SETFSI_REQ; } __attribute__((packed)) TRANSACTION2_SETFSI_REQ;
/* level 0x203 request structure follows */
typedef struct smb_com_transaction2_setfs_enc_req {
struct smb_hdr hdr; /* wct = 15 */
__le16 TotalParameterCount;
__le16 TotalDataCount;
__le16 MaxParameterCount;
__le16 MaxDataCount;
__u8 MaxSetupCount;
__u8 Reserved;
__le16 Flags;
__le32 Timeout;
__u16 Reserved2;
__le16 ParameterCount; /* 4 */
__le16 ParameterOffset;
__le16 DataCount; /* 12 */
__le16 DataOffset;
__u8 SetupCount; /* one */
__u8 Reserved3;
__le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */
__le16 ByteCount;
__u8 Pad;
__u16 Reserved4; /* Parameters start. */
__le16 InformationLevel;/* Parameters end. */
/* NTLMSSP Blob, Data start. */
} __attribute__((packed)) TRANSACTION2_SETFSI_ENC_REQ;
/* response for setfsinfo levels 0x200 and 0x203 */
typedef struct smb_com_transaction2_setfsi_rsp { typedef struct smb_com_transaction2_setfsi_rsp {
struct smb_hdr hdr; /* wct = 10 */ struct smb_hdr hdr; /* wct = 10 */
struct trans2_resp t2; struct trans2_resp t2;
__u16 ByteCount; __u16 ByteCount;
} __attribute__((packed)) TRANSACTION2_SETFSI_RSP; } __attribute__((packed)) TRANSACTION2_SETFSI_RSP;
typedef struct smb_com_transaction2_get_dfs_refer_req { typedef struct smb_com_transaction2_get_dfs_refer_req {
struct smb_hdr hdr; /* wct = 15 */ struct smb_hdr hdr; /* wct = 15 */
__le16 TotalParameterCount; __le16 TotalParameterCount;
...@@ -2098,13 +2126,13 @@ typedef struct { ...@@ -2098,13 +2126,13 @@ typedef struct {
#define CIFS_UNIX_PROXY_CAP 0x00000400 /* Proxy cap: 0xACE ioctl and #define CIFS_UNIX_PROXY_CAP 0x00000400 /* Proxy cap: 0xACE ioctl and
QFS PROXY call */ QFS PROXY call */
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
/* Can not set pathnames cap yet until we send new posix create SMB since /* presumably don't need the 0x20 POSIX_PATH_OPS_CAP since we never send
otherwise server can treat such handles opened with older ntcreatex LockingX instead of posix locking call on unix sess (and we do not expect
(by a new client which knows how to send posix path ops) LockingX to use different (ie Windows) semantics than posix locking on
as non-posix handles (can affect write behavior with byte range locks. the same session (if WINE needs to do this later, we can add this cap
We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */ back in later */
/* #define CIFS_UNIX_CAP_MASK 0x000000fb */ /* #define CIFS_UNIX_CAP_MASK 0x000000fb */
#define CIFS_UNIX_CAP_MASK 0x000000db #define CIFS_UNIX_CAP_MASK 0x000003db
#else #else
#define CIFS_UNIX_CAP_MASK 0x00000013 #define CIFS_UNIX_CAP_MASK 0x00000013
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
......
...@@ -69,8 +69,9 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, ...@@ -69,8 +69,9 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
struct TCP_Server_Info *server); struct TCP_Server_Info *server);
extern void DeleteMidQEntry(struct mid_q_entry *midEntry); extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
unsigned int nvec, mid_callback_t *callback, unsigned int nvec, mid_receive_t *receive,
void *cbdata, bool ignore_pend); mid_callback_t *callback, void *cbdata,
bool ignore_pend);
extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *, extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
...@@ -90,6 +91,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid, ...@@ -90,6 +91,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern bool is_valid_oplock_break(struct smb_hdr *smb, extern bool is_valid_oplock_break(struct smb_hdr *smb,
struct TCP_Server_Info *); struct TCP_Server_Info *);
extern bool backup_cred(struct cifs_sb_info *);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written); unsigned int bytes_written);
...@@ -145,12 +147,19 @@ extern int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -145,12 +147,19 @@ extern int cifs_get_inode_info_unix(struct inode **pinode,
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct inode *inode, struct cifs_fattr *fattr, struct inode *inode,
const char *path, const __u16 *pfid); const char *path, const __u16 *pfid);
extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64); extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
uid_t, gid_t);
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
const char *, u32 *); const char *, u32 *);
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
const char *); const char *, int);
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
unsigned int to_read);
extern int cifs_readv_from_socket(struct TCP_Server_Info *server,
struct kvec *iov_orig, unsigned int nr_segs,
unsigned int to_read);
extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
struct cifs_sb_info *cifs_sb); struct cifs_sb_info *cifs_sb);
extern int cifs_match_super(struct super_block *, void *); extern int cifs_match_super(struct super_block *, void *);
...@@ -359,14 +368,17 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon, ...@@ -359,14 +368,17 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
const __u8 lock_type, const __u32 num_unlock,
const __u32 num_lock, LOCKING_ANDX_RANGE *buf);
extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon, extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
const __u16 netfid, const __u64 len, const __u16 netfid, const __u32 netpid, const __u64 len,
const __u64 offset, const __u32 numUnlock, const __u64 offset, const __u32 numUnlock,
const __u32 numLock, const __u8 lockType, const __u32 numLock, const __u8 lockType,
const bool waitFlag, const __u8 oplock_level); const bool waitFlag, const __u8 oplock_level);
extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
const __u16 smb_file_id, const int get_flag, const __u16 smb_file_id, const __u32 netpid,
const __u64 len, struct file_lock *, const int get_flag, const __u64 len, struct file_lock *,
const __u16 lock_type, const bool waitFlag); const __u16 lock_type, const bool waitFlag);
extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon); extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon);
extern int CIFSSMBEcho(struct TCP_Server_Info *server); extern int CIFSSMBEcho(struct TCP_Server_Info *server);
...@@ -380,7 +392,7 @@ extern void tconInfoFree(struct cifs_tcon *); ...@@ -380,7 +392,7 @@ extern void tconInfoFree(struct cifs_tcon *);
extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
__u32 *); __u32 *);
extern int cifs_verify_signature(struct smb_hdr *, extern int cifs_verify_signature(struct kvec *iov, unsigned int nr_iov,
struct TCP_Server_Info *server, struct TCP_Server_Info *server,
__u32 expected_sequence_number); __u32 expected_sequence_number);
extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *); extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
...@@ -419,7 +431,7 @@ extern int CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, ...@@ -419,7 +431,7 @@ extern int CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon,
extern int CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, extern int CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon,
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen); __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
extern int CIFSSMBSetCIFSACL(const int, struct cifs_tcon *, __u16, extern int CIFSSMBSetCIFSACL(const int, struct cifs_tcon *, __u16,
struct cifs_ntsd *, __u32); struct cifs_ntsd *, __u32, int);
extern int CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon, extern int CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
const unsigned char *searchName, const unsigned char *searchName,
char *acl_inf, const int buflen, const int acl_type, char *acl_inf, const int buflen, const int acl_type,
...@@ -440,6 +452,24 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16); ...@@ -440,6 +452,24 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16);
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
unsigned char *p24); unsigned char *p24);
/* asynchronous read support */
struct cifs_readdata {
struct cifsFileInfo *cfile;
struct address_space *mapping;
__u64 offset;
unsigned int bytes;
pid_t pid;
int result;
struct list_head pages;
struct work_struct work;
unsigned int nr_iov;
struct kvec iov[1];
};
struct cifs_readdata *cifs_readdata_alloc(unsigned int nr_pages);
void cifs_readdata_free(struct cifs_readdata *rdata);
int cifs_async_readv(struct cifs_readdata *rdata);
/* asynchronous write support */ /* asynchronous write support */
struct cifs_writedata { struct cifs_writedata {
struct kref refcount; struct kref refcount;
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/posix_acl_xattr.h> #include <linux/posix_acl_xattr.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/swap.h>
#include <linux/task_io_accounting_ops.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "cifspdu.h" #include "cifspdu.h"
#include "cifsglob.h" #include "cifsglob.h"
...@@ -40,6 +42,7 @@ ...@@ -40,6 +42,7 @@
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#include "fscache.h"
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
static struct { static struct {
...@@ -83,6 +86,9 @@ static struct { ...@@ -83,6 +86,9 @@ static struct {
#endif /* CONFIG_CIFS_WEAK_PW_HASH */ #endif /* CONFIG_CIFS_WEAK_PW_HASH */
#endif /* CIFS_POSIX */ #endif /* CIFS_POSIX */
/* Forward declarations */
static void cifs_readv_complete(struct work_struct *work);
/* Mark as invalid, all open files on tree connections since they /* Mark as invalid, all open files on tree connections since they
were closed when session to server was lost */ were closed when session to server was lost */
static void mark_open_files_invalid(struct cifs_tcon *pTcon) static void mark_open_files_invalid(struct cifs_tcon *pTcon)
...@@ -453,8 +459,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) ...@@ -453,8 +459,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
} }
server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode); server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
server->maxReq = le16_to_cpu(rsp->MaxMpxCount); server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
/* even though we do not use raw we might as well set this /* even though we do not use raw we might as well set this
accurately, in case we ever find a need for it */ accurately, in case we ever find a need for it */
...@@ -561,8 +566,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) ...@@ -561,8 +566,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
little endian */ little endian */
server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
/* probably no need to store and check maxvcs */ /* probably no need to store and check maxvcs */
server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
server->capabilities = le32_to_cpu(pSMBr->Capabilities); server->capabilities = le32_to_cpu(pSMBr->Capabilities);
...@@ -739,7 +743,8 @@ CIFSSMBEcho(struct TCP_Server_Info *server) ...@@ -739,7 +743,8 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
iov.iov_base = smb; iov.iov_base = smb;
iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true); rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
server, true);
if (rc) if (rc)
cFYI(1, "Echo request failed: %d", rc); cFYI(1, "Echo request failed: %d", rc);
...@@ -1376,6 +1381,359 @@ CIFSSMBOpen(const int xid, struct cifs_tcon *tcon, ...@@ -1376,6 +1381,359 @@ CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
return rc; return rc;
} }
struct cifs_readdata *
cifs_readdata_alloc(unsigned int nr_pages)
{
struct cifs_readdata *rdata;
/* readdata + 1 kvec for each page */
rdata = kzalloc(sizeof(*rdata) +
sizeof(struct kvec) * nr_pages, GFP_KERNEL);
if (rdata != NULL) {
INIT_WORK(&rdata->work, cifs_readv_complete);
INIT_LIST_HEAD(&rdata->pages);
}
return rdata;
}
void
cifs_readdata_free(struct cifs_readdata *rdata)
{
cifsFileInfo_put(rdata->cfile);
kfree(rdata);
}
/*
* Discard any remaining data in the current SMB. To do this, we borrow the
* current bigbuf.
*/
static int
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
READ_RSP *rsp = (READ_RSP *)server->smallbuf;
unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
int remaining = rfclen + 4 - server->total_read;
struct cifs_readdata *rdata = mid->callback_data;
while (remaining > 0) {
int length;
length = cifs_read_from_socket(server, server->bigbuf,
min_t(unsigned int, remaining,
CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
if (length < 0)
return length;
server->total_read += length;
remaining -= length;
}
dequeue_mid(mid, rdata->result);
return 0;
}
static int
cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
int length, len;
unsigned int data_offset, remaining, data_len;
struct cifs_readdata *rdata = mid->callback_data;
READ_RSP *rsp = (READ_RSP *)server->smallbuf;
unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
u64 eof;
pgoff_t eof_index;
struct page *page, *tpage;
cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
mid->mid, rdata->offset, rdata->bytes);
/*
* read the rest of READ_RSP header (sans Data array), or whatever we
* can if there's not enough data. At this point, we've read down to
* the Mid.
*/
len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
sizeof(struct smb_hdr) + 1;
rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
rdata->iov[0].iov_len = len;
length = cifs_readv_from_socket(server, rdata->iov, 1, len);
if (length < 0)
return length;
server->total_read += length;
/* Was the SMB read successful? */
rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
if (rdata->result != 0) {
cFYI(1, "%s: server returned error %d", __func__,
rdata->result);
return cifs_readv_discard(server, mid);
}
/* Is there enough to get to the rest of the READ_RSP header? */
if (server->total_read < sizeof(READ_RSP)) {
cFYI(1, "%s: server returned short header. got=%u expected=%zu",
__func__, server->total_read, sizeof(READ_RSP));
rdata->result = -EIO;
return cifs_readv_discard(server, mid);
}
data_offset = le16_to_cpu(rsp->DataOffset) + 4;
if (data_offset < server->total_read) {
/*
* win2k8 sometimes sends an offset of 0 when the read
* is beyond the EOF. Treat it as if the data starts just after
* the header.
*/
cFYI(1, "%s: data offset (%u) inside read response header",
__func__, data_offset);
data_offset = server->total_read;
} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
/* data_offset is beyond the end of smallbuf */
cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
__func__, data_offset);
rdata->result = -EIO;
return cifs_readv_discard(server, mid);
}
cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
server->total_read, data_offset);
len = data_offset - server->total_read;
if (len > 0) {
/* read any junk before data into the rest of smallbuf */
rdata->iov[0].iov_base = server->smallbuf + server->total_read;
rdata->iov[0].iov_len = len;
length = cifs_readv_from_socket(server, rdata->iov, 1, len);
if (length < 0)
return length;
server->total_read += length;
}
/* set up first iov for signature check */
rdata->iov[0].iov_base = server->smallbuf;
rdata->iov[0].iov_len = server->total_read;
cFYI(1, "0: iov_base=%p iov_len=%zu",
rdata->iov[0].iov_base, rdata->iov[0].iov_len);
/* how much data is in the response? */
data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
data_len += le16_to_cpu(rsp->DataLength);
if (data_offset + data_len > rfclen) {
/* data_len is corrupt -- discard frame */
rdata->result = -EIO;
return cifs_readv_discard(server, mid);
}
/* marshal up the page array */
len = 0;
remaining = data_len;
rdata->nr_iov = 1;
/* determine the eof that the server (probably) has */
eof = CIFS_I(rdata->mapping->host)->server_eof;
eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
if (remaining >= PAGE_CACHE_SIZE) {
/* enough data to fill the page */
rdata->iov[rdata->nr_iov].iov_base = kmap(page);
rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
rdata->nr_iov, page->index,
rdata->iov[rdata->nr_iov].iov_base,
rdata->iov[rdata->nr_iov].iov_len);
++rdata->nr_iov;
len += PAGE_CACHE_SIZE;
remaining -= PAGE_CACHE_SIZE;
} else if (remaining > 0) {
/* enough for partial page, fill and zero the rest */
rdata->iov[rdata->nr_iov].iov_base = kmap(page);
rdata->iov[rdata->nr_iov].iov_len = remaining;
cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
rdata->nr_iov, page->index,
rdata->iov[rdata->nr_iov].iov_base,
rdata->iov[rdata->nr_iov].iov_len);
memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
'\0', PAGE_CACHE_SIZE - remaining);
++rdata->nr_iov;
len += remaining;
remaining = 0;
} else if (page->index > eof_index) {
/*
* The VFS will not try to do readahead past the
* i_size, but it's possible that we have outstanding
* writes with gaps in the middle and the i_size hasn't
* caught up yet. Populate those with zeroed out pages
* to prevent the VFS from repeatedly attempting to
* fill them until the writes are flushed.
*/
zero_user(page, 0, PAGE_CACHE_SIZE);
list_del(&page->lru);
lru_cache_add_file(page);
flush_dcache_page(page);
SetPageUptodate(page);
unlock_page(page);
page_cache_release(page);
} else {
/* no need to hold page hostage */
list_del(&page->lru);
lru_cache_add_file(page);
unlock_page(page);
page_cache_release(page);
}
}
/* issue the read if we have any iovecs left to fill */
if (rdata->nr_iov > 1) {
length = cifs_readv_from_socket(server, &rdata->iov[1],
rdata->nr_iov - 1, len);
if (length < 0)
return length;
server->total_read += length;
} else {
length = 0;
}
rdata->bytes = length;
cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
rfclen, remaining);
/* discard anything left over */
if (server->total_read < rfclen)
return cifs_readv_discard(server, mid);
dequeue_mid(mid, false);
return length;
}
static void
cifs_readv_complete(struct work_struct *work)
{
struct cifs_readdata *rdata = container_of(work,
struct cifs_readdata, work);
struct page *page, *tpage;
list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
list_del(&page->lru);
lru_cache_add_file(page);
if (rdata->result == 0) {
kunmap(page);
flush_dcache_page(page);
SetPageUptodate(page);
}
unlock_page(page);
if (rdata->result == 0)
cifs_readpage_to_fscache(rdata->mapping->host, page);
page_cache_release(page);
}
cifs_readdata_free(rdata);
}
static void
cifs_readv_callback(struct mid_q_entry *mid)
{
struct cifs_readdata *rdata = mid->callback_data;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
mid->mid, mid->midState, rdata->result, rdata->bytes);
switch (mid->midState) {
case MID_RESPONSE_RECEIVED:
/* result already set, check signature */
if (server->sec_mode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
server, mid->sequence_number + 1))
cERROR(1, "Unexpected SMB signature");
}
/* FIXME: should this be counted toward the initiating task? */
task_io_account_read(rdata->bytes);
cifs_stats_bytes_read(tcon, rdata->bytes);
break;
case MID_REQUEST_SUBMITTED:
case MID_RETRY_NEEDED:
rdata->result = -EAGAIN;
break;
default:
rdata->result = -EIO;
}
queue_work(system_nrt_wq, &rdata->work);
DeleteMidQEntry(mid);
atomic_dec(&server->inFlight);
wake_up(&server->request_q);
}
/* cifs_async_readv - send an async write, and set up mid to handle result */
int
cifs_async_readv(struct cifs_readdata *rdata)
{
int rc;
READ_REQ *smb = NULL;
int wct;
struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
cFYI(1, "%s: offset=%llu bytes=%u", __func__,
rdata->offset, rdata->bytes);
if (tcon->ses->capabilities & CAP_LARGE_FILES)
wct = 12;
else {
wct = 10; /* old style read */
if ((rdata->offset >> 32) > 0) {
/* can not handle this big offset for old */
return -EIO;
}
}
rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
if (rc)
return rc;
smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
smb->AndXCommand = 0xFF; /* none */
smb->Fid = rdata->cfile->netfid;
smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
if (wct == 12)
smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
smb->Remaining = 0;
smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
if (wct == 12)
smb->ByteCount = 0;
else {
/* old style read */
struct smb_com_readx_req *smbr =
(struct smb_com_readx_req *)smb;
smbr->ByteCount = 0;
}
/* 4 for RFC1001 length + 1 for BCC */
rdata->iov[0].iov_base = smb;
rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
cifs_readv_receive, cifs_readv_callback,
rdata, false);
if (rc == 0)
cifs_stats_inc(&tcon->num_reads);
cifs_small_buf_release(smb);
return rc;
}
int int
CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
char **buf, int *pbuf_type) char **buf, int *pbuf_type)
...@@ -1836,7 +2194,7 @@ cifs_async_writev(struct cifs_writedata *wdata) ...@@ -1836,7 +2194,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
kref_get(&wdata->refcount); kref_get(&wdata->refcount);
rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1, rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
cifs_writev_callback, wdata, false); NULL, cifs_writev_callback, wdata, false);
if (rc == 0) if (rc == 0)
cifs_stats_inc(&tcon->num_writes); cifs_stats_inc(&tcon->num_writes);
...@@ -1962,10 +2320,50 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms, ...@@ -1962,10 +2320,50 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
return rc; return rc;
} }
int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
const __u8 lock_type, const __u32 num_unlock,
const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
{
int rc = 0;
LOCK_REQ *pSMB = NULL;
struct kvec iov[2];
int resp_buf_type;
__u16 count;
cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
if (rc)
return rc;
pSMB->Timeout = 0;
pSMB->NumberOfLocks = cpu_to_le16(num_lock);
pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
pSMB->LockType = lock_type;
pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = netfid; /* netfid stays le */
count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
inc_rfc1001_len(pSMB, count);
pSMB->ByteCount = cpu_to_le16(count);
iov[0].iov_base = (char *)pSMB;
iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
(num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
iov[1].iov_base = (char *)buf;
iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
cifs_stats_inc(&tcon->num_locks);
rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
if (rc)
cFYI(1, "Send error in cifs_lockv = %d", rc);
return rc;
}
int int
CIFSSMBLock(const int xid, struct cifs_tcon *tcon, CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
const __u16 smb_file_id, const __u64 len, const __u16 smb_file_id, const __u32 netpid, const __u64 len,
const __u64 offset, const __u32 numUnlock, const __u64 offset, const __u32 numUnlock,
const __u32 numLock, const __u8 lockType, const __u32 numLock, const __u8 lockType,
const bool waitFlag, const __u8 oplock_level) const bool waitFlag, const __u8 oplock_level)
...@@ -2001,7 +2399,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon, ...@@ -2001,7 +2399,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
pSMB->Fid = smb_file_id; /* netfid stays le */ pSMB->Fid = smb_file_id; /* netfid stays le */
if ((numLock != 0) || (numUnlock != 0)) { if ((numLock != 0) || (numUnlock != 0)) {
pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); pSMB->Locks[0].Pid = cpu_to_le16(netpid);
/* BB where to store pid high? */ /* BB where to store pid high? */
pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len); pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32)); pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
...@@ -2035,9 +2433,9 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon, ...@@ -2035,9 +2433,9 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
int int
CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
const __u16 smb_file_id, const int get_flag, const __u64 len, const __u16 smb_file_id, const __u32 netpid, const int get_flag,
struct file_lock *pLockData, const __u16 lock_type, const __u64 len, struct file_lock *pLockData,
const bool waitFlag) const __u16 lock_type, const bool waitFlag)
{ {
struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
...@@ -2095,7 +2493,7 @@ CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, ...@@ -2095,7 +2493,7 @@ CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
} else } else
pSMB->Timeout = 0; pSMB->Timeout = 0;
parm_data->pid = cpu_to_le32(current->tgid); parm_data->pid = cpu_to_le32(netpid);
parm_data->start = cpu_to_le64(pLockData->fl_start); parm_data->start = cpu_to_le64(pLockData->fl_start);
parm_data->length = cpu_to_le64(len); /* normalize negative numbers */ parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
...@@ -2812,8 +3210,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon, ...@@ -2812,8 +3210,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
pSMB->TotalDataCount = 0; pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le32(2); pSMB->MaxParameterCount = cpu_to_le32(2);
/* BB find exact data count max from sess structure BB */ /* BB find exact data count max from sess structure BB */
pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
pSMB->MaxSetupCount = 4; pSMB->MaxSetupCount = 4;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->ParameterOffset = 0; pSMB->ParameterOffset = 0;
...@@ -3306,8 +3703,7 @@ smb_init_nttransact(const __u16 sub_command, const int setup_count, ...@@ -3306,8 +3703,7 @@ smb_init_nttransact(const __u16 sub_command, const int setup_count,
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->TotalParameterCount = cpu_to_le32(parm_len); pSMB->TotalParameterCount = cpu_to_le32(parm_len);
pSMB->TotalDataCount = 0; pSMB->TotalDataCount = 0;
pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->DataCount = pSMB->TotalDataCount; pSMB->DataCount = pSMB->TotalDataCount;
temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
...@@ -3467,7 +3863,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid, ...@@ -3467,7 +3863,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
int int
CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid, CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
struct cifs_ntsd *pntsd, __u32 acllen) struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
{ {
__u16 byte_count, param_count, data_count, param_offset, data_offset; __u16 byte_count, param_count, data_count, param_offset, data_offset;
int rc = 0; int rc = 0;
...@@ -3504,7 +3900,7 @@ CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid, ...@@ -3504,7 +3900,7 @@ CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
pSMB->Fid = fid; /* file handle always le */ pSMB->Fid = fid; /* file handle always le */
pSMB->Reserved2 = 0; pSMB->Reserved2 = 0;
pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL); pSMB->AclFlags = cpu_to_le32(aclflag);
if (pntsd && acllen) { if (pntsd && acllen) {
memcpy((char *) &pSMBr->hdr.Protocol + data_offset, memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
...@@ -3977,8 +4373,7 @@ CIFSFindFirst(const int xid, struct cifs_tcon *tcon, ...@@ -3977,8 +4373,7 @@ CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
params = 12 + name_len /* includes null */ ; params = 12 + name_len /* includes null */ ;
pSMB->TotalDataCount = 0; /* no EAs */ pSMB->TotalDataCount = 0; /* no EAs */
pSMB->MaxParameterCount = cpu_to_le16(10); pSMB->MaxParameterCount = cpu_to_le16(10);
pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf - pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -4052,8 +4447,7 @@ CIFSFindFirst(const int xid, struct cifs_tcon *tcon, ...@@ -4052,8 +4447,7 @@ CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
psrch_inf->entries_in_buffer; psrch_inf->entries_in_buffer;
lnoff = le16_to_cpu(parms->LastNameOffset); lnoff = le16_to_cpu(parms->LastNameOffset);
if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE < if (CIFSMaxBufSize < lnoff) {
lnoff) {
cERROR(1, "ignoring corrupt resume name"); cERROR(1, "ignoring corrupt resume name");
psrch_inf->last_entry = NULL; psrch_inf->last_entry = NULL;
return rc; return rc;
...@@ -4097,9 +4491,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon, ...@@ -4097,9 +4491,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
byte_count = 0; byte_count = 0;
pSMB->TotalDataCount = 0; /* no EAs */ pSMB->TotalDataCount = 0; /* no EAs */
pSMB->MaxParameterCount = cpu_to_le16(8); pSMB->MaxParameterCount = cpu_to_le16(8);
pSMB->MaxDataCount = pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
0xFFFFFF00);
pSMB->MaxSetupCount = 0; pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->Flags = 0; pSMB->Flags = 0;
...@@ -4181,8 +4573,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon, ...@@ -4181,8 +4573,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
psrch_inf->index_of_last_entry += psrch_inf->index_of_last_entry +=
psrch_inf->entries_in_buffer; psrch_inf->entries_in_buffer;
lnoff = le16_to_cpu(parms->LastNameOffset); lnoff = le16_to_cpu(parms->LastNameOffset);
if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE < if (CIFSMaxBufSize < lnoff) {
lnoff) {
cERROR(1, "ignoring corrupt resume name"); cERROR(1, "ignoring corrupt resume name");
psrch_inf->last_entry = NULL; psrch_inf->last_entry = NULL;
return rc; return rc;
...@@ -5840,7 +6231,7 @@ CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon, ...@@ -5840,7 +6231,7 @@ CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
if (ea_name) { if (ea_name) {
if (ea_name_len == name_len && if (ea_name_len == name_len &&
strncmp(ea_name, temp_ptr, name_len) == 0) { memcmp(ea_name, temp_ptr, name_len) == 0) {
temp_ptr += name_len + 1; temp_ptr += name_len + 1;
rc = value_len; rc = value_len;
if (buf_size == 0) if (buf_size == 0)
...@@ -6035,12 +6426,7 @@ int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon, ...@@ -6035,12 +6426,7 @@ int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
pSMB->TotalParameterCount = 0 ; pSMB->TotalParameterCount = 0 ;
pSMB->TotalDataCount = 0; pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le32(2); pSMB->MaxParameterCount = cpu_to_le32(2);
/* BB find exact data count max from sess structure BB */ pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
pSMB->MaxDataCount = 0; /* same in little endian or be */
/* BB VERIFY verify which is correct for above BB */
pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
pSMB->MaxSetupCount = 4; pSMB->MaxSetupCount = 4;
pSMB->Reserved = 0; pSMB->Reserved = 0;
pSMB->ParameterOffset = 0; pSMB->ParameterOffset = 0;
......
此差异已折叠。
...@@ -171,7 +171,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -171,7 +171,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
} }
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
if (oplockEnabled) if (enable_oplocks)
oplock = REQ_OPLOCK; oplock = REQ_OPLOCK;
if (nd) if (nd)
...@@ -244,6 +244,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -244,6 +244,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if (!tcon->unix_ext && (mode & S_IWUGO) == 0) if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
create_options |= CREATE_OPTION_READONLY; create_options |= CREATE_OPTION_READONLY;
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
if (tcon->ses->capabilities & CAP_NT_SMBS) if (tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, tcon, full_path, disposition, rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
desiredAccess, create_options, desiredAccess, create_options,
...@@ -357,6 +360,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, ...@@ -357,6 +360,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
{ {
int rc = -EPERM; int rc = -EPERM;
int xid; int xid;
int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *pTcon; struct cifs_tcon *pTcon;
...@@ -431,9 +435,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, ...@@ -431,9 +435,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
return rc; return rc;
} }
/* FIXME: would WRITE_OWNER | WRITE_DAC be better? */ if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, GENERIC_WRITE, create_options,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) if (rc)
...@@ -642,8 +648,16 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) ...@@ -642,8 +648,16 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
if (direntry->d_inode) { if (direntry->d_inode) {
if (cifs_revalidate_dentry(direntry)) if (cifs_revalidate_dentry(direntry))
return 0; return 0;
else else {
/*
* Forcibly invalidate automounting directory inodes
* (remote DFS directories) so to have them
* instantiated again for automount
*/
if (IS_AUTOMOUNT(direntry->d_inode))
return 0;
return 1; return 1;
}
} }
/* /*
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifsfs.h" #include "cifsfs.h"
#ifdef CIFS_NFSD_EXPORT #ifdef CONFIG_CIFS_NFSD_EXPORT
static struct dentry *cifs_get_parent(struct dentry *dentry) static struct dentry *cifs_get_parent(struct dentry *dentry)
{ {
/* BB need to add code here eventually to enable export via NFSD */ /* BB need to add code here eventually to enable export via NFSD */
...@@ -63,5 +63,5 @@ const struct export_operations cifs_export_ops = { ...@@ -63,5 +63,5 @@ const struct export_operations cifs_export_ops = {
.encode_fs = */ .encode_fs = */
}; };
#endif /* CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
此差异已折叠。
...@@ -562,7 +562,16 @@ int cifs_get_file_info(struct file *filp) ...@@ -562,7 +562,16 @@ int cifs_get_file_info(struct file *filp)
xid = GetXid(); xid = GetXid();
rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
if (rc == -EOPNOTSUPP || rc == -EINVAL) { switch (rc) {
case 0:
cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
break;
case -EREMOTE:
cifs_create_dfs_fattr(&fattr, inode->i_sb);
rc = 0;
break;
case -EOPNOTSUPP:
case -EINVAL:
/* /*
* FIXME: legacy server -- fall back to path-based call? * FIXME: legacy server -- fall back to path-based call?
* for now, just skip revalidating and mark inode for * for now, just skip revalidating and mark inode for
...@@ -570,18 +579,14 @@ int cifs_get_file_info(struct file *filp) ...@@ -570,18 +579,14 @@ int cifs_get_file_info(struct file *filp)
*/ */
rc = 0; rc = 0;
CIFS_I(inode)->time = 0; CIFS_I(inode)->time = 0;
default:
goto cgfi_exit; goto cgfi_exit;
} else if (rc == -EREMOTE) { }
cifs_create_dfs_fattr(&fattr, inode->i_sb);
rc = 0;
} else if (rc)
goto cgfi_exit;
/* /*
* don't bother with SFU junk here -- just mark inode as needing * don't bother with SFU junk here -- just mark inode as needing
* revalidation. * revalidation.
*/ */
cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
fattr.cf_uniqueid = CIFS_I(inode)->uniqueid; fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
cifs_fattr_to_inode(inode, &fattr); cifs_fattr_to_inode(inode, &fattr);
...@@ -2096,6 +2101,8 @@ static int ...@@ -2096,6 +2101,8 @@ static int
cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
{ {
int xid; int xid;
uid_t uid = NO_CHANGE_32;
gid_t gid = NO_CHANGE_32;
struct inode *inode = direntry->d_inode; struct inode *inode = direntry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifsInodeInfo *cifsInode = CIFS_I(inode);
...@@ -2146,13 +2153,25 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2146,13 +2153,25 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
goto cifs_setattr_exit; goto cifs_setattr_exit;
} }
/* if (attrs->ia_valid & ATTR_UID)
* Without unix extensions we can't send ownership changes to the uid = attrs->ia_uid;
* server, so silently ignore them. This is consistent with how
* local DOS/Windows filesystems behave (VFAT, NTFS, etc). With if (attrs->ia_valid & ATTR_GID)
* CIFSACL support + proper Windows to Unix idmapping, we may be gid = attrs->ia_gid;
* able to support this in the future.
*/ #ifdef CONFIG_CIFS_ACL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
if (uid != NO_CHANGE_32 || gid != NO_CHANGE_32) {
rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
uid, gid);
if (rc) {
cFYI(1, "%s: Setting id failed with error: %d",
__func__, rc);
goto cifs_setattr_exit;
}
}
} else
#endif /* CONFIG_CIFS_ACL */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
...@@ -2161,15 +2180,12 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2161,15 +2180,12 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
attrs->ia_valid &= ~ATTR_MODE; attrs->ia_valid &= ~ATTR_MODE;
if (attrs->ia_valid & ATTR_MODE) { if (attrs->ia_valid & ATTR_MODE) {
cFYI(1, "Mode changed to 0%o", attrs->ia_mode);
mode = attrs->ia_mode; mode = attrs->ia_mode;
}
if (attrs->ia_valid & ATTR_MODE) {
rc = 0; rc = 0;
#ifdef CONFIG_CIFS_ACL #ifdef CONFIG_CIFS_ACL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
rc = mode_to_cifs_acl(inode, full_path, mode); rc = id_mode_to_cifs_acl(inode, full_path, mode,
NO_CHANGE_32, NO_CHANGE_32);
if (rc) { if (rc) {
cFYI(1, "%s: Setting ACL failed with error: %d", cFYI(1, "%s: Setting ACL failed with error: %d",
__func__, rc); __func__, rc);
......
...@@ -183,14 +183,20 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) ...@@ -183,14 +183,20 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
static int static int
CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon, CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon,
const char *fromName, const char *toName, const char *fromName, const char *toName,
const struct nls_table *nls_codepage, int remap) struct cifs_sb_info *cifs_sb)
{ {
int rc; int rc;
int oplock = 0; int oplock = 0;
int remap;
int create_options = CREATE_NOT_DIR;
__u16 netfid = 0; __u16 netfid = 0;
u8 *buf; u8 *buf;
unsigned int bytes_written = 0; unsigned int bytes_written = 0;
struct cifs_io_parms io_parms; struct cifs_io_parms io_parms;
struct nls_table *nls_codepage;
nls_codepage = cifs_sb->local_nls;
remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
if (!buf) if (!buf)
...@@ -202,8 +208,11 @@ CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon, ...@@ -202,8 +208,11 @@ CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon,
return rc; return rc;
} }
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE, rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE,
CREATE_NOT_DIR, &netfid, &oplock, NULL, create_options, &netfid, &oplock, NULL,
nls_codepage, remap); nls_codepage, remap);
if (rc != 0) { if (rc != 0) {
kfree(buf); kfree(buf);
...@@ -559,9 +568,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -559,9 +568,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
/* BB what if DFS and this volume is on different share? BB */ /* BB what if DFS and this volume is on different share? BB */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
cifs_sb->local_nls, cifs_sb);
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
else if (pTcon->unix_ext) else if (pTcon->unix_ext)
rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
cifs_sb->local_nls); cifs_sb->local_nls);
......
...@@ -420,19 +420,22 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid) ...@@ -420,19 +420,22 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid)
} }
int int
checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int total_read)
{ {
__u32 len = be32_to_cpu(smb->smb_buf_length); __u32 rfclen = be32_to_cpu(smb->smb_buf_length);
__u32 clc_len; /* calculated length */ __u32 clc_len; /* calculated length */
cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len); cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x",
total_read, rfclen);
if (length < 2 + sizeof(struct smb_hdr)) { /* is this frame too small to even get to a BCC? */
if ((length >= sizeof(struct smb_hdr) - 1) if (total_read < 2 + sizeof(struct smb_hdr)) {
if ((total_read >= sizeof(struct smb_hdr) - 1)
&& (smb->Status.CifsError != 0)) { && (smb->Status.CifsError != 0)) {
/* it's an error return */
smb->WordCount = 0; smb->WordCount = 0;
/* some error cases do not return wct and bcc */ /* some error cases do not return wct and bcc */
return 0; return 0;
} else if ((length == sizeof(struct smb_hdr) + 1) && } else if ((total_read == sizeof(struct smb_hdr) + 1) &&
(smb->WordCount == 0)) { (smb->WordCount == 0)) {
char *tmp = (char *)smb; char *tmp = (char *)smb;
/* Need to work around a bug in two servers here */ /* Need to work around a bug in two servers here */
...@@ -452,39 +455,35 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) ...@@ -452,39 +455,35 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
} else { } else {
cERROR(1, "Length less than smb header size"); cERROR(1, "Length less than smb header size");
} }
return 1; return -EIO;
}
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
cERROR(1, "smb length greater than MaxBufSize, mid=%d",
smb->Mid);
return 1;
} }
/* otherwise, there is enough to get to the BCC */
if (check_smb_hdr(smb, mid)) if (check_smb_hdr(smb, mid))
return 1; return -EIO;
clc_len = smbCalcSize(smb); clc_len = smbCalcSize(smb);
if (4 + len != length) { if (4 + rfclen != total_read) {
cERROR(1, "Length read does not match RFC1001 length %d", cERROR(1, "Length read does not match RFC1001 length %d",
len); rfclen);
return 1; return -EIO;
} }
if (4 + len != clc_len) { if (4 + rfclen != clc_len) {
/* check if bcc wrapped around for large read responses */ /* check if bcc wrapped around for large read responses */
if ((len > 64 * 1024) && (len > clc_len)) { if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
/* check if lengths match mod 64K */ /* check if lengths match mod 64K */
if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF)) if (((4 + rfclen) & 0xFFFF) == (clc_len & 0xFFFF))
return 0; /* bcc wrapped */ return 0; /* bcc wrapped */
} }
cFYI(1, "Calculated size %u vs length %u mismatch for mid=%u", cFYI(1, "Calculated size %u vs length %u mismatch for mid=%u",
clc_len, 4 + len, smb->Mid); clc_len, 4 + rfclen, smb->Mid);
if (4 + len < clc_len) { if (4 + rfclen < clc_len) {
cERROR(1, "RFC1001 size %u smaller than SMB for mid=%u", cERROR(1, "RFC1001 size %u smaller than SMB for mid=%u",
len, smb->Mid); rfclen, smb->Mid);
return 1; return -EIO;
} else if (len > clc_len + 512) { } else if (rfclen > clc_len + 512) {
/* /*
* Some servers (Windows XP in particular) send more * Some servers (Windows XP in particular) send more
* data than the lengths in the SMB packet would * data than the lengths in the SMB packet would
...@@ -495,8 +494,8 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) ...@@ -495,8 +494,8 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
* data to 512 bytes. * data to 512 bytes.
*/ */
cERROR(1, "RFC1001 size %u more than 512 bytes larger " cERROR(1, "RFC1001 size %u more than 512 bytes larger "
"than SMB for mid=%u", len, smb->Mid); "than SMB for mid=%u", rfclen, smb->Mid);
return 1; return -EIO;
} }
} }
return 0; return 0;
...@@ -676,3 +675,18 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) ...@@ -676,3 +675,18 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
cinode->clientCanCacheRead = false; cinode->clientCanCacheRead = false;
} }
} }
bool
backup_cred(struct cifs_sb_info *cifs_sb)
{
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
if (cifs_sb->mnt_backupuid == current_fsuid())
return true;
}
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
if (in_group_p(cifs_sb->mnt_backupgid))
return true;
}
return false;
}
...@@ -124,7 +124,9 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB) ...@@ -124,7 +124,9 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
/* that we use in next few lines */ /* that we use in next few lines */
/* Note that header is initialized to zero in header_assemble */ /* Note that header is initialized to zero in header_assemble */
pSMB->req.AndXCommand = 0xFF; pSMB->req.AndXCommand = 0xFF;
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req.MaxBufferSize = cpu_to_le16(min_t(u32,
CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
USHRT_MAX));
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
pSMB->req.VcNumber = get_next_vcnum(ses); pSMB->req.VcNumber = get_next_vcnum(ses);
......
...@@ -265,91 +265,6 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) ...@@ -265,91 +265,6 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
return rc; return rc;
} }
#if 0 /* currently unused */
/* Does both the NT and LM owfs of a user's password */
static void
nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
{
char passwd[514];
memset(passwd, '\0', 514);
if (strlen(pwd) < 513)
strcpy(passwd, pwd);
else
memcpy(passwd, pwd, 512);
/* Calculate the MD4 hash (NT compatible) of the password */
memset(nt_p16, '\0', 16);
E_md4hash(passwd, nt_p16);
/* Mangle the passwords into Lanman format */
passwd[14] = '\0';
/* strupper(passwd); */
/* Calculate the SMB (lanman) hash functions of the password */
memset(p16, '\0', 16);
E_P16((unsigned char *) passwd, (unsigned char *) p16);
/* clear out local copy of user's password (just being paranoid). */
memset(passwd, '\0', sizeof(passwd));
}
#endif
/* Does the NTLMv2 owfs of a user's password */
#if 0 /* function not needed yet - but will be soon */
static void
ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
const char *domain_n, unsigned char kr_buf[16],
const struct nls_table *nls_codepage)
{
wchar_t *user_u;
wchar_t *dom_u;
int user_l, domain_l;
struct HMACMD5Context ctx;
/* might as well do one alloc to hold both (user_u and dom_u) */
user_u = kmalloc(2048 * sizeof(wchar_t), GFP_KERNEL);
if (user_u == NULL)
return;
dom_u = user_u + 1024;
/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2,
STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2,
STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
/* BB user and domain may need to be uppercased */
user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage);
user_l++; /* trailing null */
domain_l++;
hmac_md5_init_limK_to_64(owf, 16, &ctx);
hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx);
hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx);
hmac_md5_final(kr_buf, &ctx);
kfree(user_u);
}
#endif
/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
#if 0 /* currently unused */
static void
NTLMSSPOWFencrypt(unsigned char passwd[8],
unsigned char *ntlmchalresp, unsigned char p24[24])
{
unsigned char p21[21];
memset(p21, '\0', 21);
memcpy(p21, passwd, 8);
memset(p21 + 8, 0xbd, 8);
E_P24(p21, ntlmchalresp, p24);
}
#endif
/* Does the NT MD4 hash then des encryption. */ /* Does the NT MD4 hash then des encryption. */
int int
SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
...@@ -369,39 +284,3 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) ...@@ -369,39 +284,3 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
rc = E_P24(p21, c8, p24); rc = E_P24(p21, c8, p24);
return rc; return rc;
} }
/* Does the md5 encryption from the NT hash for NTLMv2. */
/* These routines will be needed later */
#if 0
static void
SMBOWFencrypt_ntv2(const unsigned char kr[16],
const struct data_blob *srv_chal,
const struct data_blob *cli_chal, unsigned char resp_buf[16])
{
struct HMACMD5Context ctx;
hmac_md5_init_limK_to_64(kr, 16, &ctx);
hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
hmac_md5_final(resp_buf, &ctx);
}
static void
SMBsesskeygen_ntv2(const unsigned char kr[16],
const unsigned char *nt_resp, __u8 sess_key[16])
{
struct HMACMD5Context ctx;
hmac_md5_init_limK_to_64(kr, 16, &ctx);
hmac_md5_update(nt_resp, 16, &ctx);
hmac_md5_final((unsigned char *) sess_key, &ctx);
}
static void
SMBsesskeygen_ntv1(const unsigned char kr[16],
const unsigned char *nt_resp, __u8 sess_key[16])
{
mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16);
}
#endif
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/freezer.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <linux/mempool.h> #include <linux/mempool.h>
...@@ -324,7 +325,7 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) ...@@ -324,7 +325,7 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
{ {
int error; int error;
error = wait_event_killable(server->response_q, error = wait_event_freezekillable(server->response_q,
midQ->midState != MID_REQUEST_SUBMITTED); midQ->midState != MID_REQUEST_SUBMITTED);
if (error < 0) if (error < 0)
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -339,8 +340,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) ...@@ -339,8 +340,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
*/ */
int int
cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
unsigned int nvec, mid_callback_t *callback, void *cbdata, unsigned int nvec, mid_receive_t *receive,
bool ignore_pend) mid_callback_t *callback, void *cbdata, bool ignore_pend)
{ {
int rc; int rc;
struct mid_q_entry *mid; struct mid_q_entry *mid;
...@@ -374,6 +375,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, ...@@ -374,6 +375,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
goto out_err; goto out_err;
} }
mid->receive = receive;
mid->callback = callback; mid->callback = callback;
mid->callback_data = cbdata; mid->callback_data = cbdata;
mid->midState = MID_REQUEST_SUBMITTED; mid->midState = MID_REQUEST_SUBMITTED;
...@@ -496,13 +498,18 @@ int ...@@ -496,13 +498,18 @@ int
cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
bool log_error) bool log_error)
{ {
dump_smb(mid->resp_buf, unsigned int len = be32_to_cpu(mid->resp_buf->smb_buf_length) + 4;
min_t(u32, 92, be32_to_cpu(mid->resp_buf->smb_buf_length)));
dump_smb(mid->resp_buf, min_t(u32, 92, len));
/* convert the length into a more usable form */ /* convert the length into a more usable form */
if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
struct kvec iov;
iov.iov_base = mid->resp_buf;
iov.iov_len = len;
/* FIXME: add code to kill session */ /* FIXME: add code to kill session */
if (cifs_verify_signature(mid->resp_buf, server, if (cifs_verify_signature(&iov, 1, server,
mid->sequence_number + 1) != 0) mid->sequence_number + 1) != 0)
cERROR(1, "Unexpected SMB signature"); cERROR(1, "Unexpected SMB signature");
} }
......
...@@ -173,7 +173,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, ...@@ -173,7 +173,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
#ifdef CONFIG_CIFS_ACL #ifdef CONFIG_CIFS_ACL
memcpy(pacl, ea_value, value_size); memcpy(pacl, ea_value, value_size);
rc = set_cifs_acl(pacl, value_size, rc = set_cifs_acl(pacl, value_size,
direntry->d_inode, full_path); direntry->d_inode, full_path, CIFS_ACL_DACL);
if (rc == 0) /* force revalidate of the inode */ if (rc == 0) /* force revalidate of the inode */
CIFS_I(direntry->d_inode)->time = 0; CIFS_I(direntry->d_inode)->time = 0;
kfree(pacl); kfree(pacl);
......
...@@ -135,10 +135,25 @@ static inline void set_freezable_with_signal(void) ...@@ -135,10 +135,25 @@ static inline void set_freezable_with_signal(void)
} }
/* /*
* Freezer-friendly wrappers around wait_event_interruptible() and * Freezer-friendly wrappers around wait_event_interruptible(),
* wait_event_interruptible_timeout(), originally defined in <linux/wait.h> * wait_event_killable() and wait_event_interruptible_timeout(), originally
* defined in <linux/wait.h>
*/ */
#define wait_event_freezekillable(wq, condition) \
({ \
int __retval; \
do { \
__retval = wait_event_killable(wq, \
(condition) || freezing(current)); \
if (__retval && !freezing(current)) \
break; \
else if (!(condition)) \
__retval = -ERESTARTSYS; \
} while (try_to_freeze()); \
__retval; \
})
#define wait_event_freezable(wq, condition) \ #define wait_event_freezable(wq, condition) \
({ \ ({ \
int __retval; \ int __retval; \
...@@ -190,6 +205,9 @@ static inline void set_freezable_with_signal(void) {} ...@@ -190,6 +205,9 @@ static inline void set_freezable_with_signal(void) {}
#define wait_event_freezable_timeout(wq, condition, timeout) \ #define wait_event_freezable_timeout(wq, condition, timeout) \
wait_event_interruptible_timeout(wq, condition, timeout) wait_event_interruptible_timeout(wq, condition, timeout)
#define wait_event_freezekillable(wq, condition) \
wait_event_killable(wq, condition)
#endif /* !CONFIG_FREEZER */ #endif /* !CONFIG_FREEZER */
#endif /* FREEZER_H_INCLUDED */ #endif /* FREEZER_H_INCLUDED */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册