When implementing connector fsid cache, we only initialized the cache when the first mark added to object was added by FAN_REPORT_FID group. We forgot to update conn->fsid when the second mark is added by FAN_REPORT_FID group to an already attached connector without fsid cache.
Unified · Split
| @@ -355,6 +355,10 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) · 354 unmodified lines | |||
| 355 | /* Mark is just getting destroyed or created? */ | 355 | /* Mark is just getting destroyed or created? */ |
| 356 | if (!conn) | 356 | if (!conn) |
| 357 | continue; | 357 | continue; |
| 358 | if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) | ||
| 359 | continue; | ||
| 360 | /* Pairs with smp_wmb() in fsnotify_add_mark_list() */ | ||
| 361 | smp_rmb(); | ||
| 358 | fsid = conn->fsid; | 362 | fsid = conn->fsid; |
| 359 | if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1])) | 363 | if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1])) |
| 360 | continue; | 364 | continue; |
| @@ -482,10 +482,13 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, · 481 unmodified lines | |||
| 482 | conn->type = type; | 482 | conn->type = type; |
| 483 | conn->obj = connp; | 483 | conn->obj = connp; |
| 484 | /* Cache fsid of filesystem containing the object */ | 484 | /* Cache fsid of filesystem containing the object */ |
| 485 | if (fsid) | 485 | if (fsid) { |
| 486 | conn->fsid = *fsid; | 486 | conn->fsid = *fsid; |
| 487 | else | 487 | conn->flags = FSNOTIFY_CONN_FLAG_HAS_FSID; |
| 488 | } else { | ||
| 488 | conn->fsid.val[0] = conn->fsid.val[1] = 0; | 489 | conn->fsid.val[0] = conn->fsid.val[1] = 0; |
| 490 | conn->flags = 0; | ||
| 491 | } | ||
| 489 | if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) | 492 | if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) |
| 490 | inode = igrab(fsnotify_conn_inode(conn)); | 493 | inode = igrab(fsnotify_conn_inode(conn)); |
| 491 | /* | 494 | /* |
| @@ -560,7 +563,12 @@ restart: · 68 unmodified lines | |||
| 560 | if (err) | 563 | if (err) |
| 561 | return err; | 564 | return err; |
| 562 | goto restart; | 565 | goto restart; |
| 563 | } else if (fsid && (conn->fsid.val[0] || conn->fsid.val[1]) && | 566 | } else if (fsid && !(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID)) { |
| 567 | conn->fsid = *fsid; | ||
| 568 | /* Pairs with smp_rmb() in fanotify_get_fsid() */ | ||
| 569 | smp_wmb(); | ||
| 570 | conn->flags |= FSNOTIFY_CONN_FLAG_HAS_FSID; | ||
| 571 | } else if (fsid && (conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID) && | ||
| 564 | (fsid->val[0] != conn->fsid.val[0] || | 572 | (fsid->val[0] != conn->fsid.val[0] || |
| 565 | fsid->val[1] != conn->fsid.val[1])) { | 573 | fsid->val[1] != conn->fsid.val[1])) { |
| 566 | /* | 574 | /* |
| @@ -292,7 +292,9 @@ typedef struct fsnotify_mark_connector __rcu *fsnotify_connp_t; · 291 unmodified lines | |||
| 292 | */ | 292 | */ |
| 293 | struct fsnotify_mark_connector { | 293 | struct fsnotify_mark_connector { |
| 294 | spinlock_t lock; | 294 | spinlock_t lock; |
| 295 | unsigned int type; /* Type of object [lock] */ | 295 | unsigned short type; /* Type of object [lock] */ |
| 296 | #define FSNOTIFY_CONN_FLAG_HAS_FSID 0x01 | ||
| 297 | unsigned short flags; /* flags [lock] */ | ||
| 296 | __kernel_fsid_t fsid; /* fsid of filesystem containing object */ | 298 | __kernel_fsid_t fsid; /* fsid of filesystem containing object */ |
| 297 | union { | 299 | union { |
| 298 | /* Object pointer [lock] */ | 300 | /* Object pointer [lock] */ |