aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-08-02 13:54:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-08-02 13:54:11 -0400
commit630103ea2c286de3e7ea9ae6b1035d91ef051413 (patch)
tree864fe60cc603434ddc16e7c0344a1a7f982d7b54 /fs
parent8783b6e2b2cb726f2734cf208d101f73ac1ba616 (diff)
parent1a500f010fb2d121c58f77ddfde2eca1bde3bfcd (diff)
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS update from Steve French: "Adds SMB2 rmdir/mkdir capability to the SMB2/SMB2.1 support in cifs. I am holding up a few more days on merging the remainder of the SMB2/SMB2.1 enablement although it is nearing review completion, in order to address some review comments from Jeff Layton on a few of the subsequent SMB2 patches, and also to debug an unrelated cifs problem that Pavel discovered." * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: CIFS: Add SMB2 support for rmdir CIFS: Move rmdir code to ops struct CIFS: Add SMB2 support for mkdir operation CIFS: Separate protocol specific part from mkdir CIFS: Simplify cifs_mkdir call
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifsglob.h10
-rw-r--r--fs/cifs/cifsproto.h11
-rw-r--r--fs/cifs/cifssmb.c31
-rw-r--r--fs/cifs/inode.c302
-rw-r--r--fs/cifs/smb1ops.c24
-rw-r--r--fs/cifs/smb2inode.c39
-rw-r--r--fs/cifs/smb2ops.c3
-rw-r--r--fs/cifs/smb2proto.h8
8 files changed, 270 insertions, 158 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 497da5ce704c..977dc0e85ccb 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -246,6 +246,16 @@ struct smb_version_operations {
246 bool (*can_echo)(struct TCP_Server_Info *); 246 bool (*can_echo)(struct TCP_Server_Info *);
247 /* send echo request */ 247 /* send echo request */
248 int (*echo)(struct TCP_Server_Info *); 248 int (*echo)(struct TCP_Server_Info *);
249 /* create directory */
250 int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
251 struct cifs_sb_info *);
252 /* set info on created directory */
253 void (*mkdir_setinfo)(struct inode *, const char *,
254 struct cifs_sb_info *, struct cifs_tcon *,
255 const unsigned int);
256 /* remove directory */
257 int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
258 struct cifs_sb_info *);
249}; 259};
250 260
251struct smb_version_values { 261struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index cf7fb185103c..f1bbf8305d3a 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -289,18 +289,15 @@ extern int CIFSSMBUnixSetFileInfo(const unsigned int xid,
289 u16 fid, u32 pid_of_opener); 289 u16 fid, u32 pid_of_opener);
290 290
291extern int CIFSSMBUnixSetPathInfo(const unsigned int xid, 291extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
292 struct cifs_tcon *tcon, char *file_name, 292 struct cifs_tcon *tcon, const char *file_name,
293 const struct cifs_unix_set_info_args *args, 293 const struct cifs_unix_set_info_args *args,
294 const struct nls_table *nls_codepage, 294 const struct nls_table *nls_codepage,
295 int remap_special_chars); 295 int remap);
296 296
297extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, 297extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
298 const char *newName, 298 const char *name, struct cifs_sb_info *cifs_sb);
299 const struct nls_table *nls_codepage,
300 int remap_special_chars);
301extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, 299extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
302 const char *name, const struct nls_table *nls_codepage, 300 const char *name, struct cifs_sb_info *cifs_sb);
303 int remap_special_chars);
304extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, 301extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
305 const char *name, __u16 type, 302 const char *name, __u16 type,
306 const struct nls_table *nls_codepage, 303 const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index cabc7a01f5df..074923ce593d 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -948,15 +948,15 @@ DelFileRetry:
948} 948}
949 949
950int 950int
951CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, 951CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
952 const char *dirName, const struct nls_table *nls_codepage, 952 struct cifs_sb_info *cifs_sb)
953 int remap)
954{ 953{
955 DELETE_DIRECTORY_REQ *pSMB = NULL; 954 DELETE_DIRECTORY_REQ *pSMB = NULL;
956 DELETE_DIRECTORY_RSP *pSMBr = NULL; 955 DELETE_DIRECTORY_RSP *pSMBr = NULL;
957 int rc = 0; 956 int rc = 0;
958 int bytes_returned; 957 int bytes_returned;
959 int name_len; 958 int name_len;
959 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
960 960
961 cFYI(1, "In CIFSSMBRmDir"); 961 cFYI(1, "In CIFSSMBRmDir");
962RmDirRetry: 962RmDirRetry:
@@ -966,14 +966,15 @@ RmDirRetry:
966 return rc; 966 return rc;
967 967
968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
969 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName, 969 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
970 PATH_MAX, nls_codepage, remap); 970 PATH_MAX, cifs_sb->local_nls,
971 remap);
971 name_len++; /* trailing null */ 972 name_len++; /* trailing null */
972 name_len *= 2; 973 name_len *= 2;
973 } else { /* BB improve check for buffer overruns BB */ 974 } else { /* BB improve check for buffer overruns BB */
974 name_len = strnlen(dirName, PATH_MAX); 975 name_len = strnlen(name, PATH_MAX);
975 name_len++; /* trailing null */ 976 name_len++; /* trailing null */
976 strncpy(pSMB->DirName, dirName, name_len); 977 strncpy(pSMB->DirName, name, name_len);
977 } 978 }
978 979
979 pSMB->BufferFormat = 0x04; 980 pSMB->BufferFormat = 0x04;
@@ -992,14 +993,15 @@ RmDirRetry:
992} 993}
993 994
994int 995int
995CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, 996CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
996 const char *name, const struct nls_table *nls_codepage, int remap) 997 struct cifs_sb_info *cifs_sb)
997{ 998{
998 int rc = 0; 999 int rc = 0;
999 CREATE_DIRECTORY_REQ *pSMB = NULL; 1000 CREATE_DIRECTORY_REQ *pSMB = NULL;
1000 CREATE_DIRECTORY_RSP *pSMBr = NULL; 1001 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1001 int bytes_returned; 1002 int bytes_returned;
1002 int name_len; 1003 int name_len;
1004 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
1003 1005
1004 cFYI(1, "In CIFSSMBMkDir"); 1006 cFYI(1, "In CIFSSMBMkDir");
1005MkDirRetry: 1007MkDirRetry:
@@ -1010,7 +1012,8 @@ MkDirRetry:
1010 1012
1011 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 1013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1012 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, 1014 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1013 PATH_MAX, nls_codepage, remap); 1015 PATH_MAX, cifs_sb->local_nls,
1016 remap);
1014 name_len++; /* trailing null */ 1017 name_len++; /* trailing null */
1015 name_len *= 2; 1018 name_len *= 2;
1016 } else { /* BB improve check for buffer overruns BB */ 1019 } else { /* BB improve check for buffer overruns BB */
@@ -5943,7 +5946,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
5943 5946
5944int 5947int
5945CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, 5948CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
5946 char *fileName, 5949 const char *file_name,
5947 const struct cifs_unix_set_info_args *args, 5950 const struct cifs_unix_set_info_args *args,
5948 const struct nls_table *nls_codepage, int remap) 5951 const struct nls_table *nls_codepage, int remap)
5949{ 5952{
@@ -5964,14 +5967,14 @@ setPermsRetry:
5964 5967
5965 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 5968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5966 name_len = 5969 name_len =
5967 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, 5970 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5968 PATH_MAX, nls_codepage, remap); 5971 PATH_MAX, nls_codepage, remap);
5969 name_len++; /* trailing null */ 5972 name_len++; /* trailing null */
5970 name_len *= 2; 5973 name_len *= 2;
5971 } else { /* BB improve the check for buffer overruns BB */ 5974 } else { /* BB improve the check for buffer overruns BB */
5972 name_len = strnlen(fileName, PATH_MAX); 5975 name_len = strnlen(file_name, PATH_MAX);
5973 name_len++; /* trailing null */ 5976 name_len++; /* trailing null */
5974 strncpy(pSMB->FileName, fileName, name_len); 5977 strncpy(pSMB->FileName, file_name, name_len);
5975 } 5978 }
5976 5979
5977 params = 6 + name_len; 5980 params = 6 + name_len;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 35cb6a374a45..7354877fa3bd 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1219,16 +1219,153 @@ unlink_out:
1219 return rc; 1219 return rc;
1220} 1220}
1221 1221
1222static int
1223cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
1224 const char *full_path, struct cifs_sb_info *cifs_sb,
1225 struct cifs_tcon *tcon, const unsigned int xid)
1226{
1227 int rc = 0;
1228 struct inode *newinode = NULL;
1229
1230 if (tcon->unix_ext)
1231 rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
1232 xid);
1233 else
1234 rc = cifs_get_inode_info(&newinode, full_path, NULL,
1235 inode->i_sb, xid, NULL);
1236 if (rc)
1237 return rc;
1238
1239 d_instantiate(dentry, newinode);
1240 /*
1241 * setting nlink not necessary except in cases where we failed to get it
1242 * from the server or was set bogus
1243 */
1244 if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
1245 set_nlink(dentry->d_inode, 2);
1246
1247 mode &= ~current_umask();
1248 /* must turn on setgid bit if parent dir has it */
1249 if (inode->i_mode & S_ISGID)
1250 mode |= S_ISGID;
1251
1252 if (tcon->unix_ext) {
1253 struct cifs_unix_set_info_args args = {
1254 .mode = mode,
1255 .ctime = NO_CHANGE_64,
1256 .atime = NO_CHANGE_64,
1257 .mtime = NO_CHANGE_64,
1258 .device = 0,
1259 };
1260 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
1261 args.uid = (__u64)current_fsuid();
1262 if (inode->i_mode & S_ISGID)
1263 args.gid = (__u64)inode->i_gid;
1264 else
1265 args.gid = (__u64)current_fsgid();
1266 } else {
1267 args.uid = NO_CHANGE_64;
1268 args.gid = NO_CHANGE_64;
1269 }
1270 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
1271 cifs_sb->local_nls,
1272 cifs_sb->mnt_cifs_flags &
1273 CIFS_MOUNT_MAP_SPECIAL_CHR);
1274 } else {
1275 struct TCP_Server_Info *server = tcon->ses->server;
1276 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1277 (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
1278 server->ops->mkdir_setinfo(newinode, full_path, cifs_sb,
1279 tcon, xid);
1280 if (dentry->d_inode) {
1281 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
1282 dentry->d_inode->i_mode = (mode | S_IFDIR);
1283
1284 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
1285 dentry->d_inode->i_uid = current_fsuid();
1286 if (inode->i_mode & S_ISGID)
1287 dentry->d_inode->i_gid = inode->i_gid;
1288 else
1289 dentry->d_inode->i_gid =
1290 current_fsgid();
1291 }
1292 }
1293 }
1294 return rc;
1295}
1296
1297static int
1298cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
1299 const char *full_path, struct cifs_sb_info *cifs_sb,
1300 struct cifs_tcon *tcon, const unsigned int xid)
1301{
1302 int rc = 0;
1303 u32 oplock = 0;
1304 FILE_UNIX_BASIC_INFO *info = NULL;
1305 struct inode *newinode = NULL;
1306 struct cifs_fattr fattr;
1307
1308 info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
1309 if (info == NULL) {
1310 rc = -ENOMEM;
1311 goto posix_mkdir_out;
1312 }
1313
1314 mode &= ~current_umask();
1315 rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
1316 NULL /* netfid */, info, &oplock, full_path,
1317 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1318 CIFS_MOUNT_MAP_SPECIAL_CHR);
1319 if (rc == -EOPNOTSUPP)
1320 goto posix_mkdir_out;
1321 else if (rc) {
1322 cFYI(1, "posix mkdir returned 0x%x", rc);
1323 d_drop(dentry);
1324 goto posix_mkdir_out;
1325 }
1326
1327 if (info->Type == cpu_to_le32(-1))
1328 /* no return info, go query for it */
1329 goto posix_mkdir_get_info;
1330 /*
1331 * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
1332 * need to set uid/gid.
1333 */
1334
1335 cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
1336 cifs_fill_uniqueid(inode->i_sb, &fattr);
1337 newinode = cifs_iget(inode->i_sb, &fattr);
1338 if (!newinode)
1339 goto posix_mkdir_get_info;
1340
1341 d_instantiate(dentry, newinode);
1342
1343#ifdef CONFIG_CIFS_DEBUG2
1344 cFYI(1, "instantiated dentry %p %s to inode %p", dentry,
1345 dentry->d_name.name, newinode);
1346
1347 if (newinode->i_nlink != 2)
1348 cFYI(1, "unexpected number of links %d", newinode->i_nlink);
1349#endif
1350
1351posix_mkdir_out:
1352 kfree(info);
1353 return rc;
1354posix_mkdir_get_info:
1355 rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
1356 xid);
1357 goto posix_mkdir_out;
1358}
1359
1222int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) 1360int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
1223{ 1361{
1224 int rc = 0, tmprc; 1362 int rc = 0;
1225 unsigned int xid; 1363 unsigned int xid;
1226 struct cifs_sb_info *cifs_sb; 1364 struct cifs_sb_info *cifs_sb;
1227 struct tcon_link *tlink; 1365 struct tcon_link *tlink;
1228 struct cifs_tcon *tcon; 1366 struct cifs_tcon *tcon;
1229 char *full_path = NULL; 1367 struct TCP_Server_Info *server;
1230 struct inode *newinode = NULL; 1368 char *full_path;
1231 struct cifs_fattr fattr;
1232 1369
1233 cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode); 1370 cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
1234 1371
@@ -1248,145 +1385,29 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
1248 1385
1249 if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 1386 if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
1250 le64_to_cpu(tcon->fsUnixInfo.Capability))) { 1387 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1251 u32 oplock = 0; 1388 rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
1252 FILE_UNIX_BASIC_INFO *pInfo = 1389 tcon, xid);
1253 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 1390 if (rc != -EOPNOTSUPP)
1254 if (pInfo == NULL) {
1255 rc = -ENOMEM;
1256 goto mkdir_out; 1391 goto mkdir_out;
1257 } 1392 }
1258
1259 mode &= ~current_umask();
1260 rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
1261 mode, NULL /* netfid */, pInfo, &oplock,
1262 full_path, cifs_sb->local_nls,
1263 cifs_sb->mnt_cifs_flags &
1264 CIFS_MOUNT_MAP_SPECIAL_CHR);
1265 if (rc == -EOPNOTSUPP) {
1266 kfree(pInfo);
1267 goto mkdir_retry_old;
1268 } else if (rc) {
1269 cFYI(1, "posix mkdir returned 0x%x", rc);
1270 d_drop(direntry);
1271 } else {
1272 if (pInfo->Type == cpu_to_le32(-1)) {
1273 /* no return info, go query for it */
1274 kfree(pInfo);
1275 goto mkdir_get_info;
1276 }
1277/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
1278 to set uid/gid */
1279
1280 cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
1281 cifs_fill_uniqueid(inode->i_sb, &fattr);
1282 newinode = cifs_iget(inode->i_sb, &fattr);
1283 if (!newinode) {
1284 kfree(pInfo);
1285 goto mkdir_get_info;
1286 }
1287
1288 d_instantiate(direntry, newinode);
1289 1393
1290#ifdef CONFIG_CIFS_DEBUG2 1394 server = tcon->ses->server;
1291 cFYI(1, "instantiated dentry %p %s to inode %p",
1292 direntry, direntry->d_name.name, newinode);
1293 1395
1294 if (newinode->i_nlink != 2) 1396 if (!server->ops->mkdir) {
1295 cFYI(1, "unexpected number of links %d", 1397 rc = -ENOSYS;
1296 newinode->i_nlink);
1297#endif
1298 }
1299 kfree(pInfo);
1300 goto mkdir_out; 1398 goto mkdir_out;
1301 } 1399 }
1302mkdir_retry_old: 1400
1303 /* BB add setting the equivalent of mode via CreateX w/ACLs */ 1401 /* BB add setting the equivalent of mode via CreateX w/ACLs */
1304 rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls, 1402 rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb);
1305 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1306 if (rc) { 1403 if (rc) {
1307 cFYI(1, "cifs_mkdir returned 0x%x", rc); 1404 cFYI(1, "cifs_mkdir returned 0x%x", rc);
1308 d_drop(direntry); 1405 d_drop(direntry);
1309 } else { 1406 goto mkdir_out;
1310mkdir_get_info:
1311 if (tcon->unix_ext)
1312 rc = cifs_get_inode_info_unix(&newinode, full_path,
1313 inode->i_sb, xid);
1314 else
1315 rc = cifs_get_inode_info(&newinode, full_path, NULL,
1316 inode->i_sb, xid, NULL);
1317
1318 d_instantiate(direntry, newinode);
1319 /* setting nlink not necessary except in cases where we
1320 * failed to get it from the server or was set bogus */
1321 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
1322 set_nlink(direntry->d_inode, 2);
1323
1324 mode &= ~current_umask();
1325 /* must turn on setgid bit if parent dir has it */
1326 if (inode->i_mode & S_ISGID)
1327 mode |= S_ISGID;
1328
1329 if (tcon->unix_ext) {
1330 struct cifs_unix_set_info_args args = {
1331 .mode = mode,
1332 .ctime = NO_CHANGE_64,
1333 .atime = NO_CHANGE_64,
1334 .mtime = NO_CHANGE_64,
1335 .device = 0,
1336 };
1337 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
1338 args.uid = (__u64)current_fsuid();
1339 if (inode->i_mode & S_ISGID)
1340 args.gid = (__u64)inode->i_gid;
1341 else
1342 args.gid = (__u64)current_fsgid();
1343 } else {
1344 args.uid = NO_CHANGE_64;
1345 args.gid = NO_CHANGE_64;
1346 }
1347 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
1348 cifs_sb->local_nls,
1349 cifs_sb->mnt_cifs_flags &
1350 CIFS_MOUNT_MAP_SPECIAL_CHR);
1351 } else {
1352 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1353 (mode & S_IWUGO) == 0) {
1354 FILE_BASIC_INFO pInfo;
1355 struct cifsInodeInfo *cifsInode;
1356 u32 dosattrs;
1357
1358 memset(&pInfo, 0, sizeof(pInfo));
1359 cifsInode = CIFS_I(newinode);
1360 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1361 pInfo.Attributes = cpu_to_le32(dosattrs);
1362 tmprc = CIFSSMBSetPathInfo(xid, tcon,
1363 full_path, &pInfo,
1364 cifs_sb->local_nls,
1365 cifs_sb->mnt_cifs_flags &
1366 CIFS_MOUNT_MAP_SPECIAL_CHR);
1367 if (tmprc == 0)
1368 cifsInode->cifsAttrs = dosattrs;
1369 }
1370 if (direntry->d_inode) {
1371 if (cifs_sb->mnt_cifs_flags &
1372 CIFS_MOUNT_DYNPERM)
1373 direntry->d_inode->i_mode =
1374 (mode | S_IFDIR);
1375
1376 if (cifs_sb->mnt_cifs_flags &
1377 CIFS_MOUNT_SET_UID) {
1378 direntry->d_inode->i_uid =
1379 current_fsuid();
1380 if (inode->i_mode & S_ISGID)
1381 direntry->d_inode->i_gid =
1382 inode->i_gid;
1383 else
1384 direntry->d_inode->i_gid =
1385 current_fsgid();
1386 }
1387 }
1388 }
1389 } 1407 }
1408
1409 rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
1410 xid);
1390mkdir_out: 1411mkdir_out:
1391 /* 1412 /*
1392 * Force revalidate to get parent dir info when needed since cached 1413 * Force revalidate to get parent dir info when needed since cached
@@ -1405,7 +1426,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1405 unsigned int xid; 1426 unsigned int xid;
1406 struct cifs_sb_info *cifs_sb; 1427 struct cifs_sb_info *cifs_sb;
1407 struct tcon_link *tlink; 1428 struct tcon_link *tlink;
1408 struct cifs_tcon *pTcon; 1429 struct cifs_tcon *tcon;
1430 struct TCP_Server_Info *server;
1409 char *full_path = NULL; 1431 char *full_path = NULL;
1410 struct cifsInodeInfo *cifsInode; 1432 struct cifsInodeInfo *cifsInode;
1411 1433
@@ -1425,10 +1447,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1425 rc = PTR_ERR(tlink); 1447 rc = PTR_ERR(tlink);
1426 goto rmdir_exit; 1448 goto rmdir_exit;
1427 } 1449 }
1428 pTcon = tlink_tcon(tlink); 1450 tcon = tlink_tcon(tlink);
1451 server = tcon->ses->server;
1452
1453 if (!server->ops->rmdir) {
1454 rc = -ENOSYS;
1455 cifs_put_tlink(tlink);
1456 goto rmdir_exit;
1457 }
1429 1458
1430 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, 1459 rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
1431 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1432 cifs_put_tlink(tlink); 1460 cifs_put_tlink(tlink);
1433 1461
1434 if (!rc) { 1462 if (!rc) {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index c40356d24c5c..3129ac74b819 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -586,6 +586,27 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
586#endif 586#endif
587} 587}
588 588
589static void
590cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
591 struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
592 const unsigned int xid)
593{
594 FILE_BASIC_INFO info;
595 struct cifsInodeInfo *cifsInode;
596 u32 dosattrs;
597 int rc;
598
599 memset(&info, 0, sizeof(info));
600 cifsInode = CIFS_I(inode);
601 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
602 info.Attributes = cpu_to_le32(dosattrs);
603 rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
604 cifs_sb->mnt_cifs_flags &
605 CIFS_MOUNT_MAP_SPECIAL_CHR);
606 if (rc == 0)
607 cifsInode->cifsAttrs = dosattrs;
608}
609
589struct smb_version_operations smb1_operations = { 610struct smb_version_operations smb1_operations = {
590 .send_cancel = send_nt_cancel, 611 .send_cancel = send_nt_cancel,
591 .compare_fids = cifs_compare_fids, 612 .compare_fids = cifs_compare_fids,
@@ -620,6 +641,9 @@ struct smb_version_operations smb1_operations = {
620 .get_srv_inum = cifs_get_srv_inum, 641 .get_srv_inum = cifs_get_srv_inum,
621 .build_path_to_root = cifs_build_path_to_root, 642 .build_path_to_root = cifs_build_path_to_root,
622 .echo = CIFSSMBEcho, 643 .echo = CIFSSMBEcho,
644 .mkdir = CIFSSMBMkDir,
645 .mkdir_setinfo = cifs_mkdir_setinfo,
646 .rmdir = CIFSSMBRmDir,
623}; 647};
624 648
625struct smb_version_values smb1_values = { 649struct smb_version_values smb1_values = {
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1ba5c405315c..2aa5cb08c526 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -122,3 +122,42 @@ out:
122 kfree(smb2_data); 122 kfree(smb2_data);
123 return rc; 123 return rc;
124} 124}
125
126int
127smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
128 struct cifs_sb_info *cifs_sb)
129{
130 return smb2_open_op_close(xid, tcon, cifs_sb, name,
131 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
132 CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
133}
134
135void
136smb2_mkdir_setinfo(struct inode *inode, const char *name,
137 struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
138 const unsigned int xid)
139{
140 FILE_BASIC_INFO data;
141 struct cifsInodeInfo *cifs_i;
142 u32 dosattrs;
143 int tmprc;
144
145 memset(&data, 0, sizeof(data));
146 cifs_i = CIFS_I(inode);
147 dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
148 data.Attributes = cpu_to_le32(dosattrs);
149 tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name,
150 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
151 CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
152 if (tmprc == 0)
153 cifs_i->cifsAttrs = dosattrs;
154}
155
156int
157smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
158 struct cifs_sb_info *cifs_sb)
159{
160 return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
161 0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
162 NULL, SMB2_OP_DELETE);
163}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 410cf925ea26..826209bf3684 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -318,6 +318,9 @@ struct smb_version_operations smb21_operations = {
318 .query_path_info = smb2_query_path_info, 318 .query_path_info = smb2_query_path_info,
319 .get_srv_inum = smb2_get_srv_inum, 319 .get_srv_inum = smb2_get_srv_inum,
320 .build_path_to_root = smb2_build_path_to_root, 320 .build_path_to_root = smb2_build_path_to_root,
321 .mkdir = smb2_mkdir,
322 .mkdir_setinfo = smb2_mkdir_setinfo,
323 .rmdir = smb2_rmdir,
321}; 324};
322 325
323struct smb_version_values smb21_values = { 326struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 902bbe2b5ad3..bfaa7b148afd 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -52,6 +52,14 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
52 struct cifs_sb_info *cifs_sb, 52 struct cifs_sb_info *cifs_sb,
53 const char *full_path, FILE_ALL_INFO *data, 53 const char *full_path, FILE_ALL_INFO *data,
54 bool *adjust_tz); 54 bool *adjust_tz);
55extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
56 const char *name, struct cifs_sb_info *cifs_sb);
57extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
58 struct cifs_sb_info *cifs_sb,
59 struct cifs_tcon *tcon, const unsigned int xid);
60extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
61 const char *name, struct cifs_sb_info *cifs_sb);
62
55/* 63/*
56 * SMB2 Worker functions - most of protocol specific implementation details 64 * SMB2 Worker functions - most of protocol specific implementation details
57 * are contained within these calls. 65 * are contained within these calls.