17063fbf2SJoel Becker /* -*- mode: c; c-basic-offset: 8; -*- 27063fbf2SJoel Becker * vim: noexpandtab sw=8 ts=8 sts=0: 37063fbf2SJoel Becker * 47063fbf2SJoel Becker * inode.c - basic inode and dentry operations. 57063fbf2SJoel Becker * 67063fbf2SJoel Becker * This program is free software; you can redistribute it and/or 77063fbf2SJoel Becker * modify it under the terms of the GNU General Public 87063fbf2SJoel Becker * License as published by the Free Software Foundation; either 97063fbf2SJoel Becker * version 2 of the License, or (at your option) any later version. 107063fbf2SJoel Becker * 117063fbf2SJoel Becker * This program is distributed in the hope that it will be useful, 127063fbf2SJoel Becker * but WITHOUT ANY WARRANTY; without even the implied warranty of 137063fbf2SJoel Becker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 147063fbf2SJoel Becker * General Public License for more details. 157063fbf2SJoel Becker * 167063fbf2SJoel Becker * You should have received a copy of the GNU General Public 177063fbf2SJoel Becker * License along with this program; if not, write to the 187063fbf2SJoel Becker * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 197063fbf2SJoel Becker * Boston, MA 021110-1307, USA. 207063fbf2SJoel Becker * 217063fbf2SJoel Becker * Based on sysfs: 227063fbf2SJoel Becker * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel 237063fbf2SJoel Becker * 247063fbf2SJoel Becker * configfs Copyright (C) 2005 Oracle. All rights reserved. 257063fbf2SJoel Becker * 267063fbf2SJoel Becker * Please see Documentation/filesystems/configfs.txt for more information. 277063fbf2SJoel Becker */ 287063fbf2SJoel Becker 297063fbf2SJoel Becker #undef DEBUG 307063fbf2SJoel Becker 317063fbf2SJoel Becker #include <linux/pagemap.h> 327063fbf2SJoel Becker #include <linux/namei.h> 337063fbf2SJoel Becker #include <linux/backing-dev.h> 343d0f89bbSJoel Becker #include <linux/capability.h> 357063fbf2SJoel Becker 367063fbf2SJoel Becker #include <linux/configfs.h> 377063fbf2SJoel Becker #include "configfs_internal.h" 387063fbf2SJoel Becker 397063fbf2SJoel Becker extern struct super_block * configfs_sb; 407063fbf2SJoel Becker 41f5e54d6eSChristoph Hellwig static const struct address_space_operations configfs_aops = { 427063fbf2SJoel Becker .readpage = simple_readpage, 437063fbf2SJoel Becker .prepare_write = simple_prepare_write, 447063fbf2SJoel Becker .commit_write = simple_commit_write 457063fbf2SJoel Becker }; 467063fbf2SJoel Becker 477063fbf2SJoel Becker static struct backing_dev_info configfs_backing_dev_info = { 487063fbf2SJoel Becker .ra_pages = 0, /* No readahead */ 497063fbf2SJoel Becker .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, 507063fbf2SJoel Becker }; 517063fbf2SJoel Becker 52754661f1SArjan van de Ven static const struct inode_operations configfs_inode_operations ={ 533d0f89bbSJoel Becker .setattr = configfs_setattr, 543d0f89bbSJoel Becker }; 553d0f89bbSJoel Becker 563d0f89bbSJoel Becker int configfs_setattr(struct dentry * dentry, struct iattr * iattr) 577063fbf2SJoel Becker { 583d0f89bbSJoel Becker struct inode * inode = dentry->d_inode; 593d0f89bbSJoel Becker struct configfs_dirent * sd = dentry->d_fsdata; 603d0f89bbSJoel Becker struct iattr * sd_iattr; 613d0f89bbSJoel Becker unsigned int ia_valid = iattr->ia_valid; 623d0f89bbSJoel Becker int error; 633d0f89bbSJoel Becker 643d0f89bbSJoel Becker if (!sd) 653d0f89bbSJoel Becker return -EINVAL; 663d0f89bbSJoel Becker 673d0f89bbSJoel Becker sd_iattr = sd->s_iattr; 683d0f89bbSJoel Becker 693d0f89bbSJoel Becker error = inode_change_ok(inode, iattr); 703d0f89bbSJoel Becker if (error) 713d0f89bbSJoel Becker return error; 723d0f89bbSJoel Becker 733d0f89bbSJoel Becker error = inode_setattr(inode, iattr); 743d0f89bbSJoel Becker if (error) 753d0f89bbSJoel Becker return error; 763d0f89bbSJoel Becker 773d0f89bbSJoel Becker if (!sd_iattr) { 783d0f89bbSJoel Becker /* setting attributes for the first time, allocate now */ 79f8314dc6SPanagiotis Issaris sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); 803d0f89bbSJoel Becker if (!sd_iattr) 813d0f89bbSJoel Becker return -ENOMEM; 823d0f89bbSJoel Becker /* assign default attributes */ 833d0f89bbSJoel Becker sd_iattr->ia_mode = sd->s_mode; 843d0f89bbSJoel Becker sd_iattr->ia_uid = 0; 853d0f89bbSJoel Becker sd_iattr->ia_gid = 0; 863d0f89bbSJoel Becker sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; 873d0f89bbSJoel Becker sd->s_iattr = sd_iattr; 883d0f89bbSJoel Becker } 893d0f89bbSJoel Becker 903d0f89bbSJoel Becker /* attributes were changed atleast once in past */ 913d0f89bbSJoel Becker 923d0f89bbSJoel Becker if (ia_valid & ATTR_UID) 933d0f89bbSJoel Becker sd_iattr->ia_uid = iattr->ia_uid; 943d0f89bbSJoel Becker if (ia_valid & ATTR_GID) 953d0f89bbSJoel Becker sd_iattr->ia_gid = iattr->ia_gid; 963d0f89bbSJoel Becker if (ia_valid & ATTR_ATIME) 973d0f89bbSJoel Becker sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, 983d0f89bbSJoel Becker inode->i_sb->s_time_gran); 993d0f89bbSJoel Becker if (ia_valid & ATTR_MTIME) 1003d0f89bbSJoel Becker sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, 1013d0f89bbSJoel Becker inode->i_sb->s_time_gran); 1023d0f89bbSJoel Becker if (ia_valid & ATTR_CTIME) 1033d0f89bbSJoel Becker sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, 1043d0f89bbSJoel Becker inode->i_sb->s_time_gran); 1053d0f89bbSJoel Becker if (ia_valid & ATTR_MODE) { 1063d0f89bbSJoel Becker umode_t mode = iattr->ia_mode; 1073d0f89bbSJoel Becker 1083d0f89bbSJoel Becker if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) 1093d0f89bbSJoel Becker mode &= ~S_ISGID; 1103d0f89bbSJoel Becker sd_iattr->ia_mode = sd->s_mode = mode; 1113d0f89bbSJoel Becker } 1123d0f89bbSJoel Becker 1133d0f89bbSJoel Becker return error; 1143d0f89bbSJoel Becker } 1153d0f89bbSJoel Becker 1163d0f89bbSJoel Becker static inline void set_default_inode_attr(struct inode * inode, mode_t mode) 1173d0f89bbSJoel Becker { 1187063fbf2SJoel Becker inode->i_mode = mode; 1197063fbf2SJoel Becker inode->i_uid = 0; 1207063fbf2SJoel Becker inode->i_gid = 0; 1213d0f89bbSJoel Becker inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 1223d0f89bbSJoel Becker } 1233d0f89bbSJoel Becker 1243d0f89bbSJoel Becker static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) 1253d0f89bbSJoel Becker { 1263d0f89bbSJoel Becker inode->i_mode = iattr->ia_mode; 1273d0f89bbSJoel Becker inode->i_uid = iattr->ia_uid; 1283d0f89bbSJoel Becker inode->i_gid = iattr->ia_gid; 1293d0f89bbSJoel Becker inode->i_atime = iattr->ia_atime; 1303d0f89bbSJoel Becker inode->i_mtime = iattr->ia_mtime; 1313d0f89bbSJoel Becker inode->i_ctime = iattr->ia_ctime; 1323d0f89bbSJoel Becker } 1333d0f89bbSJoel Becker 1343d0f89bbSJoel Becker struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd) 1353d0f89bbSJoel Becker { 1363d0f89bbSJoel Becker struct inode * inode = new_inode(configfs_sb); 1373d0f89bbSJoel Becker if (inode) { 1387063fbf2SJoel Becker inode->i_blocks = 0; 1397063fbf2SJoel Becker inode->i_mapping->a_ops = &configfs_aops; 1407063fbf2SJoel Becker inode->i_mapping->backing_dev_info = &configfs_backing_dev_info; 1413d0f89bbSJoel Becker inode->i_op = &configfs_inode_operations; 1423d0f89bbSJoel Becker 1433d0f89bbSJoel Becker if (sd->s_iattr) { 1443d0f89bbSJoel Becker /* sysfs_dirent has non-default attributes 1453d0f89bbSJoel Becker * get them for the new inode from persistent copy 1463d0f89bbSJoel Becker * in sysfs_dirent 1473d0f89bbSJoel Becker */ 1483d0f89bbSJoel Becker set_inode_attr(inode, sd->s_iattr); 1493d0f89bbSJoel Becker } else 1503d0f89bbSJoel Becker set_default_inode_attr(inode, mode); 1517063fbf2SJoel Becker } 1527063fbf2SJoel Becker return inode; 1537063fbf2SJoel Becker } 1547063fbf2SJoel Becker 1557063fbf2SJoel Becker int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) 1567063fbf2SJoel Becker { 1577063fbf2SJoel Becker int error = 0; 1587063fbf2SJoel Becker struct inode * inode = NULL; 1597063fbf2SJoel Becker if (dentry) { 1607063fbf2SJoel Becker if (!dentry->d_inode) { 1613d0f89bbSJoel Becker struct configfs_dirent *sd = dentry->d_fsdata; 1623d0f89bbSJoel Becker if ((inode = configfs_new_inode(mode, sd))) { 1637063fbf2SJoel Becker if (dentry->d_parent && dentry->d_parent->d_inode) { 1647063fbf2SJoel Becker struct inode *p_inode = dentry->d_parent->d_inode; 1657063fbf2SJoel Becker p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; 1667063fbf2SJoel Becker } 1677063fbf2SJoel Becker goto Proceed; 1687063fbf2SJoel Becker } 1697063fbf2SJoel Becker else 1707063fbf2SJoel Becker error = -ENOMEM; 1717063fbf2SJoel Becker } else 1727063fbf2SJoel Becker error = -EEXIST; 1737063fbf2SJoel Becker } else 1747063fbf2SJoel Becker error = -ENOENT; 1757063fbf2SJoel Becker goto Done; 1767063fbf2SJoel Becker 1777063fbf2SJoel Becker Proceed: 1787063fbf2SJoel Becker if (init) 1797063fbf2SJoel Becker error = init(inode); 1807063fbf2SJoel Becker if (!error) { 1817063fbf2SJoel Becker d_instantiate(dentry, inode); 1827063fbf2SJoel Becker if (S_ISDIR(mode) || S_ISLNK(mode)) 1837063fbf2SJoel Becker dget(dentry); /* pin link and directory dentries in core */ 1847063fbf2SJoel Becker } else 1857063fbf2SJoel Becker iput(inode); 1867063fbf2SJoel Becker Done: 1877063fbf2SJoel Becker return error; 1887063fbf2SJoel Becker } 1897063fbf2SJoel Becker 1907063fbf2SJoel Becker /* 1917063fbf2SJoel Becker * Get the name for corresponding element represented by the given configfs_dirent 1927063fbf2SJoel Becker */ 1937063fbf2SJoel Becker const unsigned char * configfs_get_name(struct configfs_dirent *sd) 1947063fbf2SJoel Becker { 1953d0f89bbSJoel Becker struct configfs_attribute *attr; 1967063fbf2SJoel Becker 1971a1974fdSEric Sesterhenn / snakebyte BUG_ON(!sd || !sd->s_element); 1987063fbf2SJoel Becker 1997063fbf2SJoel Becker /* These always have a dentry, so use that */ 2007063fbf2SJoel Becker if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK)) 2017063fbf2SJoel Becker return sd->s_dentry->d_name.name; 2027063fbf2SJoel Becker 2037063fbf2SJoel Becker if (sd->s_type & CONFIGFS_ITEM_ATTR) { 2047063fbf2SJoel Becker attr = sd->s_element; 2053d0f89bbSJoel Becker return attr->ca_name; 2067063fbf2SJoel Becker } 2077063fbf2SJoel Becker return NULL; 2087063fbf2SJoel Becker } 2097063fbf2SJoel Becker 2107063fbf2SJoel Becker 2117063fbf2SJoel Becker /* 2127063fbf2SJoel Becker * Unhashes the dentry corresponding to given configfs_dirent 2131b1dcc1bSJes Sorensen * Called with parent inode's i_mutex held. 2147063fbf2SJoel Becker */ 2157063fbf2SJoel Becker void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) 2167063fbf2SJoel Becker { 2177063fbf2SJoel Becker struct dentry * dentry = sd->s_dentry; 2187063fbf2SJoel Becker 2197063fbf2SJoel Becker if (dentry) { 2207063fbf2SJoel Becker spin_lock(&dcache_lock); 2213d0f89bbSJoel Becker spin_lock(&dentry->d_lock); 2227063fbf2SJoel Becker if (!(d_unhashed(dentry) && dentry->d_inode)) { 2237063fbf2SJoel Becker dget_locked(dentry); 2247063fbf2SJoel Becker __d_drop(dentry); 2253d0f89bbSJoel Becker spin_unlock(&dentry->d_lock); 2267063fbf2SJoel Becker spin_unlock(&dcache_lock); 2277063fbf2SJoel Becker simple_unlink(parent->d_inode, dentry); 2283d0f89bbSJoel Becker } else { 2293d0f89bbSJoel Becker spin_unlock(&dentry->d_lock); 2307063fbf2SJoel Becker spin_unlock(&dcache_lock); 2317063fbf2SJoel Becker } 2327063fbf2SJoel Becker } 2333d0f89bbSJoel Becker } 2347063fbf2SJoel Becker 2357063fbf2SJoel Becker void configfs_hash_and_remove(struct dentry * dir, const char * name) 2367063fbf2SJoel Becker { 2377063fbf2SJoel Becker struct configfs_dirent * sd; 2387063fbf2SJoel Becker struct configfs_dirent * parent_sd = dir->d_fsdata; 2397063fbf2SJoel Becker 2403d0f89bbSJoel Becker if (dir->d_inode == NULL) 2413d0f89bbSJoel Becker /* no inode means this hasn't been made visible yet */ 2423d0f89bbSJoel Becker return; 2433d0f89bbSJoel Becker 2441b1dcc1bSJes Sorensen mutex_lock(&dir->d_inode->i_mutex); 2457063fbf2SJoel Becker list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { 2467063fbf2SJoel Becker if (!sd->s_element) 2477063fbf2SJoel Becker continue; 2487063fbf2SJoel Becker if (!strcmp(configfs_get_name(sd), name)) { 2497063fbf2SJoel Becker list_del_init(&sd->s_sibling); 2507063fbf2SJoel Becker configfs_drop_dentry(sd, dir); 2517063fbf2SJoel Becker configfs_put(sd); 2527063fbf2SJoel Becker break; 2537063fbf2SJoel Becker } 2547063fbf2SJoel Becker } 2551b1dcc1bSJes Sorensen mutex_unlock(&dir->d_inode->i_mutex); 2567063fbf2SJoel Becker } 2577063fbf2SJoel Becker 2587063fbf2SJoel Becker 259