diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/proc/base.c | 132 |
1 files changed, 114 insertions, 18 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index be94ddebb413..0697fd089de8 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1238,7 +1238,10 @@ out: | |||
1238 | return ~0U; | 1238 | return ~0U; |
1239 | } | 1239 | } |
1240 | 1240 | ||
1241 | static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) | 1241 | #define PROC_FDINFO_MAX 64 |
1242 | |||
1243 | static int proc_fd_info(struct inode *inode, struct dentry **dentry, | ||
1244 | struct vfsmount **mnt, char *info) | ||
1242 | { | 1245 | { |
1243 | struct task_struct *task = get_proc_task(inode); | 1246 | struct task_struct *task = get_proc_task(inode); |
1244 | struct files_struct *files = NULL; | 1247 | struct files_struct *files = NULL; |
@@ -1257,8 +1260,16 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm | |||
1257 | spin_lock(&files->file_lock); | 1260 | spin_lock(&files->file_lock); |
1258 | file = fcheck_files(files, fd); | 1261 | file = fcheck_files(files, fd); |
1259 | if (file) { | 1262 | if (file) { |
1260 | *mnt = mntget(file->f_path.mnt); | 1263 | if (mnt) |
1261 | *dentry = dget(file->f_path.dentry); | 1264 | *mnt = mntget(file->f_path.mnt); |
1265 | if (dentry) | ||
1266 | *dentry = dget(file->f_path.dentry); | ||
1267 | if (info) | ||
1268 | snprintf(info, PROC_FDINFO_MAX, | ||
1269 | "pos:\t%lli\n" | ||
1270 | "flags:\t0%o\n", | ||
1271 | (long long) file->f_pos, | ||
1272 | file->f_flags); | ||
1262 | spin_unlock(&files->file_lock); | 1273 | spin_unlock(&files->file_lock); |
1263 | put_files_struct(files); | 1274 | put_files_struct(files); |
1264 | return 0; | 1275 | return 0; |
@@ -1269,6 +1280,12 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm | |||
1269 | return -ENOENT; | 1280 | return -ENOENT; |
1270 | } | 1281 | } |
1271 | 1282 | ||
1283 | static int proc_fd_link(struct inode *inode, struct dentry **dentry, | ||
1284 | struct vfsmount **mnt) | ||
1285 | { | ||
1286 | return proc_fd_info(inode, dentry, mnt, NULL); | ||
1287 | } | ||
1288 | |||
1272 | static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | 1289 | static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) |
1273 | { | 1290 | { |
1274 | struct inode *inode = dentry->d_inode; | 1291 | struct inode *inode = dentry->d_inode; |
@@ -1364,7 +1381,9 @@ out_iput: | |||
1364 | goto out; | 1381 | goto out; |
1365 | } | 1382 | } |
1366 | 1383 | ||
1367 | static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd) | 1384 | static struct dentry *proc_lookupfd_common(struct inode *dir, |
1385 | struct dentry *dentry, | ||
1386 | instantiate_t instantiate) | ||
1368 | { | 1387 | { |
1369 | struct task_struct *task = get_proc_task(dir); | 1388 | struct task_struct *task = get_proc_task(dir); |
1370 | unsigned fd = name_to_int(dentry); | 1389 | unsigned fd = name_to_int(dentry); |
@@ -1375,23 +1394,15 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, | |||
1375 | if (fd == ~0U) | 1394 | if (fd == ~0U) |
1376 | goto out; | 1395 | goto out; |
1377 | 1396 | ||
1378 | result = proc_fd_instantiate(dir, dentry, task, &fd); | 1397 | result = instantiate(dir, dentry, task, &fd); |
1379 | out: | 1398 | out: |
1380 | put_task_struct(task); | 1399 | put_task_struct(task); |
1381 | out_no_task: | 1400 | out_no_task: |
1382 | return result; | 1401 | return result; |
1383 | } | 1402 | } |
1384 | 1403 | ||
1385 | static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | 1404 | static int proc_readfd_common(struct file * filp, void * dirent, |
1386 | struct task_struct *task, int fd) | 1405 | filldir_t filldir, instantiate_t instantiate) |
1387 | { | ||
1388 | char name[PROC_NUMBUF]; | ||
1389 | int len = snprintf(name, sizeof(name), "%d", fd); | ||
1390 | return proc_fill_cache(filp, dirent, filldir, name, len, | ||
1391 | proc_fd_instantiate, task, &fd); | ||
1392 | } | ||
1393 | |||
1394 | static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | ||
1395 | { | 1406 | { |
1396 | struct dentry *dentry = filp->f_path.dentry; | 1407 | struct dentry *dentry = filp->f_path.dentry; |
1397 | struct inode *inode = dentry->d_inode; | 1408 | struct inode *inode = dentry->d_inode; |
@@ -1427,12 +1438,17 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | |||
1427 | for (fd = filp->f_pos-2; | 1438 | for (fd = filp->f_pos-2; |
1428 | fd < fdt->max_fds; | 1439 | fd < fdt->max_fds; |
1429 | fd++, filp->f_pos++) { | 1440 | fd++, filp->f_pos++) { |
1441 | char name[PROC_NUMBUF]; | ||
1442 | int len; | ||
1430 | 1443 | ||
1431 | if (!fcheck_files(files, fd)) | 1444 | if (!fcheck_files(files, fd)) |
1432 | continue; | 1445 | continue; |
1433 | rcu_read_unlock(); | 1446 | rcu_read_unlock(); |
1434 | 1447 | ||
1435 | if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) { | 1448 | len = snprintf(name, sizeof(name), "%d", fd); |
1449 | if (proc_fill_cache(filp, dirent, filldir, | ||
1450 | name, len, instantiate, | ||
1451 | p, &fd) < 0) { | ||
1436 | rcu_read_lock(); | 1452 | rcu_read_lock(); |
1437 | break; | 1453 | break; |
1438 | } | 1454 | } |
@@ -1447,6 +1463,32 @@ out_no_task: | |||
1447 | return retval; | 1463 | return retval; |
1448 | } | 1464 | } |
1449 | 1465 | ||
1466 | static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, | ||
1467 | struct nameidata *nd) | ||
1468 | { | ||
1469 | return proc_lookupfd_common(dir, dentry, proc_fd_instantiate); | ||
1470 | } | ||
1471 | |||
1472 | static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir) | ||
1473 | { | ||
1474 | return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate); | ||
1475 | } | ||
1476 | |||
1477 | static ssize_t proc_fdinfo_read(struct file *file, char __user *buf, | ||
1478 | size_t len, loff_t *ppos) | ||
1479 | { | ||
1480 | char tmp[PROC_FDINFO_MAX]; | ||
1481 | int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, NULL, tmp); | ||
1482 | if (!err) | ||
1483 | err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp)); | ||
1484 | return err; | ||
1485 | } | ||
1486 | |||
1487 | static const struct file_operations proc_fdinfo_file_operations = { | ||
1488 | .open = nonseekable_open, | ||
1489 | .read = proc_fdinfo_read, | ||
1490 | }; | ||
1491 | |||
1450 | static const struct file_operations proc_fd_operations = { | 1492 | static const struct file_operations proc_fd_operations = { |
1451 | .read = generic_read_dir, | 1493 | .read = generic_read_dir, |
1452 | .readdir = proc_readfd, | 1494 | .readdir = proc_readfd, |
@@ -1478,6 +1520,58 @@ static const struct inode_operations proc_fd_inode_operations = { | |||
1478 | .setattr = proc_setattr, | 1520 | .setattr = proc_setattr, |
1479 | }; | 1521 | }; |
1480 | 1522 | ||
1523 | static struct dentry *proc_fdinfo_instantiate(struct inode *dir, | ||
1524 | struct dentry *dentry, struct task_struct *task, const void *ptr) | ||
1525 | { | ||
1526 | unsigned fd = *(unsigned *)ptr; | ||
1527 | struct inode *inode; | ||
1528 | struct proc_inode *ei; | ||
1529 | struct dentry *error = ERR_PTR(-ENOENT); | ||
1530 | |||
1531 | inode = proc_pid_make_inode(dir->i_sb, task); | ||
1532 | if (!inode) | ||
1533 | goto out; | ||
1534 | ei = PROC_I(inode); | ||
1535 | ei->fd = fd; | ||
1536 | inode->i_mode = S_IFREG | S_IRUSR; | ||
1537 | inode->i_fop = &proc_fdinfo_file_operations; | ||
1538 | dentry->d_op = &tid_fd_dentry_operations; | ||
1539 | d_add(dentry, inode); | ||
1540 | /* Close the race of the process dying before we return the dentry */ | ||
1541 | if (tid_fd_revalidate(dentry, NULL)) | ||
1542 | error = NULL; | ||
1543 | |||
1544 | out: | ||
1545 | return error; | ||
1546 | } | ||
1547 | |||
1548 | static struct dentry *proc_lookupfdinfo(struct inode *dir, | ||
1549 | struct dentry *dentry, | ||
1550 | struct nameidata *nd) | ||
1551 | { | ||
1552 | return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); | ||
1553 | } | ||
1554 | |||
1555 | static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir) | ||
1556 | { | ||
1557 | return proc_readfd_common(filp, dirent, filldir, | ||
1558 | proc_fdinfo_instantiate); | ||
1559 | } | ||
1560 | |||
1561 | static const struct file_operations proc_fdinfo_operations = { | ||
1562 | .read = generic_read_dir, | ||
1563 | .readdir = proc_readfdinfo, | ||
1564 | }; | ||
1565 | |||
1566 | /* | ||
1567 | * proc directories can do almost nothing.. | ||
1568 | */ | ||
1569 | static const struct inode_operations proc_fdinfo_inode_operations = { | ||
1570 | .lookup = proc_lookupfdinfo, | ||
1571 | .setattr = proc_setattr, | ||
1572 | }; | ||
1573 | |||
1574 | |||
1481 | static struct dentry *proc_pident_instantiate(struct inode *dir, | 1575 | static struct dentry *proc_pident_instantiate(struct inode *dir, |
1482 | struct dentry *dentry, struct task_struct *task, const void *ptr) | 1576 | struct dentry *dentry, struct task_struct *task, const void *ptr) |
1483 | { | 1577 | { |
@@ -1888,6 +1982,7 @@ static const struct inode_operations proc_task_inode_operations; | |||
1888 | static const struct pid_entry tgid_base_stuff[] = { | 1982 | static const struct pid_entry tgid_base_stuff[] = { |
1889 | DIR("task", S_IRUGO|S_IXUGO, task), | 1983 | DIR("task", S_IRUGO|S_IXUGO, task), |
1890 | DIR("fd", S_IRUSR|S_IXUSR, fd), | 1984 | DIR("fd", S_IRUSR|S_IXUSR, fd), |
1985 | DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo), | ||
1891 | INF("environ", S_IRUSR, pid_environ), | 1986 | INF("environ", S_IRUSR, pid_environ), |
1892 | INF("auxv", S_IRUSR, pid_auxv), | 1987 | INF("auxv", S_IRUSR, pid_auxv), |
1893 | INF("status", S_IRUGO, pid_status), | 1988 | INF("status", S_IRUGO, pid_status), |
@@ -2041,7 +2136,7 @@ static struct dentry *proc_pid_instantiate(struct inode *dir, | |||
2041 | inode->i_op = &proc_tgid_base_inode_operations; | 2136 | inode->i_op = &proc_tgid_base_inode_operations; |
2042 | inode->i_fop = &proc_tgid_base_operations; | 2137 | inode->i_fop = &proc_tgid_base_operations; |
2043 | inode->i_flags|=S_IMMUTABLE; | 2138 | inode->i_flags|=S_IMMUTABLE; |
2044 | inode->i_nlink = 4; | 2139 | inode->i_nlink = 5; |
2045 | #ifdef CONFIG_SECURITY | 2140 | #ifdef CONFIG_SECURITY |
2046 | inode->i_nlink += 1; | 2141 | inode->i_nlink += 1; |
2047 | #endif | 2142 | #endif |
@@ -2171,6 +2266,7 @@ out_no_task: | |||
2171 | */ | 2266 | */ |
2172 | static const struct pid_entry tid_base_stuff[] = { | 2267 | static const struct pid_entry tid_base_stuff[] = { |
2173 | DIR("fd", S_IRUSR|S_IXUSR, fd), | 2268 | DIR("fd", S_IRUSR|S_IXUSR, fd), |
2269 | DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo), | ||
2174 | INF("environ", S_IRUSR, pid_environ), | 2270 | INF("environ", S_IRUSR, pid_environ), |
2175 | INF("auxv", S_IRUSR, pid_auxv), | 2271 | INF("auxv", S_IRUSR, pid_auxv), |
2176 | INF("status", S_IRUGO, pid_status), | 2272 | INF("status", S_IRUGO, pid_status), |
@@ -2251,7 +2347,7 @@ static struct dentry *proc_task_instantiate(struct inode *dir, | |||
2251 | inode->i_op = &proc_tid_base_inode_operations; | 2347 | inode->i_op = &proc_tid_base_inode_operations; |
2252 | inode->i_fop = &proc_tid_base_operations; | 2348 | inode->i_fop = &proc_tid_base_operations; |
2253 | inode->i_flags|=S_IMMUTABLE; | 2349 | inode->i_flags|=S_IMMUTABLE; |
2254 | inode->i_nlink = 3; | 2350 | inode->i_nlink = 4; |
2255 | #ifdef CONFIG_SECURITY | 2351 | #ifdef CONFIG_SECURITY |
2256 | inode->i_nlink += 1; | 2352 | inode->i_nlink += 1; |
2257 | #endif | 2353 | #endif |