1 /* 2 * dir.c - Operations for sysfs directories. 3 */ 4 5 #undef DEBUG 6 7 #include <linux/fs.h> 8 #include <linux/mount.h> 9 #include <linux/module.h> 10 #include <linux/kobject.h> 11 #include <linux/namei.h> 12 #include "sysfs.h" 13 14 DECLARE_RWSEM(sysfs_rename_sem); 15 16 static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) 17 { 18 struct sysfs_dirent * sd = dentry->d_fsdata; 19 20 if (sd) { 21 BUG_ON(sd->s_dentry != dentry); 22 sd->s_dentry = NULL; 23 sysfs_put(sd); 24 } 25 iput(inode); 26 } 27 28 static struct dentry_operations sysfs_dentry_ops = { 29 .d_iput = sysfs_d_iput, 30 }; 31 32 /* 33 * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent 34 */ 35 static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, 36 void * element) 37 { 38 struct sysfs_dirent * sd; 39 40 sd = kmem_cache_alloc(sysfs_dir_cachep, GFP_KERNEL); 41 if (!sd) 42 return NULL; 43 44 memset(sd, 0, sizeof(*sd)); 45 atomic_set(&sd->s_count, 1); 46 INIT_LIST_HEAD(&sd->s_children); 47 list_add(&sd->s_sibling, &parent_sd->s_children); 48 sd->s_element = element; 49 50 return sd; 51 } 52 53 int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, 54 void * element, umode_t mode, int type) 55 { 56 struct sysfs_dirent * sd; 57 58 sd = sysfs_new_dirent(parent_sd, element); 59 if (!sd) 60 return -ENOMEM; 61 62 sd->s_mode = mode; 63 sd->s_type = type; 64 sd->s_dentry = dentry; 65 if (dentry) { 66 dentry->d_fsdata = sysfs_get(sd); 67 dentry->d_op = &sysfs_dentry_ops; 68 } 69 70 return 0; 71 } 72 73 static int init_dir(struct inode * inode) 74 { 75 inode->i_op = &sysfs_dir_inode_operations; 76 inode->i_fop = &sysfs_dir_operations; 77 78 /* directory inodes start off with i_nlink == 2 (for "." entry) */ 79 inode->i_nlink++; 80 return 0; 81 } 82 83 static int init_file(struct inode * inode) 84 { 85 inode->i_size = PAGE_SIZE; 86 inode->i_fop = &sysfs_file_operations; 87 return 0; 88 } 89 90 static int init_symlink(struct inode * inode) 91 { 92 inode->i_op = &sysfs_symlink_inode_operations; 93 return 0; 94 } 95 96 static int create_dir(struct kobject * k, struct dentry * p, 97 const char * n, struct dentry ** d) 98 { 99 int error; 100 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; 101 102 down(&p->d_inode->i_sem); 103 *d = lookup_one_len(n, p, strlen(n)); 104 if (!IS_ERR(*d)) { 105 error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); 106 if (!error) { 107 error = sysfs_create(*d, mode, init_dir); 108 if (!error) { 109 p->d_inode->i_nlink++; 110 (*d)->d_op = &sysfs_dentry_ops; 111 d_rehash(*d); 112 } 113 } 114 if (error && (error != -EEXIST)) { 115 sysfs_put((*d)->d_fsdata); 116 d_drop(*d); 117 } 118 dput(*d); 119 } else 120 error = PTR_ERR(*d); 121 up(&p->d_inode->i_sem); 122 return error; 123 } 124 125 126 int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d) 127 { 128 return create_dir(k,k->dentry,n,d); 129 } 130 131 /** 132 * sysfs_create_dir - create a directory for an object. 133 * @parent: parent parent object. 134 * @kobj: object we're creating directory for. 135 */ 136 137 int sysfs_create_dir(struct kobject * kobj) 138 { 139 struct dentry * dentry = NULL; 140 struct dentry * parent; 141 int error = 0; 142 143 BUG_ON(!kobj); 144 145 if (kobj->parent) 146 parent = kobj->parent->dentry; 147 else if (sysfs_mount && sysfs_mount->mnt_sb) 148 parent = sysfs_mount->mnt_sb->s_root; 149 else 150 return -EFAULT; 151 152 error = create_dir(kobj,parent,kobject_name(kobj),&dentry); 153 if (!error) 154 kobj->dentry = dentry; 155 return error; 156 } 157 158 /* attaches attribute's sysfs_dirent to the dentry corresponding to the 159 * attribute file 160 */ 161 static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry) 162 { 163 struct attribute * attr = NULL; 164 struct bin_attribute * bin_attr = NULL; 165 int (* init) (struct inode *) = NULL; 166 int error = 0; 167 168 if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { 169 bin_attr = sd->s_element; 170 attr = &bin_attr->attr; 171 } else { 172 attr = sd->s_element; 173 init = init_file; 174 } 175 176 dentry->d_fsdata = sysfs_get(sd); 177 sd->s_dentry = dentry; 178 error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init); 179 if (error) { 180 sysfs_put(sd); 181 return error; 182 } 183 184 if (bin_attr) { 185 dentry->d_inode->i_size = bin_attr->size; 186 dentry->d_inode->i_fop = &bin_fops; 187 } 188 dentry->d_op = &sysfs_dentry_ops; 189 d_rehash(dentry); 190 191 return 0; 192 } 193 194 static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry) 195 { 196 int err = 0; 197 198 dentry->d_fsdata = sysfs_get(sd); 199 sd->s_dentry = dentry; 200 err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink); 201 if (!err) { 202 dentry->d_op = &sysfs_dentry_ops; 203 d_rehash(dentry); 204 } else 205 sysfs_put(sd); 206 207 return err; 208 } 209 210 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, 211 struct nameidata *nd) 212 { 213 struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; 214 struct sysfs_dirent * sd; 215 int err = 0; 216 217 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { 218 if (sd->s_type & SYSFS_NOT_PINNED) { 219 const unsigned char * name = sysfs_get_name(sd); 220 221 if (strcmp(name, dentry->d_name.name)) 222 continue; 223 224 if (sd->s_type & SYSFS_KOBJ_LINK) 225 err = sysfs_attach_link(sd, dentry); 226 else 227 err = sysfs_attach_attr(sd, dentry); 228 break; 229 } 230 } 231 232 return ERR_PTR(err); 233 } 234 235 struct inode_operations sysfs_dir_inode_operations = { 236 .lookup = sysfs_lookup, 237 .setattr = sysfs_setattr, 238 }; 239 240 static void remove_dir(struct dentry * d) 241 { 242 struct dentry * parent = dget(d->d_parent); 243 struct sysfs_dirent * sd; 244 245 down(&parent->d_inode->i_sem); 246 d_delete(d); 247 sd = d->d_fsdata; 248 list_del_init(&sd->s_sibling); 249 sysfs_put(sd); 250 if (d->d_inode) 251 simple_rmdir(parent->d_inode,d); 252 253 pr_debug(" o %s removing done (%d)\n",d->d_name.name, 254 atomic_read(&d->d_count)); 255 256 up(&parent->d_inode->i_sem); 257 dput(parent); 258 } 259 260 void sysfs_remove_subdir(struct dentry * d) 261 { 262 remove_dir(d); 263 } 264 265 266 /** 267 * sysfs_remove_dir - remove an object's directory. 268 * @kobj: object. 269 * 270 * The only thing special about this is that we remove any files in 271 * the directory before we remove the directory, and we've inlined 272 * what used to be sysfs_rmdir() below, instead of calling separately. 273 */ 274 275 void sysfs_remove_dir(struct kobject * kobj) 276 { 277 struct dentry * dentry = dget(kobj->dentry); 278 struct sysfs_dirent * parent_sd; 279 struct sysfs_dirent * sd, * tmp; 280 281 if (!dentry) 282 return; 283 284 pr_debug("sysfs %s: removing dir\n",dentry->d_name.name); 285 down(&dentry->d_inode->i_sem); 286 parent_sd = dentry->d_fsdata; 287 list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) { 288 if (!sd->s_element || !(sd->s_type & SYSFS_NOT_PINNED)) 289 continue; 290 list_del_init(&sd->s_sibling); 291 sysfs_drop_dentry(sd, dentry); 292 sysfs_put(sd); 293 } 294 up(&dentry->d_inode->i_sem); 295 296 remove_dir(dentry); 297 /** 298 * Drop reference from dget() on entrance. 299 */ 300 dput(dentry); 301 } 302 303 int sysfs_rename_dir(struct kobject * kobj, const char *new_name) 304 { 305 int error = 0; 306 struct dentry * new_dentry, * parent; 307 308 if (!strcmp(kobject_name(kobj), new_name)) 309 return -EINVAL; 310 311 if (!kobj->parent) 312 return -EINVAL; 313 314 down_write(&sysfs_rename_sem); 315 parent = kobj->parent->dentry; 316 317 down(&parent->d_inode->i_sem); 318 319 new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); 320 if (!IS_ERR(new_dentry)) { 321 if (!new_dentry->d_inode) { 322 error = kobject_set_name(kobj, "%s", new_name); 323 if (!error) { 324 d_add(new_dentry, NULL); 325 d_move(kobj->dentry, new_dentry); 326 } 327 else 328 d_drop(new_dentry); 329 } else 330 error = -EEXIST; 331 dput(new_dentry); 332 } 333 up(&parent->d_inode->i_sem); 334 up_write(&sysfs_rename_sem); 335 336 return error; 337 } 338 339 static int sysfs_dir_open(struct inode *inode, struct file *file) 340 { 341 struct dentry * dentry = file->f_dentry; 342 struct sysfs_dirent * parent_sd = dentry->d_fsdata; 343 344 down(&dentry->d_inode->i_sem); 345 file->private_data = sysfs_new_dirent(parent_sd, NULL); 346 up(&dentry->d_inode->i_sem); 347 348 return file->private_data ? 0 : -ENOMEM; 349 350 } 351 352 static int sysfs_dir_close(struct inode *inode, struct file *file) 353 { 354 struct dentry * dentry = file->f_dentry; 355 struct sysfs_dirent * cursor = file->private_data; 356 357 down(&dentry->d_inode->i_sem); 358 list_del_init(&cursor->s_sibling); 359 up(&dentry->d_inode->i_sem); 360 361 release_sysfs_dirent(cursor); 362 363 return 0; 364 } 365 366 /* Relationship between s_mode and the DT_xxx types */ 367 static inline unsigned char dt_type(struct sysfs_dirent *sd) 368 { 369 return (sd->s_mode >> 12) & 15; 370 } 371 372 static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) 373 { 374 struct dentry *dentry = filp->f_dentry; 375 struct sysfs_dirent * parent_sd = dentry->d_fsdata; 376 struct sysfs_dirent *cursor = filp->private_data; 377 struct list_head *p, *q = &cursor->s_sibling; 378 ino_t ino; 379 int i = filp->f_pos; 380 381 switch (i) { 382 case 0: 383 ino = dentry->d_inode->i_ino; 384 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) 385 break; 386 filp->f_pos++; 387 i++; 388 /* fallthrough */ 389 case 1: 390 ino = parent_ino(dentry); 391 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) 392 break; 393 filp->f_pos++; 394 i++; 395 /* fallthrough */ 396 default: 397 if (filp->f_pos == 2) { 398 list_del(q); 399 list_add(q, &parent_sd->s_children); 400 } 401 for (p=q->next; p!= &parent_sd->s_children; p=p->next) { 402 struct sysfs_dirent *next; 403 const char * name; 404 int len; 405 406 next = list_entry(p, struct sysfs_dirent, 407 s_sibling); 408 if (!next->s_element) 409 continue; 410 411 name = sysfs_get_name(next); 412 len = strlen(name); 413 if (next->s_dentry) 414 ino = next->s_dentry->d_inode->i_ino; 415 else 416 ino = iunique(sysfs_sb, 2); 417 418 if (filldir(dirent, name, len, filp->f_pos, ino, 419 dt_type(next)) < 0) 420 return 0; 421 422 list_del(q); 423 list_add(q, p); 424 p = q; 425 filp->f_pos++; 426 } 427 } 428 return 0; 429 } 430 431 static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) 432 { 433 struct dentry * dentry = file->f_dentry; 434 435 down(&dentry->d_inode->i_sem); 436 switch (origin) { 437 case 1: 438 offset += file->f_pos; 439 case 0: 440 if (offset >= 0) 441 break; 442 default: 443 up(&file->f_dentry->d_inode->i_sem); 444 return -EINVAL; 445 } 446 if (offset != file->f_pos) { 447 file->f_pos = offset; 448 if (file->f_pos >= 2) { 449 struct sysfs_dirent *sd = dentry->d_fsdata; 450 struct sysfs_dirent *cursor = file->private_data; 451 struct list_head *p; 452 loff_t n = file->f_pos - 2; 453 454 list_del(&cursor->s_sibling); 455 p = sd->s_children.next; 456 while (n && p != &sd->s_children) { 457 struct sysfs_dirent *next; 458 next = list_entry(p, struct sysfs_dirent, 459 s_sibling); 460 if (next->s_element) 461 n--; 462 p = p->next; 463 } 464 list_add_tail(&cursor->s_sibling, p); 465 } 466 } 467 up(&dentry->d_inode->i_sem); 468 return offset; 469 } 470 471 struct file_operations sysfs_dir_operations = { 472 .open = sysfs_dir_open, 473 .release = sysfs_dir_close, 474 .llseek = sysfs_dir_lseek, 475 .read = generic_read_dir, 476 .readdir = sysfs_readdir, 477 }; 478 479 EXPORT_SYMBOL_GPL(sysfs_create_dir); 480 EXPORT_SYMBOL_GPL(sysfs_remove_dir); 481 EXPORT_SYMBOL_GPL(sysfs_rename_dir); 482 483