diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-02 13:28:43 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-02 13:28:43 -0500 |
| commit | 7e05b807b93cc553bc2aa5ae8fac620cece34720 (patch) | |
| tree | 6240b09f201c210d7e3f5cd46086a64852530de2 | |
| parent | 4cb8c3593bbb884c5c282b1d8502a0930235fe88 (diff) | |
| parent | 9f2f7d4c8dfcf4617af5de6ea381b91deac3db48 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull VFS fixes from Al Viro:
"A bunch of assorted fixes, most of them followups to overlayfs merge"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
ovl: initialize ->is_cursor
Return short read or 0 at end of a raw device, not EIO
isofs: don't bother with ->d_op for normal case
isofs_cmp(): we'll never see a dentry for . or ..
overlayfs: fix lockdep misannotation
ovl: fix check for cursor
overlayfs: barriers for opening upper-layer directory
rcu: Provide counterpart to rcu_dereference() for non-RCU situations
staging: android: logger: Fix log corruption regression
| -rw-r--r-- | drivers/char/raw.c | 2 | ||||
| -rw-r--r-- | drivers/staging/android/logger.c | 13 | ||||
| -rw-r--r-- | fs/block_dev.c | 3 | ||||
| -rw-r--r-- | fs/isofs/inode.c | 24 | ||||
| -rw-r--r-- | fs/isofs/namei.c | 22 | ||||
| -rw-r--r-- | fs/namei.c | 2 | ||||
| -rw-r--r-- | fs/overlayfs/readdir.c | 17 | ||||
| -rw-r--r-- | include/linux/fs.h | 10 | ||||
| -rw-r--r-- | include/linux/rcupdate.h | 15 |
9 files changed, 50 insertions, 58 deletions
diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 0102dc788608..a24891b97547 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c | |||
| @@ -285,7 +285,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd, | |||
| 285 | 285 | ||
| 286 | static const struct file_operations raw_fops = { | 286 | static const struct file_operations raw_fops = { |
| 287 | .read = new_sync_read, | 287 | .read = new_sync_read, |
| 288 | .read_iter = generic_file_read_iter, | 288 | .read_iter = blkdev_read_iter, |
| 289 | .write = new_sync_write, | 289 | .write = new_sync_write, |
| 290 | .write_iter = blkdev_write_iter, | 290 | .write_iter = blkdev_write_iter, |
| 291 | .fsync = blkdev_fsync, | 291 | .fsync = blkdev_fsync, |
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c index 28b93d39a94e..a673ffa34aa3 100644 --- a/drivers/staging/android/logger.c +++ b/drivers/staging/android/logger.c | |||
| @@ -420,7 +420,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
| 420 | struct logger_log *log = file_get_log(iocb->ki_filp); | 420 | struct logger_log *log = file_get_log(iocb->ki_filp); |
| 421 | struct logger_entry header; | 421 | struct logger_entry header; |
| 422 | struct timespec now; | 422 | struct timespec now; |
| 423 | size_t len, count; | 423 | size_t len, count, w_off; |
| 424 | 424 | ||
| 425 | count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD); | 425 | count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD); |
| 426 | 426 | ||
| @@ -452,11 +452,14 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
| 452 | memcpy(log->buffer + log->w_off, &header, len); | 452 | memcpy(log->buffer + log->w_off, &header, len); |
| 453 | memcpy(log->buffer, (char *)&header + len, sizeof(header) - len); | 453 | memcpy(log->buffer, (char *)&header + len, sizeof(header) - len); |
| 454 | 454 | ||
| 455 | len = min(count, log->size - log->w_off); | 455 | /* Work with a copy until we are ready to commit the whole entry */ |
| 456 | w_off = logger_offset(log, log->w_off + sizeof(struct logger_entry)); | ||
| 456 | 457 | ||
| 457 | if (copy_from_iter(log->buffer + log->w_off, len, from) != len) { | 458 | len = min(count, log->size - w_off); |
| 459 | |||
| 460 | if (copy_from_iter(log->buffer + w_off, len, from) != len) { | ||
| 458 | /* | 461 | /* |
| 459 | * Note that by not updating w_off, this abandons the | 462 | * Note that by not updating log->w_off, this abandons the |
| 460 | * portion of the new entry that *was* successfully | 463 | * portion of the new entry that *was* successfully |
| 461 | * copied, just above. This is intentional to avoid | 464 | * copied, just above. This is intentional to avoid |
| 462 | * message corruption from missing fragments. | 465 | * message corruption from missing fragments. |
| @@ -470,7 +473,7 @@ static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
| 470 | return -EFAULT; | 473 | return -EFAULT; |
| 471 | } | 474 | } |
| 472 | 475 | ||
| 473 | log->w_off = logger_offset(log, log->w_off + count); | 476 | log->w_off = logger_offset(log, w_off + count); |
| 474 | mutex_unlock(&log->mutex); | 477 | mutex_unlock(&log->mutex); |
| 475 | 478 | ||
| 476 | /* wake up any blocked readers */ | 479 | /* wake up any blocked readers */ |
diff --git a/fs/block_dev.c b/fs/block_dev.c index cc9d4114cda0..1d9c9f3754f8 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -1585,7 +1585,7 @@ ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
| 1585 | } | 1585 | } |
| 1586 | EXPORT_SYMBOL_GPL(blkdev_write_iter); | 1586 | EXPORT_SYMBOL_GPL(blkdev_write_iter); |
| 1587 | 1587 | ||
| 1588 | static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) | 1588 | ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) |
| 1589 | { | 1589 | { |
| 1590 | struct file *file = iocb->ki_filp; | 1590 | struct file *file = iocb->ki_filp; |
| 1591 | struct inode *bd_inode = file->f_mapping->host; | 1591 | struct inode *bd_inode = file->f_mapping->host; |
| @@ -1599,6 +1599,7 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) | |||
| 1599 | iov_iter_truncate(to, size); | 1599 | iov_iter_truncate(to, size); |
| 1600 | return generic_file_read_iter(iocb, to); | 1600 | return generic_file_read_iter(iocb, to); |
| 1601 | } | 1601 | } |
| 1602 | EXPORT_SYMBOL_GPL(blkdev_read_iter); | ||
| 1602 | 1603 | ||
| 1603 | /* | 1604 | /* |
| 1604 | * Try to release a page associated with block device when the system | 1605 | * Try to release a page associated with block device when the system |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 881b3bd0143f..fe839b915116 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -29,13 +29,9 @@ | |||
| 29 | #define BEQUIET | 29 | #define BEQUIET |
| 30 | 30 | ||
| 31 | static int isofs_hashi(const struct dentry *parent, struct qstr *qstr); | 31 | static int isofs_hashi(const struct dentry *parent, struct qstr *qstr); |
| 32 | static int isofs_hash(const struct dentry *parent, struct qstr *qstr); | ||
| 33 | static int isofs_dentry_cmpi(const struct dentry *parent, | 32 | static int isofs_dentry_cmpi(const struct dentry *parent, |
| 34 | const struct dentry *dentry, | 33 | const struct dentry *dentry, |
| 35 | unsigned int len, const char *str, const struct qstr *name); | 34 | unsigned int len, const char *str, const struct qstr *name); |
| 36 | static int isofs_dentry_cmp(const struct dentry *parent, | ||
| 37 | const struct dentry *dentry, | ||
| 38 | unsigned int len, const char *str, const struct qstr *name); | ||
| 39 | 35 | ||
| 40 | #ifdef CONFIG_JOLIET | 36 | #ifdef CONFIG_JOLIET |
| 41 | static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr); | 37 | static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr); |
| @@ -135,10 +131,6 @@ static const struct super_operations isofs_sops = { | |||
| 135 | 131 | ||
| 136 | static const struct dentry_operations isofs_dentry_ops[] = { | 132 | static const struct dentry_operations isofs_dentry_ops[] = { |
| 137 | { | 133 | { |
| 138 | .d_hash = isofs_hash, | ||
| 139 | .d_compare = isofs_dentry_cmp, | ||
| 140 | }, | ||
| 141 | { | ||
| 142 | .d_hash = isofs_hashi, | 134 | .d_hash = isofs_hashi, |
| 143 | .d_compare = isofs_dentry_cmpi, | 135 | .d_compare = isofs_dentry_cmpi, |
| 144 | }, | 136 | }, |
| @@ -258,25 +250,12 @@ static int isofs_dentry_cmp_common( | |||
| 258 | } | 250 | } |
| 259 | 251 | ||
| 260 | static int | 252 | static int |
| 261 | isofs_hash(const struct dentry *dentry, struct qstr *qstr) | ||
| 262 | { | ||
| 263 | return isofs_hash_common(qstr, 0); | ||
| 264 | } | ||
| 265 | |||
| 266 | static int | ||
| 267 | isofs_hashi(const struct dentry *dentry, struct qstr *qstr) | 253 | isofs_hashi(const struct dentry *dentry, struct qstr *qstr) |
| 268 | { | 254 | { |
| 269 | return isofs_hashi_common(qstr, 0); | 255 | return isofs_hashi_common(qstr, 0); |
| 270 | } | 256 | } |
| 271 | 257 | ||
| 272 | static int | 258 | static int |
| 273 | isofs_dentry_cmp(const struct dentry *parent, const struct dentry *dentry, | ||
| 274 | unsigned int len, const char *str, const struct qstr *name) | ||
| 275 | { | ||
| 276 | return isofs_dentry_cmp_common(len, str, name, 0, 0); | ||
| 277 | } | ||
| 278 | |||
| 279 | static int | ||
| 280 | isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry, | 259 | isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry, |
| 281 | unsigned int len, const char *str, const struct qstr *name) | 260 | unsigned int len, const char *str, const struct qstr *name) |
| 282 | { | 261 | { |
| @@ -930,7 +909,8 @@ root_found: | |||
| 930 | if (opt.check == 'r') | 909 | if (opt.check == 'r') |
| 931 | table++; | 910 | table++; |
| 932 | 911 | ||
| 933 | s->s_d_op = &isofs_dentry_ops[table]; | 912 | if (table) |
| 913 | s->s_d_op = &isofs_dentry_ops[table - 1]; | ||
| 934 | 914 | ||
| 935 | /* get the root dentry */ | 915 | /* get the root dentry */ |
| 936 | s->s_root = d_make_root(inode); | 916 | s->s_root = d_make_root(inode); |
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 95295640d9c8..7b543e6b6526 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c | |||
| @@ -18,25 +18,10 @@ static int | |||
| 18 | isofs_cmp(struct dentry *dentry, const char *compare, int dlen) | 18 | isofs_cmp(struct dentry *dentry, const char *compare, int dlen) |
| 19 | { | 19 | { |
| 20 | struct qstr qstr; | 20 | struct qstr qstr; |
| 21 | |||
| 22 | if (!compare) | ||
| 23 | return 1; | ||
| 24 | |||
| 25 | /* check special "." and ".." files */ | ||
| 26 | if (dlen == 1) { | ||
| 27 | /* "." */ | ||
| 28 | if (compare[0] == 0) { | ||
| 29 | if (!dentry->d_name.len) | ||
| 30 | return 0; | ||
| 31 | compare = "."; | ||
| 32 | } else if (compare[0] == 1) { | ||
| 33 | compare = ".."; | ||
| 34 | dlen = 2; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | qstr.name = compare; | 21 | qstr.name = compare; |
| 39 | qstr.len = dlen; | 22 | qstr.len = dlen; |
| 23 | if (likely(!dentry->d_op)) | ||
| 24 | return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen); | ||
| 40 | return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr); | 25 | return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr); |
| 41 | } | 26 | } |
| 42 | 27 | ||
| @@ -146,7 +131,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, | |||
| 146 | (!(de->flags[-sbi->s_high_sierra] & 1))) && | 131 | (!(de->flags[-sbi->s_high_sierra] & 1))) && |
| 147 | (sbi->s_showassoc || | 132 | (sbi->s_showassoc || |
| 148 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { | 133 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { |
| 149 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); | 134 | if (dpnt && (dlen > 1 || dpnt[0] > 1)) |
| 135 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); | ||
| 150 | } | 136 | } |
| 151 | if (match) { | 137 | if (match) { |
| 152 | isofs_normalize_block_and_offset(de, | 138 | isofs_normalize_block_and_offset(de, |
diff --git a/fs/namei.c b/fs/namei.c index 78512898d3ba..db5fe86319e6 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -2497,7 +2497,7 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) | |||
| 2497 | } | 2497 | } |
| 2498 | 2498 | ||
| 2499 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); | 2499 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); |
| 2500 | mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); | 2500 | mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT2); |
| 2501 | return NULL; | 2501 | return NULL; |
| 2502 | } | 2502 | } |
| 2503 | EXPORT_SYMBOL(lock_rename); | 2503 | EXPORT_SYMBOL(lock_rename); |
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 910553f37aca..4e9d7c1fea52 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
| @@ -21,9 +21,10 @@ struct ovl_cache_entry { | |||
| 21 | unsigned int len; | 21 | unsigned int len; |
| 22 | unsigned int type; | 22 | unsigned int type; |
| 23 | u64 ino; | 23 | u64 ino; |
| 24 | bool is_whiteout; | ||
| 25 | struct list_head l_node; | 24 | struct list_head l_node; |
| 26 | struct rb_node node; | 25 | struct rb_node node; |
| 26 | bool is_whiteout; | ||
| 27 | bool is_cursor; | ||
| 27 | char name[]; | 28 | char name[]; |
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| @@ -92,6 +93,7 @@ static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len, | |||
| 92 | p->type = d_type; | 93 | p->type = d_type; |
| 93 | p->ino = ino; | 94 | p->ino = ino; |
| 94 | p->is_whiteout = false; | 95 | p->is_whiteout = false; |
| 96 | p->is_cursor = false; | ||
| 95 | } | 97 | } |
| 96 | 98 | ||
| 97 | return p; | 99 | return p; |
| @@ -251,7 +253,7 @@ static int ovl_dir_mark_whiteouts(struct dentry *dir, | |||
| 251 | 253 | ||
| 252 | mutex_lock(&dir->d_inode->i_mutex); | 254 | mutex_lock(&dir->d_inode->i_mutex); |
| 253 | list_for_each_entry(p, rdd->list, l_node) { | 255 | list_for_each_entry(p, rdd->list, l_node) { |
| 254 | if (!p->name) | 256 | if (p->is_cursor) |
| 255 | continue; | 257 | continue; |
| 256 | 258 | ||
| 257 | if (p->type != DT_CHR) | 259 | if (p->type != DT_CHR) |
| @@ -307,7 +309,6 @@ static inline int ovl_dir_read_merged(struct path *upperpath, | |||
| 307 | } | 309 | } |
| 308 | out: | 310 | out: |
| 309 | return err; | 311 | return err; |
| 310 | |||
| 311 | } | 312 | } |
| 312 | 313 | ||
| 313 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | 314 | static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) |
| @@ -316,7 +317,7 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | |||
| 316 | loff_t off = 0; | 317 | loff_t off = 0; |
| 317 | 318 | ||
| 318 | list_for_each_entry(p, &od->cache->entries, l_node) { | 319 | list_for_each_entry(p, &od->cache->entries, l_node) { |
| 319 | if (!p->name) | 320 | if (p->is_cursor) |
| 320 | continue; | 321 | continue; |
| 321 | if (off >= pos) | 322 | if (off >= pos) |
| 322 | break; | 323 | break; |
| @@ -389,7 +390,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx) | |||
| 389 | 390 | ||
| 390 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); | 391 | p = list_entry(od->cursor.l_node.next, struct ovl_cache_entry, l_node); |
| 391 | /* Skip cursors */ | 392 | /* Skip cursors */ |
| 392 | if (p->name) { | 393 | if (!p->is_cursor) { |
| 393 | if (!p->is_whiteout) { | 394 | if (!p->is_whiteout) { |
| 394 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) | 395 | if (!dir_emit(ctx, p->name, p->len, p->ino, p->type)) |
| 395 | break; | 396 | break; |
| @@ -454,12 +455,13 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, | |||
| 454 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { | 455 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { |
| 455 | struct inode *inode = file_inode(file); | 456 | struct inode *inode = file_inode(file); |
| 456 | 457 | ||
| 457 | realfile = od->upperfile; | 458 | realfile =lockless_dereference(od->upperfile); |
| 458 | if (!realfile) { | 459 | if (!realfile) { |
| 459 | struct path upperpath; | 460 | struct path upperpath; |
| 460 | 461 | ||
| 461 | ovl_path_upper(dentry, &upperpath); | 462 | ovl_path_upper(dentry, &upperpath); |
| 462 | realfile = ovl_path_open(&upperpath, O_RDONLY); | 463 | realfile = ovl_path_open(&upperpath, O_RDONLY); |
| 464 | smp_mb__before_spinlock(); | ||
| 463 | mutex_lock(&inode->i_mutex); | 465 | mutex_lock(&inode->i_mutex); |
| 464 | if (!od->upperfile) { | 466 | if (!od->upperfile) { |
| 465 | if (IS_ERR(realfile)) { | 467 | if (IS_ERR(realfile)) { |
| @@ -518,6 +520,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file) | |||
| 518 | od->realfile = realfile; | 520 | od->realfile = realfile; |
| 519 | od->is_real = (type != OVL_PATH_MERGE); | 521 | od->is_real = (type != OVL_PATH_MERGE); |
| 520 | od->is_upper = (type != OVL_PATH_LOWER); | 522 | od->is_upper = (type != OVL_PATH_LOWER); |
| 523 | od->cursor.is_cursor = true; | ||
| 521 | file->private_data = od; | 524 | file->private_data = od; |
| 522 | 525 | ||
| 523 | return 0; | 526 | return 0; |
| @@ -569,7 +572,7 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list) | |||
| 569 | { | 572 | { |
| 570 | struct ovl_cache_entry *p; | 573 | struct ovl_cache_entry *p; |
| 571 | 574 | ||
| 572 | mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_PARENT); | 575 | mutex_lock_nested(&upper->d_inode->i_mutex, I_MUTEX_CHILD); |
| 573 | list_for_each_entry(p, list, l_node) { | 576 | list_for_each_entry(p, list, l_node) { |
| 574 | struct dentry *dentry; | 577 | struct dentry *dentry; |
| 575 | 578 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 4e41a4a331bb..9ab779e8a63c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -639,11 +639,13 @@ static inline int inode_unhashed(struct inode *inode) | |||
| 639 | * 2: child/target | 639 | * 2: child/target |
| 640 | * 3: xattr | 640 | * 3: xattr |
| 641 | * 4: second non-directory | 641 | * 4: second non-directory |
| 642 | * The last is for certain operations (such as rename) which lock two | 642 | * 5: second parent (when locking independent directories in rename) |
| 643 | * | ||
| 644 | * I_MUTEX_NONDIR2 is for certain operations (such as rename) which lock two | ||
| 643 | * non-directories at once. | 645 | * non-directories at once. |
| 644 | * | 646 | * |
| 645 | * The locking order between these classes is | 647 | * The locking order between these classes is |
| 646 | * parent -> child -> normal -> xattr -> second non-directory | 648 | * parent[2] -> child -> grandchild -> normal -> xattr -> second non-directory |
| 647 | */ | 649 | */ |
| 648 | enum inode_i_mutex_lock_class | 650 | enum inode_i_mutex_lock_class |
| 649 | { | 651 | { |
| @@ -651,7 +653,8 @@ enum inode_i_mutex_lock_class | |||
| 651 | I_MUTEX_PARENT, | 653 | I_MUTEX_PARENT, |
| 652 | I_MUTEX_CHILD, | 654 | I_MUTEX_CHILD, |
| 653 | I_MUTEX_XATTR, | 655 | I_MUTEX_XATTR, |
| 654 | I_MUTEX_NONDIR2 | 656 | I_MUTEX_NONDIR2, |
| 657 | I_MUTEX_PARENT2, | ||
| 655 | }; | 658 | }; |
| 656 | 659 | ||
| 657 | void lock_two_nondirectories(struct inode *, struct inode*); | 660 | void lock_two_nondirectories(struct inode *, struct inode*); |
| @@ -2466,6 +2469,7 @@ extern ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, lo | |||
| 2466 | extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); | 2469 | extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); |
| 2467 | 2470 | ||
| 2468 | /* fs/block_dev.c */ | 2471 | /* fs/block_dev.c */ |
| 2472 | extern ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to); | ||
| 2469 | extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from); | 2473 | extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from); |
| 2470 | extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, | 2474 | extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, |
| 2471 | int datasync); | 2475 | int datasync); |
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index a4a819ffb2d1..53ff1a752d7e 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
| @@ -617,6 +617,21 @@ static inline void rcu_preempt_sleep_check(void) | |||
| 617 | #define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) | 617 | #define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) |
| 618 | 618 | ||
| 619 | /** | 619 | /** |
| 620 | * lockless_dereference() - safely load a pointer for later dereference | ||
| 621 | * @p: The pointer to load | ||
| 622 | * | ||
| 623 | * Similar to rcu_dereference(), but for situations where the pointed-to | ||
| 624 | * object's lifetime is managed by something other than RCU. That | ||
| 625 | * "something other" might be reference counting or simple immortality. | ||
| 626 | */ | ||
| 627 | #define lockless_dereference(p) \ | ||
| 628 | ({ \ | ||
| 629 | typeof(p) _________p1 = ACCESS_ONCE(p); \ | ||
| 630 | smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ | ||
| 631 | (_________p1); \ | ||
| 632 | }) | ||
| 633 | |||
| 634 | /** | ||
| 620 | * rcu_assign_pointer() - assign to RCU-protected pointer | 635 | * rcu_assign_pointer() - assign to RCU-protected pointer |
| 621 | * @p: pointer to assign to | 636 | * @p: pointer to assign to |
| 622 | * @v: value to assign (publish) | 637 | * @v: value to assign (publish) |
