Skip to content

Commit 87dbe42

Browse files
committed
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: "Including: - nine bug fixes for stable. Some of these we found at the recent two weeks of SMB3 test events/plugfests. - significant improvements in reconnection (e.g. if server or network crashes) especially when mounted with "persistenthandles" or to server which advertises Continuous Availability on the share. - a new mount option "idsfromsid" which improves POSIX compatibility in some cases (when winbind not configured e.g.) by better (and faster) fetching uid/gid from acl (when "cifsacl" mount option is enabled). NB: we are almost complete work on "cifsacl" (querying mode/uid/gid from ACL) for SMB3, but SMB3 support for cifsacl is not included in this set. - improved handling for SMB3 "credits" (even if server is buggy) Still working on two sets of changes: - cifsacl enablement for SMB3 - cleanup of RFC1001 length calculation (so we can handle encryption and multichannel and RDMA) And a couple of new bugs were reported recently (unrelated to above) so will probably have another merge request next week" * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: (21 commits) CIFS: Retrieve uid and gid from special sid if enabled CIFS: Add new mount option to set owner uid and gid from special sids in acl CIFS: Reset read oplock to NONE if we have mandatory locks after reopen CIFS: Fix persistent handles re-opening on reconnect SMB2: Separate RawNTLMSSP authentication from SMB2_sess_setup SMB2: Separate Kerberos authentication from SMB2_sess_setup Expose cifs module parameters in sysfs Cleanup missing frees on some ioctls Enable previous version support Do not send SMB3 SET_INFO request if nothing is changing SMB3: Add mount parameter to allow user to override max credits fs/cifs: reopen persistent handles on reconnect Clarify locking of cifs file and tcon structures and make more granular Fix regression which breaks DFS mounting fs/cifs: keep guid when assigning fid to fileinfo SMB3: GUIDs should be constructed as random but valid uuids Set previous session id correctly on SMB3 reconnect cifs: Limit the overall credit acquired Display number of credits available Add way to query creation time of file via cifs xattr ...
2 parents d3304ca + 3514de3 commit 87dbe42

19 files changed

Lines changed: 824 additions & 296 deletions

fs/cifs/cifs_debug.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
152152
list_for_each(tmp1, &cifs_tcp_ses_list) {
153153
server = list_entry(tmp1, struct TCP_Server_Info,
154154
tcp_ses_list);
155+
seq_printf(m, "\nNumber of credits: %d", server->credits);
155156
i++;
156157
list_for_each(tmp2, &server->smb_ses_list) {
157158
ses = list_entry(tmp2, struct cifs_ses,

fs/cifs/cifs_fs_sb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#define CIFS_MOUNT_USE_PREFIX_PATH 0x1000000 /* make subpath with unaccessible
5050
* root mountable
5151
*/
52+
#define CIFS_MOUNT_UID_FROM_ACL 0x2000000 /* try to get UID via special SID */
5253

5354
struct cifs_sb_info {
5455
struct rb_root tlink_tree;

fs/cifs/cifs_ioctl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,15 @@ struct smb_mnt_fs_info {
3636
__u64 cifs_posix_caps;
3737
} __packed;
3838

39+
struct smb_snapshot_array {
40+
__u32 number_of_snapshots;
41+
__u32 number_of_snapshots_returned;
42+
__u32 snapshot_array_size;
43+
/* snapshots[]; */
44+
} __packed;
45+
3946
#define CIFS_IOCTL_MAGIC 0xCF
4047
#define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int)
4148
#define CIFS_IOC_SET_INTEGRITY _IO(CIFS_IOCTL_MAGIC, 4)
4249
#define CIFS_IOC_GET_MNT_INFO _IOR(CIFS_IOCTL_MAGIC, 5, struct smb_mnt_fs_info)
50+
#define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array)

fs/cifs/cifsacl.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,35 @@ static const struct cifs_sid sid_authusers = {
4242
/* group users */
4343
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
4444

45+
/* S-1-22-1 Unmapped Unix users */
46+
static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22},
47+
{cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
48+
49+
/* S-1-22-2 Unmapped Unix groups */
50+
static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22},
51+
{cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
52+
53+
/*
54+
* See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
55+
*/
56+
57+
/* S-1-5-88 MS NFS and Apple style UID/GID/mode */
58+
59+
/* S-1-5-88-1 Unix uid */
60+
static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5},
61+
{cpu_to_le32(88),
62+
cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
63+
64+
/* S-1-5-88-2 Unix gid */
65+
static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5},
66+
{cpu_to_le32(88),
67+
cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
68+
69+
/* S-1-5-88-3 Unix mode */
70+
static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5},
71+
{cpu_to_le32(88),
72+
cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
73+
4574
static const struct cred *root_cred;
4675

4776
static int
@@ -183,6 +212,62 @@ compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
183212
return 0; /* sids compare/match */
184213
}
185214

215+
static bool
216+
is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group)
217+
{
218+
int i;
219+
int num_subauth;
220+
const struct cifs_sid *pwell_known_sid;
221+
222+
if (!psid || (puid == NULL))
223+
return false;
224+
225+
num_subauth = psid->num_subauth;
226+
227+
/* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */
228+
if (num_subauth == 2) {
229+
if (is_group)
230+
pwell_known_sid = &sid_unix_groups;
231+
else
232+
pwell_known_sid = &sid_unix_users;
233+
} else if (num_subauth == 3) {
234+
if (is_group)
235+
pwell_known_sid = &sid_unix_NFS_groups;
236+
else
237+
pwell_known_sid = &sid_unix_NFS_users;
238+
} else
239+
return false;
240+
241+
/* compare the revision */
242+
if (psid->revision != pwell_known_sid->revision)
243+
return false;
244+
245+
/* compare all of the six auth values */
246+
for (i = 0; i < NUM_AUTHS; ++i) {
247+
if (psid->authority[i] != pwell_known_sid->authority[i]) {
248+
cifs_dbg(FYI, "auth %d did not match\n", i);
249+
return false;
250+
}
251+
}
252+
253+
if (num_subauth == 2) {
254+
if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0])
255+
return false;
256+
257+
*puid = le32_to_cpu(psid->sub_auth[1]);
258+
} else /* 3 subauths, ie Windows/Mac style */ {
259+
*puid = le32_to_cpu(psid->sub_auth[0]);
260+
if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) ||
261+
(psid->sub_auth[1] != pwell_known_sid->sub_auth[1]))
262+
return false;
263+
264+
*puid = le32_to_cpu(psid->sub_auth[2]);
265+
}
266+
267+
cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid);
268+
return true; /* well known sid found, uid returned */
269+
}
270+
186271
static void
187272
cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
188273
{
@@ -276,6 +361,43 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
276361
return -EIO;
277362
}
278363

