aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-07-13 06:04:46 -0400
committerSteve French <smfrench@gmail.com>2012-07-27 16:17:16 -0400
commitff691e969433a54e26fb6502a6613e02c680e8ee (patch)
tree3a9fdbbcf7adca4f90f303dc65acef7d9d3b16f4 /fs/cifs/inode.c
parentb387e41e523c1aa347cff055455d0dd129357df4 (diff)
CIFS: Simplify cifs_mkdir call
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c295
1 files changed, 161 insertions, 134 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 35cb6a374a45..e9ba1a150fe3 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1219,16 +1219,165 @@ 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 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1276 (mode & S_IWUGO) == 0) {
1277 FILE_BASIC_INFO info;
1278 struct cifsInodeInfo *cifsInode;
1279 u32 dosattrs;
1280 int tmprc;
1281
1282 memset(&info, 0, sizeof(info));
1283 cifsInode = CIFS_I(newinode);
1284 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1285 info.Attributes = cpu_to_le32(dosattrs);
1286 tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
1287 cifs_sb->local_nls,
1288 cifs_sb->mnt_cifs_flags &
1289 CIFS_MOUNT_MAP_SPECIAL_CHR);
1290 if (tmprc == 0)
1291 cifsInode->cifsAttrs = dosattrs;
1292 }
1293 if (dentry->d_inode) {
1294 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
1295 dentry->d_inode->i_mode = (mode | S_IFDIR);
1296
1297 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
1298 dentry->d_inode->i_uid = current_fsuid();
1299 if (inode->i_mode & S_ISGID)
1300 dentry->d_inode->i_gid = inode->i_gid;
1301 else
1302 dentry->d_inode->i_gid =
1303 current_fsgid();
1304 }
1305 }
1306 }
1307 return rc;
1308}
1309
1310static int
1311cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
1312 const char *full_path, struct cifs_sb_info *cifs_sb,
1313 struct cifs_tcon *tcon, const unsigned int xid)
1314{
1315 int rc = 0;
1316 u32 oplock = 0;
1317 FILE_UNIX_BASIC_INFO *info = NULL;
1318 struct inode *newinode = NULL;
1319 struct cifs_fattr fattr;
1320
1321 info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
1322 if (info == NULL) {
1323 rc = -ENOMEM;
1324 goto posix_mkdir_out;
1325 }
1326
1327 mode &= ~current_umask();
1328 rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
1329 NULL /* netfid */, info, &oplock, full_path,
1330 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1331 CIFS_MOUNT_MAP_SPECIAL_CHR);
1332 if (rc == -EOPNOTSUPP)
1333 goto posix_mkdir_out;
1334 else if (rc) {
1335 cFYI(1, "posix mkdir returned 0x%x", rc);
1336 d_drop(dentry);
1337 goto posix_mkdir_out;
1338 }
1339
1340 if (info->Type == cpu_to_le32(-1))
1341 /* no return info, go query for it */
1342 goto posix_mkdir_get_info;
1343 /*
1344 * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
1345 * need to set uid/gid.
1346 */
1347
1348 cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
1349 cifs_fill_uniqueid(inode->i_sb, &fattr);
1350 newinode = cifs_iget(inode->i_sb, &fattr);
1351 if (!newinode)
1352 goto posix_mkdir_get_info;
1353
1354 d_instantiate(dentry, newinode);
1355
1356#ifdef CONFIG_CIFS_DEBUG2
1357 cFYI(1, "instantiated dentry %p %s to inode %p", dentry,
1358 dentry->d_name.name, newinode);
1359
1360 if (newinode->i_nlink != 2)
1361 cFYI(1, "unexpected number of links %d", newinode->i_nlink);
1362#endif
1363
1364posix_mkdir_out:
1365 kfree(info);
1366 return rc;
1367posix_mkdir_get_info:
1368 rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
1369 xid);
1370 goto posix_mkdir_out;
1371}
1372
1222int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) 1373int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
1223{ 1374{
1224 int rc = 0, tmprc; 1375 int rc = 0;
1225 unsigned int xid; 1376 unsigned int xid;
1226 struct cifs_sb_info *cifs_sb; 1377 struct cifs_sb_info *cifs_sb;
1227 struct tcon_link *tlink; 1378 struct tcon_link *tlink;
1228 struct cifs_tcon *tcon; 1379 struct cifs_tcon *tcon;
1229 char *full_path = NULL; 1380 char *full_path;
1230 struct inode *newinode = NULL;
1231 struct cifs_fattr fattr;
1232 1381
1233 cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode); 1382 cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
1234 1383
@@ -1248,145 +1397,23 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
1248 1397
1249 if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 1398 if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
1250 le64_to_cpu(tcon->fsUnixInfo.Capability))) { 1399 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1251 u32 oplock = 0; 1400 rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
1252 FILE_UNIX_BASIC_INFO *pInfo = 1401 tcon, xid);
1253 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 1402 if (rc != -EOPNOTSUPP)
1254 if (pInfo == NULL) {
1255 rc = -ENOMEM;
1256 goto mkdir_out; 1403 goto mkdir_out;
1257 }
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
1290#ifdef CONFIG_CIFS_DEBUG2
1291 cFYI(1, "instantiated dentry %p %s to inode %p",
1292 direntry, direntry->d_name.name, newinode);
1293
1294 if (newinode->i_nlink != 2)
1295 cFYI(1, "unexpected number of links %d",
1296 newinode->i_nlink);
1297#endif
1298 }
1299 kfree(pInfo);
1300 goto mkdir_out;
1301 } 1404 }
1302mkdir_retry_old: 1405
1303 /* BB add setting the equivalent of mode via CreateX w/ACLs */ 1406 /* BB add setting the equivalent of mode via CreateX w/ACLs */
1304 rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls, 1407 rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
1305 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 1408 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1306 if (rc) { 1409 if (rc) {
1307 cFYI(1, "cifs_mkdir returned 0x%x", rc); 1410 cFYI(1, "cifs_mkdir returned 0x%x", rc);
1308 d_drop(direntry); 1411 d_drop(direntry);
1309 } else { 1412 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 } 1413 }
1414
1415 rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
1416 xid);
1390mkdir_out: 1417mkdir_out:
1391 /* 1418 /*
1392 * Force revalidate to get parent dir info when needed since cached 1419 * Force revalidate to get parent dir info when needed since cached