aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDave Hansen <haveblue@us.ibm.com>2008-02-15 17:37:57 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2008-04-19 00:25:34 -0400
commit463c3197263bd26ac59a00d2484990e17e35c50e (patch)
treeb27c04f978ccd447ae33f7387b6a4aba0033acc5 /fs
parent0622753b800e4cc6cb9319b36b27658c72dd7cdc (diff)
[PATCH] r/o bind mounts: get callers of vfs_mknod/create/mkdir()
This takes care of all of the direct callers of vfs_mknod(). Since a few of these cases also handle normal file creation as well, this also covers some calls to vfs_create(). So that we don't have to make three mnt_want/drop_write() calls inside of the switch statement, we move some of its logic outside of the switch and into a helper function suggested by Christoph. This also encapsulates a fix for mknod(S_IFREG) that Miklos found. [AV: merged mkdir handling, added missing nfsd pieces] Acked-by: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c48
-rw-r--r--fs/nfsd/nfs4recover.c4
-rw-r--r--fs/nfsd/vfs.c24
3 files changed, 63 insertions, 13 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 89ef3178eaaa..3fbcf2021a2e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1984,6 +1984,23 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
1984 return error; 1984 return error;
1985} 1985}
1986 1986
1987static int may_mknod(mode_t mode)
1988{
1989 switch (mode & S_IFMT) {
1990 case S_IFREG:
1991 case S_IFCHR:
1992 case S_IFBLK:
1993 case S_IFIFO:
1994 case S_IFSOCK:
1995 case 0: /* zero mode translates to S_IFREG */
1996 return 0;
1997 case S_IFDIR:
1998 return -EPERM;
1999 default:
2000 return -EINVAL;
2001 }
2002}
2003
1987asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, 2004asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
1988 unsigned dev) 2005 unsigned dev)
1989{ 2006{
@@ -2002,12 +2019,19 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
2002 if (error) 2019 if (error)
2003 goto out; 2020 goto out;
2004 dentry = lookup_create(&nd, 0); 2021 dentry = lookup_create(&nd, 0);
2005 error = PTR_ERR(dentry); 2022 if (IS_ERR(dentry)) {
2006 2023 error = PTR_ERR(dentry);
2024 goto out_unlock;
2025 }
2007 if (!IS_POSIXACL(nd.path.dentry->d_inode)) 2026 if (!IS_POSIXACL(nd.path.dentry->d_inode))
2008 mode &= ~current->fs->umask; 2027 mode &= ~current->fs->umask;
2009 if (!IS_ERR(dentry)) { 2028 error = may_mknod(mode);
2010 switch (mode & S_IFMT) { 2029 if (error)
2030 goto out_dput;
2031 error = mnt_want_write(nd.path.mnt);
2032 if (error)
2033 goto out_dput;
2034 switch (mode & S_IFMT) {
2011 case 0: case S_IFREG: 2035 case 0: case S_IFREG:
2012 error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd); 2036 error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
2013 break; 2037 break;
@@ -2018,14 +2042,11 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
2018 case S_IFIFO: case S_IFSOCK: 2042 case S_IFIFO: case S_IFSOCK:
2019 error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0); 2043 error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
2020 break; 2044 break;
2021 case S_IFDIR:
2022 error = -EPERM;
2023 break;
2024 default:
2025 error = -EINVAL;
2026 }
2027 dput(dentry);
2028 } 2045 }
2046 mnt_drop_write(nd.path.mnt);
2047out_dput:
2048 dput(dentry);
2049out_unlock:
2029 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2050 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
2030 path_put(&nd.path); 2051 path_put(&nd.path);
2031out: 2052out:
@@ -2083,7 +2104,12 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
2083 2104
2084 if (!IS_POSIXACL(nd.path.dentry->d_inode)) 2105 if (!IS_POSIXACL(nd.path.dentry->d_inode))
2085 mode &= ~current->fs->umask; 2106 mode &= ~current->fs->umask;
2107 error = mnt_want_write(nd.path.mnt);
2108 if (error)
2109 goto out_dput;
2086 error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); 2110 error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
2111 mnt_drop_write(nd.path.mnt);
2112out_dput:
2087 dput(dentry); 2113 dput(dentry);
2088out_unlock: 2114out_unlock:
2089 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2115 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 4e77a1a3bd73..145b3c877a27 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -155,7 +155,11 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
155 dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); 155 dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
156 goto out_put; 156 goto out_put;
157 } 157 }
158 status = mnt_want_write(rec_dir.path.mnt);
159 if (status)
160 goto out_put;
158 status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU); 161 status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU);
162 mnt_drop_write(rec_dir.path.mnt);
159out_put: 163out_put:
160 dput(dentry); 164 dput(dentry);
161out_unlock: 165out_unlock:
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index efff58a5818c..14d582467029 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1255,23 +1255,35 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1255 err = 0; 1255 err = 0;
1256 switch (type) { 1256 switch (type) {
1257 case S_IFREG: 1257 case S_IFREG:
1258 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1259 if (host_err)
1260 goto out_nfserr;
1258 host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); 1261 host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
1259 break; 1262 break;
1260 case S_IFDIR: 1263 case S_IFDIR:
1264 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1265 if (host_err)
1266 goto out_nfserr;
1261 host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); 1267 host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
1262 break; 1268 break;
1263 case S_IFCHR: 1269 case S_IFCHR:
1264 case S_IFBLK: 1270 case S_IFBLK:
1265 case S_IFIFO: 1271 case S_IFIFO:
1266 case S_IFSOCK: 1272 case S_IFSOCK:
1273 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1274 if (host_err)
1275 goto out_nfserr;
1267 host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); 1276 host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
1268 break; 1277 break;
1269 default: 1278 default:
1270 printk("nfsd: bad file type %o in nfsd_create\n", type); 1279 printk("nfsd: bad file type %o in nfsd_create\n", type);
1271 host_err = -EINVAL; 1280 host_err = -EINVAL;
1281 goto out_nfserr;
1272 } 1282 }
1273 if (host_err < 0) 1283 if (host_err < 0) {
1284 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1274 goto out_nfserr; 1285 goto out_nfserr;
1286 }
1275 1287
1276 if (EX_ISSYNC(fhp->fh_export)) { 1288 if (EX_ISSYNC(fhp->fh_export)) {
1277 err = nfserrno(nfsd_sync_dir(dentry)); 1289 err = nfserrno(nfsd_sync_dir(dentry));
@@ -1282,6 +1294,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1282 err2 = nfsd_create_setattr(rqstp, resfhp, iap); 1294 err2 = nfsd_create_setattr(rqstp, resfhp, iap);
1283 if (err2) 1295 if (err2)
1284 err = err2; 1296 err = err2;
1297 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1285 /* 1298 /*
1286 * Update the file handle to get the new inode info. 1299 * Update the file handle to get the new inode info.
1287 */ 1300 */
@@ -1359,6 +1372,9 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1359 v_atime = verifier[1]&0x7fffffff; 1372 v_atime = verifier[1]&0x7fffffff;
1360 } 1373 }
1361 1374
1375 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1376 if (host_err)
1377 goto out_nfserr;
1362 if (dchild->d_inode) { 1378 if (dchild->d_inode) {
1363 err = 0; 1379 err = 0;
1364 1380
@@ -1390,12 +1406,15 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1390 case NFS3_CREATE_GUARDED: 1406 case NFS3_CREATE_GUARDED:
1391 err = nfserr_exist; 1407 err = nfserr_exist;
1392 } 1408 }
1409 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1393 goto out; 1410 goto out;
1394 } 1411 }
1395 1412
1396 host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); 1413 host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
1397 if (host_err < 0) 1414 if (host_err < 0) {
1415 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1398 goto out_nfserr; 1416 goto out_nfserr;
1417 }
1399 if (created) 1418 if (created)
1400 *created = 1; 1419 *created = 1;
1401 1420
@@ -1420,6 +1439,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1420 if (err2) 1439 if (err2)
1421 err = err2; 1440 err = err2;
1422 1441
1442 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1423 /* 1443 /*
1424 * Update the filehandle to get the new inode info. 1444 * Update the filehandle to get the new inode info.
1425 */ 1445 */