364+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) {
365+
uint32_t unix_id;
366+
bool is_group;
367+
368+
if (sidtype != SIDOWNER)
369+
is_group = true;
370+
else
371+
is_group = false;
372+
373+
if (is_well_known_sid(psid, &unix_id, is_group) == false)
374+
goto try_upcall_to_get_id;
375+
376+
if (is_group) {
377+
kgid_t gid;
378+
gid_t id;
379+
380+
id = (gid_t)unix_id;
381+
gid = make_kgid(&init_user_ns, id);
382+
if (gid_valid(gid)) {
383+
fgid = gid;
384+
goto got_valid_id;
385+
}
386+
} else {
387+
kuid_t uid;
388+
uid_t id;
389+
390+
id = (uid_t)unix_id;
391+
uid = make_kuid(&init_user_ns, id);
392+
if (uid_valid(uid)) {
393+
fuid = uid;
394+
goto got_valid_id;
395+
}
396+
}
397+
/* If unable to find uid/gid easily from SID try via upcall */
398+
}
399+
400+
try_upcall_to_get_id:
279401
sidstr = sid_to_key_str(psid, sidtype);
280402
if (!sidstr)
281403
return -ENOMEM;
@@ -329,6 +451,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
329451
* Note that we return 0 here unconditionally. If the mapping
330452
* fails then we just fall back to using the mnt_uid/mnt_gid.
331453
*/
454+
got_valid_id:
332455
if (sidtype == SIDOWNER)
333456
fattr->cf_uid = fuid;
334457
else

