1 /* 2 * fs/sysfs/file.c - sysfs regular (text) file implementation 3 * 4 * Copyright (c) 2001-3 Patrick Mochel 5 * Copyright (c) 2007 SUSE Linux Products GmbH 6 * Copyright (c) 2007 Tejun Heo <teheo@suse.de> 7 * 8 * This file is released under the GPLv2. 9 * 10 * Please see Documentation/filesystems/sysfs.txt for more information. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/kobject.h> 15 #include <linux/kallsyms.h> 16 #include <linux/slab.h> 17 #include <linux/list.h> 18 #include <linux/mutex.h> 19 #include <linux/seq_file.h> 20 21 #include "sysfs.h" 22 #include "../kernfs/kernfs-internal.h" 23 24 /* 25 * Determine ktype->sysfs_ops for the given kernfs_node. This function 26 * must be called while holding an active reference. 27 */ 28 static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) 29 { 30 struct kobject *kobj = kn->parent->priv; 31 32 if (kn->flags & KERNFS_LOCKDEP) 33 lockdep_assert_held(kn); 34 return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; 35 } 36 37 /* 38 * Reads on sysfs are handled through seq_file, which takes care of hairy 39 * details like buffering and seeking. The following function pipes 40 * sysfs_ops->show() result through seq_file. 41 */ 42 static int sysfs_kf_seq_show(struct seq_file *sf, void *v) 43 { 44 struct kernfs_open_file *of = sf->private; 45 struct kobject *kobj = of->kn->parent->priv; 46 const struct sysfs_ops *ops = sysfs_file_ops(of->kn); 47 ssize_t count; 48 char *buf; 49 50 /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */ 51 count = seq_get_buf(sf, &buf); 52 if (count < PAGE_SIZE) { 53 seq_commit(sf, -1); 54 return 0; 55 } 56 memset(buf, 0, PAGE_SIZE); 57 58 /* 59 * Invoke show(). Control may reach here via seq file lseek even 60 * if @ops->show() isn't implemented. 61 */ 62 if (ops->show) { 63 count = ops->show(kobj, of->kn->priv, buf); 64 if (count < 0) 65 return count; 66 } 67 68 /* 69 * The code works fine with PAGE_SIZE return but it's likely to 70 * indicate truncated result or overflow in normal use cases. 71 */ 72 if (count >= (ssize_t)PAGE_SIZE) { 73 print_symbol("fill_read_buffer: %s returned bad count\n", 74 (unsigned long)ops->show); 75 /* Try to struggle along */ 76 count = PAGE_SIZE - 1; 77 } 78 seq_commit(sf, count); 79 return 0; 80 } 81 82 static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, 83 size_t count, loff_t pos) 84 { 85 struct bin_attribute *battr = of->kn->priv; 86 struct kobject *kobj = of->kn->parent->priv; 87 loff_t size = file_inode(of->file)->i_size; 88 89 if (!count) 90 return 0; 91 92 if (size) { 93 if (pos >= size) 94 return 0; 95 if (pos + count > size) 96 count = size - pos; 97 } 98 99 if (!battr->read) 100 return -EIO; 101 102 return battr->read(of->file, kobj, battr, buf, pos, count); 103 } 104 105 /* kernfs read callback for regular sysfs files with pre-alloc */ 106 static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf, 107 size_t count, loff_t pos) 108 { 109 const struct sysfs_ops *ops = sysfs_file_ops(of->kn); 110 struct kobject *kobj = of->kn->parent->priv; 111 ssize_t len; 112 113 /* 114 * If buf != of->prealloc_buf, we don't know how 115 * large it is, so cannot safely pass it to ->show 116 */ 117 if (WARN_ON_ONCE(buf != of->prealloc_buf)) 118 return 0; 119 len = ops->show(kobj, of->kn->priv, buf); 120 if (len < 0) 121 return len; 122 if (pos) { 123 if (len <= pos) 124 return 0; 125 len -= pos; 126 memmove(buf, buf + pos, len); 127 } 128 return min_t(ssize_t, count, len); 129 } 130 131 /* kernfs write callback for regular sysfs files */ 132 static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, 133 size_t count, loff_t pos) 134 { 135 const struct sysfs_ops *ops = sysfs_file_ops(of->kn); 136 struct kobject *kobj = of->kn->parent->priv; 137 138 if (!count) 139 return 0; 140 141 return ops->store(kobj, of->kn->priv, buf, count); 142 } 143 144 /* kernfs write callback for bin sysfs files */ 145 static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, 146 size_t count, loff_t pos) 147 { 148 struct bin_attribute *battr = of->kn->priv; 149 struct kobject *kobj = of->kn->parent->priv; 150 loff_t size = file_inode(of->file)->i_size; 151 152 if (size) { 153 if (size <= pos) 154 return -EFBIG; 155 count = min_t(ssize_t, count, size - pos); 156 } 157 if (!count) 158 return 0; 159 160 if (!battr->write) 161 return -EIO; 162 163 return battr->write(of->file, kobj, battr, buf, pos, count); 164 } 165 166 static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, 167 struct vm_area_struct *vma) 168 { 169 struct bin_attribute *battr = of->kn->priv; 170 struct kobject *kobj = of->kn->parent->priv; 171 172 return battr->mmap(of->file, kobj, battr, vma); 173 } 174 175 void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr) 176 { 177 struct kernfs_node *kn = kobj->sd, *tmp; 178 179 if (kn && dir) 180 kn = kernfs_find_and_get(kn, dir); 181 else 182 kernfs_get(kn); 183 184 if (kn && attr) { 185 tmp = kernfs_find_and_get(kn, attr); 186 kernfs_put(kn); 187 kn = tmp; 188 } 189 190 if (kn) { 191 kernfs_notify(kn); 192 kernfs_put(kn); 193 } 194 } 195 EXPORT_SYMBOL_GPL(sysfs_notify); 196 197 static const struct kernfs_ops sysfs_file_kfops_empty = { 198 }; 199 200 static const struct kernfs_ops sysfs_file_kfops_ro = { 201 .seq_show = sysfs_kf_seq_show, 202 }; 203 204 static const struct kernfs_ops sysfs_file_kfops_wo = { 205 .write = sysfs_kf_write, 206 }; 207 208 static const struct kernfs_ops sysfs_file_kfops_rw = { 209 .seq_show = sysfs_kf_seq_show, 210 .write = sysfs_kf_write, 211 }; 212 213 static const struct kernfs_ops sysfs_prealloc_kfops_ro = { 214 .read = sysfs_kf_read, 215 .prealloc = true, 216 }; 217 218 static const struct kernfs_ops sysfs_prealloc_kfops_wo = { 219 .write = sysfs_kf_write, 220 .prealloc = true, 221 }; 222 223 static const struct kernfs_ops sysfs_prealloc_kfops_rw = { 224 .read = sysfs_kf_read, 225 .write = sysfs_kf_write, 226 .prealloc = true, 227 }; 228 229 static const struct kernfs_ops sysfs_bin_kfops_ro = { 230 .read = sysfs_kf_bin_read, 231 }; 232 233 static const struct kernfs_ops sysfs_bin_kfops_wo = { 234 .write = sysfs_kf_bin_write, 235 }; 236 237 static const struct kernfs_ops sysfs_bin_kfops_rw = { 238 .read = sysfs_kf_bin_read, 239 .write = sysfs_kf_bin_write, 240 }; 241 242 static const struct kernfs_ops sysfs_bin_kfops_mmap = { 243 .read = sysfs_kf_bin_read, 244 .write = sysfs_kf_bin_write, 245 .mmap = sysfs_kf_bin_mmap, 246 }; 247 248 int sysfs_add_file_mode_ns(struct kernfs_node *parent, 249 const struct attribute *attr, bool is_bin, 250 umode_t mode, const void *ns) 251 { 252 struct lock_class_key *key = NULL; 253 const struct kernfs_ops *ops; 254 struct kernfs_node *kn; 255 loff_t size; 256 257 if (!is_bin) { 258 struct kobject *kobj = parent->priv; 259 const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops; 260 261 /* every kobject with an attribute needs a ktype assigned */ 262 if (WARN(!sysfs_ops, KERN_ERR 263 "missing sysfs attribute operations for kobject: %s\n", 264 kobject_name(kobj))) 265 return -EINVAL; 266 267 if (sysfs_ops->show && sysfs_ops->store) { 268 if (mode & SYSFS_PREALLOC) 269 ops = &sysfs_prealloc_kfops_rw; 270 else 271 ops = &sysfs_file_kfops_rw; 272 } else if (sysfs_ops->show) { 273 if (mode & SYSFS_PREALLOC) 274 ops = &sysfs_prealloc_kfops_ro; 275 else 276 ops = &sysfs_file_kfops_ro; 277 } else if (sysfs_ops->store) { 278 if (mode & SYSFS_PREALLOC) 279 ops = &sysfs_prealloc_kfops_wo; 280 else 281 ops = &sysfs_file_kfops_wo; 282 } else 283 ops = &sysfs_file_kfops_empty; 284 285 size = PAGE_SIZE; 286 } else { 287 struct bin_attribute *battr = (void *)attr; 288 289 if (battr->mmap) 290 ops = &sysfs_bin_kfops_mmap; 291 else if (battr->read && battr->write) 292 ops = &sysfs_bin_kfops_rw; 293 else if (battr->read) 294 ops = &sysfs_bin_kfops_ro; 295 else if (battr->write) 296 ops = &sysfs_bin_kfops_wo; 297 else 298 ops = &sysfs_file_kfops_empty; 299 300 size = battr->size; 301 } 302 303 #ifdef CONFIG_DEBUG_LOCK_ALLOC 304 if (!attr->ignore_lockdep) 305 key = attr->key ?: (struct lock_class_key *)&attr->skey; 306 #endif 307 kn = __kernfs_create_file(parent, attr->name, mode & 0777, size, ops, 308 (void *)attr, ns, key); 309 if (IS_ERR(kn)) { 310 if (PTR_ERR(kn) == -EEXIST) 311 sysfs_warn_dup(parent, attr->name); 312 return PTR_ERR(kn); 313 } 314 return 0; 315 } 316 317 int sysfs_add_file(struct kernfs_node *parent, const struct attribute *attr, 318 bool is_bin) 319 { 320 return sysfs_add_file_mode_ns(parent, attr, is_bin, attr->mode, NULL); 321 } 322 323 /** 324 * sysfs_create_file_ns - create an attribute file for an object with custom ns 325 * @kobj: object we're creating for 326 * @attr: attribute descriptor 327 * @ns: namespace the new file should belong to 328 */ 329 int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, 330 const void *ns) 331 { 332 BUG_ON(!kobj || !kobj->sd || !attr); 333 334 return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, ns); 335 336 } 337 EXPORT_SYMBOL_GPL(sysfs_create_file_ns); 338 339 int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) 340 { 341 int err = 0; 342 int i; 343 344 for (i = 0; ptr[i] && !err; i++) 345 err = sysfs_create_file(kobj, ptr[i]); 346 if (err) 347 while (--i >= 0) 348 sysfs_remove_file(kobj, ptr[i]); 349 return err; 350 } 351 EXPORT_SYMBOL_GPL(sysfs_create_files); 352 353 /** 354 * sysfs_add_file_to_group - add an attribute file to a pre-existing group. 355 * @kobj: object we're acting for. 356 * @attr: attribute descriptor. 357 * @group: group name. 358 */ 359 int sysfs_add_file_to_group(struct kobject *kobj, 360 const struct attribute *attr, const char *group) 361 { 362 struct kernfs_node *parent; 363 int error; 364 365 if (group) { 366 parent = kernfs_find_and_get(kobj->sd, group); 367 } else { 368 parent = kobj->sd; 369 kernfs_get(parent); 370 } 371 372 if (!parent) 373 return -ENOENT; 374 375 error = sysfs_add_file(parent, attr, false); 376 kernfs_put(parent); 377 378 return error; 379 } 380 EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); 381 382 /** 383 * sysfs_chmod_file - update the modified mode value on an object attribute. 384 * @kobj: object we're acting for. 385 * @attr: attribute descriptor. 386 * @mode: file permissions. 387 * 388 */ 389 int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, 390 umode_t mode) 391 { 392 struct kernfs_node *kn; 393 struct iattr newattrs; 394 int rc; 395 396 kn = kernfs_find_and_get(kobj->sd, attr->name); 397 if (!kn) 398 return -ENOENT; 399 400 newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO); 401 newattrs.ia_valid = ATTR_MODE; 402 403 rc = kernfs_setattr(kn, &newattrs); 404 405 kernfs_put(kn); 406 return rc; 407 } 408 EXPORT_SYMBOL_GPL(sysfs_chmod_file); 409 410 /** 411 * sysfs_remove_file_ns - remove an object attribute with a custom ns tag 412 * @kobj: object we're acting for 413 * @attr: attribute descriptor 414 * @ns: namespace tag of the file to remove 415 * 416 * Hash the attribute name and namespace tag and kill the victim. 417 */ 418 void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, 419 const void *ns) 420 { 421 struct kernfs_node *parent = kobj->sd; 422 423 kernfs_remove_by_name_ns(parent, attr->name, ns); 424 } 425 EXPORT_SYMBOL_GPL(sysfs_remove_file_ns); 426 427 /** 428 * sysfs_remove_file_self - remove an object attribute from its own method 429 * @kobj: object we're acting for 430 * @attr: attribute descriptor 431 * 432 * See kernfs_remove_self() for details. 433 */ 434 bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr) 435 { 436 struct kernfs_node *parent = kobj->sd; 437 struct kernfs_node *kn; 438 bool ret; 439 440 kn = kernfs_find_and_get(parent, attr->name); 441 if (WARN_ON_ONCE(!kn)) 442 return false; 443 444 ret = kernfs_remove_self(kn); 445 446 kernfs_put(kn); 447 return ret; 448 } 449 450 void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr) 451 { 452 int i; 453 for (i = 0; ptr[i]; i++) 454 sysfs_remove_file(kobj, ptr[i]); 455 } 456 EXPORT_SYMBOL_GPL(sysfs_remove_files); 457 458 /** 459 * sysfs_remove_file_from_group - remove an attribute file from a group. 460 * @kobj: object we're acting for. 461 * @attr: attribute descriptor. 462 * @group: group name. 463 */ 464 void sysfs_remove_file_from_group(struct kobject *kobj, 465 const struct attribute *attr, const char *group) 466 { 467 struct kernfs_node *parent; 468 469 if (group) { 470 parent = kernfs_find_and_get(kobj->sd, group); 471 } else { 472 parent = kobj->sd; 473 kernfs_get(parent); 474 } 475 476 if (parent) { 477 kernfs_remove_by_name(parent, attr->name); 478 kernfs_put(parent); 479 } 480 } 481 EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); 482 483 /** 484 * sysfs_create_bin_file - create binary file for object. 485 * @kobj: object. 486 * @attr: attribute descriptor. 487 */ 488 int sysfs_create_bin_file(struct kobject *kobj, 489 const struct bin_attribute *attr) 490 { 491 BUG_ON(!kobj || !kobj->sd || !attr); 492 493 return sysfs_add_file(kobj->sd, &attr->attr, true); 494 } 495 EXPORT_SYMBOL_GPL(sysfs_create_bin_file); 496 497 /** 498 * sysfs_remove_bin_file - remove binary file for object. 499 * @kobj: object. 500 * @attr: attribute descriptor. 501 */ 502 void sysfs_remove_bin_file(struct kobject *kobj, 503 const struct bin_attribute *attr) 504 { 505 kernfs_remove_by_name(kobj->sd, attr->attr.name); 506 } 507 EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); 508