diff options
author | Dave Hansen <haveblue@us.ibm.com> | 2008-02-15 17:37:57 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-19 00:25:34 -0400 |
commit | 463c3197263bd26ac59a00d2484990e17e35c50e (patch) | |
tree | b27c04f978ccd447ae33f7387b6a4aba0033acc5 /fs | |
parent | 0622753b800e4cc6cb9319b36b27658c72dd7cdc (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.c | 48 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 4 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 24 |
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 | ||
1987 | static 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 | |||
1987 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, | 2004 | asmlinkage 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); | ||
2047 | out_dput: | ||
2048 | dput(dentry); | ||
2049 | out_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); |
2031 | out: | 2052 | out: |
@@ -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); | ||
2112 | out_dput: | ||
2087 | dput(dentry); | 2113 | dput(dentry); |
2088 | out_unlock: | 2114 | out_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); | ||
159 | out_put: | 163 | out_put: |
160 | dput(dentry); | 164 | dput(dentry); |
161 | out_unlock: | 165 | out_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 | */ |