fs/cifs/cifsfs.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ unsigned int global_secflags = CIFSSEC_DEF;
6464
unsigned int sign_CIFS_PDUs = 1;
6565
static const struct super_operations cifs_super_ops;
6666
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
67-
module_param(CIFSMaxBufSize, uint, 0);
67+
module_param(CIFSMaxBufSize, uint, 0444);
6868
MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). "
6969
"Default: 16384 Range: 8192 to 130048");
7070
unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
71-
module_param(cifs_min_rcv, uint, 0);
71+
module_param(cifs_min_rcv, uint, 0444);
7272
MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: "
7373
"1 to 64");
7474
unsigned int cifs_min_small = 30;
75-
module_param(cifs_min_small, uint, 0);
75+
module_param(cifs_min_small, uint, 0444);
7676
MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
7777
"Range: 2 to 256");
7878
unsigned int cifs_max_pending = CIFS_MAX_REQ;
@@ -271,7 +271,7 @@ cifs_alloc_inode(struct super_block *sb)
271271
cifs_inode->createtime = 0;
272272
cifs_inode->epoch = 0;
273273
#ifdef CONFIG_CIFS_SMB2
274-
get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
274+
generate_random_uuid(cifs_inode->lease_key);
275275
#endif
276276
/*
277277
* Can not set i_flags here - they get immediately overwritten to zero
@@ -469,6 +469,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
469469
seq_puts(s, ",posixpaths");
470470
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
471471
seq_puts(s, ",setuids");
472+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
473+
seq_puts(s, ",idsfromsid");
472474
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
473475
seq_puts(s, ",serverino");
474476
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
@@ -1262,7 +1264,6 @@ init_cifs(void)
12621264
GlobalTotalActiveXid = 0;
12631265
GlobalMaxActiveXid = 0;
12641266
spin_lock_init(&cifs_tcp_ses_lock);
1265-
spin_lock_init(&cifs_file_list_lock);
12661267
spin_lock_init(&GlobalMid_Lock);
12671268

12681269
get_random_bytes(&cifs_lock_secret, sizeof(cifs_lock_secret));

fs/cifs/cifsglob.h

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@
7575
#define SMB_ECHO_INTERVAL_MAX 600
7676
#define SMB_ECHO_INTERVAL_DEFAULT 60
7777

78+
/*
79+
* Default number of credits to keep available for SMB3.
80+
* This value is chosen somewhat arbitrarily. The Windows client
81+
* defaults to 128 credits, the Windows server allows clients up to
82+
* 512 credits (or 8K for later versions), and the NetApp server
83+
* does not limit clients at all. Choose a high enough default value
84+
* such that the client shouldn't limit performance, but allow mount
85+
* to override (until you approach 64K, where we limit credits to 65000
86+
* to reduce possibility of seeing more server credit overflow bugs.
87+
*/
88+
#define SMB2_MAX_CREDITS_AVAILABLE 32000
89+
7890
#include "cifspdu.h"
7991

8092
#ifndef XATTR_DOS_ATTRIB
@@ -376,6 +388,8 @@ struct smb_version_operations {
376388
int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
377389
int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
378390
struct cifsFileInfo *src_file);
391+
int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
392+
struct cifsFileInfo *src_file, void __user *);
379393
int (*query_mf_symlink)(unsigned int, struct cifs_tcon *,
380394
struct cifs_sb_info *, const unsigned char *,
381395
char *, unsigned int *);
@@ -464,6 +478,7 @@ struct smb_vol {
464478
bool retry:1;
465479
bool intr:1;
466480
bool setuids:1;
481+
bool setuidfromacl:1;
467482
bool override_uid:1;
468483
bool override_gid:1;
469484
bool dynperm:1;
@@ -510,6 +525,7 @@ struct smb_vol {
510525
struct sockaddr_storage srcaddr; /* allow binding to a local IP */
511526
struct nls_table *local_nls;
512527
unsigned int echo_interval; /* echo interval in secs */
528+
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
513529
};
514530

515531
#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
@@ -567,7 +583,8 @@ struct TCP_Server_Info {
567583
bool noblocksnd; /* use blocking sendmsg */
568584
bool noautotune; /* do not autotune send buf sizes */
569585
bool tcp_nodelay;
570-
int credits; /* send no more requests at once */
586+
unsigned int credits; /* send no more requests at once */
587+
unsigned int max_credits; /* can override large 32000 default at mnt */
571588
unsigned int in_flight; /* number of requests on the wire to server */
572589
spinlock_t req_lock; /* protect the two values above */
573590
struct mutex srv_mutex;
@@ -833,6 +850,7 @@ struct cifs_tcon {
833850
struct list_head tcon_list;
834851
int tc_count;
835852
struct list_head openFileList;
853+
spinlock_t open_file_lock; /* protects list above */
836854
struct cifs_ses *ses; /* pointer to session associated with */
837855
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
838856
char *nativeFileSystem;
@@ -889,7 +907,7 @@ struct cifs_tcon {
889907
#endif /* CONFIG_CIFS_STATS2 */
890908
__u64 bytes_read;
891909
__u64 bytes_written;
892-
spinlock_t stat_lock;
910+
spinlock_t stat_lock; /* protects the two fields above */
893911
#endif /* CONFIG_CIFS_STATS */
894912
FILE_SYSTEM_DEVICE_INFO fsDevInfo;
895913
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
@@ -1040,20 +1058,24 @@ struct cifs_fid_locks {
10401058
};
10411059

10421060
struct cifsFileInfo {
1061+
/* following two lists are protected by tcon->open_file_lock */
10431062
struct list_head tlist; /* pointer to next fid owned by tcon */
10441063
struct list_head flist; /* next fid (file instance) for this inode */
1064+
/* lock list below protected by cifsi->lock_sem */
10451065
struct cifs_fid_locks *llist; /* brlocks held by this fid */
10461066
kuid_t uid; /* allows finding which FileInfo structure */
10471067
__u32 pid; /* process id who opened file */
10481068
struct cifs_fid fid; /* file id from remote */
1069+
struct list_head rlist; /* reconnect list */
10491070
/* BB add lock scope info here if needed */ ;
10501071
/* lock scope id (0 if none) */
10511072
struct dentry *dentry;
1052-
unsigned int f_flags;
10531073
struct tcon_link *tlink;
1074+
unsigned int f_flags;
10541075
bool invalidHandle:1; /* file closed via session abend */
10551076
bool oplock_break_cancelled:1;
1056-
int count; /* refcount protected by cifs_file_list_lock */
1077+
int count;
1078+
spinlock_t file_info_lock; /* protects four flag/count fields above */
10571079
struct mutex fh_mutex; /* prevents reopen race after dead ses*/
10581080
struct cifs_search_info srch_inf;
10591081
struct work_struct oplock_break; /* work for oplock breaks */
@@ -1120,7 +1142,7 @@ struct cifs_writedata {
11201142

11211143
/*
11221144
* Take a reference on the file private data. Must be called with
1123-
* cifs_file_list_lock held.
1145+
* cfile->file_info_lock held.
11241146
*/
11251147
static inline void
11261148
cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
@@ -1514,8 +1536,10 @@ require use of the stronger protocol */
15141536
* GlobalMid_Lock protects:
15151537
* list operations on pending_mid_q and oplockQ
15161538
* updates to XID counters, multiplex id and SMB sequence numbers
1517-
* cifs_file_list_lock protects:
1518-
* list operations on tcp and SMB session lists and tCon lists
1539+
* tcp_ses_lock protects:
1540+
* list operations on tcp and SMB session lists
1541+
* tcon->open_file_lock protects the list of open files hanging off the tcon
1542+
* cfile->file_info_lock protects counters and fields in cifs file struct
15191543
* f_owner.lock protects certain per file struct operations
15201544
* mapping->page_lock protects certain per page operations
15211545
*
@@ -1547,18 +1571,12 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
15471571
* tcp session, and the list of tcon's per smb session. It also protects
15481572
* the reference counters for the server, smb session, and tcon. Finally,
15491573
* changes to the tcon->tidStatus should be done while holding this lock.
1574+
* generally the locks should be taken in order tcp_ses_lock before
1575+
* tcon->open_file_lock and that before file->file_info_lock since the
1576+
* structure order is cifs_socket-->cifs_ses-->cifs_tcon-->cifs_file
15501577
*/
15511578
GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock;
15521579

1553-
/*
1554-
* This lock protects the cifs_file->llist and cifs_file->flist
1555-
* list operations, and updates to some flags (cifs_file->invalidHandle)
1556-
* It will be moved to either use the tcon->stat_lock or equivalent later.
1557-
* If cifs_tcp_ses_lock and the lock below are both needed to be held, then
1558-
* the cifs_tcp_ses_lock must be grabbed first and released last.
1559-
*/
1560-
GLOBAL_EXTERN spinlock_t cifs_file_list_lock;
1561-
15621580
#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
15631581
/* Outstanding dir notify requests */
15641582
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;

fs/cifs/cifsproto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data,
193193
extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
194194
extern void cifs_umount(struct cifs_sb_info *);
195195
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
196+
extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
197+
196198
extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset,
197199
__u64 length, __u8 type,
198200
struct cifsLockInfo **conf_lock,

fs/cifs/cifssmb.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
9898
struct list_head *tmp1;
9999

100100
/* list all files open on tree connection and mark them invalid */
101-
spin_lock(&cifs_file_list_lock);
101+
spin_lock(&tcon->open_file_lock);
102102
list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
103103
open_file = list_entry(tmp, struct cifsFileInfo, tlist);
104104
open_file->invalidHandle = true;
105105
open_file->oplock_break_cancelled = true;
106106
}
107-
spin_unlock(&cifs_file_list_lock);
107+
spin_unlock(&tcon->open_file_lock);
108108
/*
109109
* BB Add call to invalidate_inodes(sb) for all superblocks mounted
110110
* to this tcon.

0 commit comments

Comments
 (0)